NGUI之实现连连看小游戏

一,部分游戏规则如下:

二,代码如下:

1. 游戏逻辑核心代码

  1 using System.Collections.Generic;
  2 using UnityEngine;
  3 
  4 namespace Modules.UI
  5 {
  6     // 逻辑与UI分离,这是逻辑类
  7     public class LianLianKanController
  8     {
  9         int m_rowCount;
 10         List<LianLianKanCell> m_cells = new List<LianLianKanCell>();
 11         IHandler m_handler;
 12 
 13 
 14         public int RowCount
 15         {
 16             get { return m_rowCount; }
 17         }
 18 
 19         public List<LianLianKanCell> Cells
 20         {
 21             get { return m_cells; }
 22         }
 23 
 24         public bool GameFinished
 25         {
 26             get
 27             {
 28                 for (int i = 0; i < m_cells.Count; i++)
 29                 {
 30                     if (m_cells[i].Showing)
 31                     {
 32                         return false;
 33                     }
 34                 }
 35                 return true;
 36             }
 37         }
 38 
 39 
 40         public interface IHandler
 41         {
 42             void OnResetPos();
 43         }
 44 
 45 
 46         public LianLianKanController(int rowCount, IHandler handler)
 47         {
 48             m_rowCount = rowCount + 2;      // 为了边缘上的格子也能连线
 49             m_handler = handler;
 50 
 51             // 生成cell
 52             for (int x = 0; x < m_rowCount; x++)
 53             {
 54                 for (int y = 0; y < m_rowCount; y++)
 55                 {
 56                     int pos = m_rowCount * y + x;
 57                     LianLianKanCell cell = new LianLianKanCell(this);
 58                     cell.Position = pos;
 59                     cell.Showing = x != 0 && x != m_rowCount - 1 && y != 0 && y != m_rowCount - 1;
 60                     cell.Icon = y - 1;
 61                     m_cells.Add(cell);
 62                 }
 63             }
 64         }
 65 
 66         // 打乱
 67         public void ResetPos()
 68         {
 69             List<int> positions = new List<int>();
 70             for (int i = 1; i <= m_rowCount - 2; i++)
 71             {
 72                 for (int j = 1; j <= m_rowCount - 2; j++)
 73                 {
 74                     int pos = m_rowCount * j + i;
 75                     positions.Add(pos);
 76                 }
 77             }
 78 
 79             for (int i = 0; i < m_cells.Count; i++)
 80             {
 81                 var cell = m_cells[i];
 82                 if (cell.Showing)
 83                 {
 84                     int ranIndex = Random.Range(0, positions.Count);
 85                     int position = positions[ranIndex];
 86                     positions.RemoveAt(ranIndex);
 87                     cell.Position = position;
 88                 }
 89             }
 90 
 91             bool canDraw = CanDrawAnyLine();
 92             if (canDraw)
 93                 m_handler.OnResetPos();
 94             else
 95                 ResetPos();
 96         }
 97 
 98         bool CanDrawAnyLine(LianLianKanCell start)
 99         {
100             for (int i = 0; i < m_cells.Count; i++)
101             {
102                 var end = m_cells[i];
103                 if (start != end && end.Showing)
104                 {
105                     List<LianLianKanCell> brokenCells;
106                     bool isMatch = IsMatch(start, end, out brokenCells);
107                     if (isMatch)
108                         return true;
109                 }
110             }
111 
112             return false;
113         }
114 
115         bool CanDrawAnyLine()
116         {
117             for (int i = 0; i < m_cells.Count; i++)
118             {
119                 var start = m_cells[i];
120                 if (start.Showing)
121                 {
122                     bool canDraw = CanDrawAnyLine(start);
123                     if (canDraw)
124                         return true;
125                 }
126             }
127 
128             return false;
129         }
130 
131         // 尝试连线
132         public bool TryDrawLine(LianLianKanCell first, LianLianKanCell second, out List<LianLianKanCell> brokenCells)
133         {
134             bool isMatch = IsMatch(first, second, out brokenCells);
135             if (isMatch)
136             {
137                 first.Showing = false;
138                 second.Showing = false;
139 
140                 if (!GameFinished && !CanDrawAnyLine())
141                 {
142                     ResetPos();
143                 }
144             }
145             return isMatch;
146         }
147 
148         LianLianKanCell GetCellByPos(int x, int y)
149         {
150             for (int i = 0; i < m_cells.Count; i++)
151             {
152                 var cell = m_cells[i];
153                 if (cell.X == x && cell.Y == y)
154                     return cell;
155             }
156             return null;
157         }
158 
159         // 0个拐点
160         bool MatchBroken0(LianLianKanCell first, LianLianKanCell second)
161         {
162             // 如果不属于0折连接则返回false
163             if (first.X != second.X && first.Y != second.Y)
164             {
165                 return false;
166             }
167 
168             int min, max;
169             // 如果两点的x坐标相等,则在竖直方向上扫描
170             if (first.X == second.X)
171             {
172                 min = first.Y < second.Y ? first.Y : second.Y;
173                 min++;
174                 max = first.Y > second.Y ? first.Y : second.Y;
175 
176                 for (int i = min; i < max; i++)
177                 {
178                     var cell = GetCellByPos(first.X, i);
179                     if (cell.Showing)
180                         return false;
181                 }
182             }
183             // 如果两点的y坐标相等,则在水平方向上扫描
184             else
185             {
186                 min = first.X < second.X ? first.X : second.X;
187                 min++;
188                 max = first.X > second.X ? first.X : second.X;
189 
190                 for (int i = min; i < max; i++)
191                 {
192                     var cell = GetCellByPos(i, first.Y);
193                     if (cell.Showing)
194                         return false;
195                 }
196             }
197 
198             return true;
199         }
200 
201         // 1个拐点
202         bool MatchBroken1(LianLianKanCell first, LianLianKanCell second, out LianLianKanCell brokenCell)
203         {
204             if (first.X == second.X || first.Y == second.Y)
205             {
206                 brokenCell = null;
207                 return false;
208             }
209 
210             // 测试对角点1
211             brokenCell = GetCellByPos(first.X, second.Y);
212             if (!brokenCell.Showing)
213             {
214                 bool match = MatchBroken0(first, brokenCell) && MatchBroken0(brokenCell, second);
215                 if (match)
216                     return true;
217             }
218 
219             // 测试对角点2
220             brokenCell = GetCellByPos(second.X, first.Y);
221             if (!brokenCell.Showing)
222             {
223                 bool match = MatchBroken0(first, brokenCell) && MatchBroken0(brokenCell, second);
224                 if (match)
225                     return true;
226             }
227 
228             return false;
229         }
230 
231         // 2个拐点
232         bool MatchBroken2(LianLianKanCell first, LianLianKanCell second, ref List<LianLianKanCell> brokenCells)
233         {
234             for (int i = first.Y + 1; i < m_rowCount; i++)
235             {
236                 var cell = GetCellByPos(first.X, i);
237                 if (cell.Showing)
238                     break;
239 
240                 LianLianKanCell brokenCell;
241                 if (MatchBroken1(cell, second, out brokenCell))
242                 {
243                     brokenCells.Add(cell);
244                     brokenCells.Add(brokenCell);
245                     return true;
246                 }
247             }
248 
249             for (int i = first.Y - 1; i > -1; i--)
250             {
251                 var cell = GetCellByPos(first.X, i);
252                 if (cell.Showing)
253                     break;
254 
255                 LianLianKanCell brokenCell;
256                 if (MatchBroken1(cell, second, out brokenCell))
257                 {
258                     brokenCells.Add(cell);
259                     brokenCells.Add(brokenCell);
260                     return true;
261                 }
262             }
263 
264             for (int i = first.X + 1; i < m_rowCount; i++)
265             {
266                 var cell = GetCellByPos(i, first.Y);
267                 if (cell.Showing)
268                     break;
269 
270                 LianLianKanCell brokenCell;
271                 if (MatchBroken1(cell, second, out brokenCell))
272                 {
273                     brokenCells.Add(cell);
274                     brokenCells.Add(brokenCell);
275                     return true;
276                 }
277             }
278 
279 
280             for (int i = first.X - 1; i > -1; i--)
281             {
282                 var cell = GetCellByPos(i, first.Y);
283                 if (cell.Showing)
284                     break;
285 
286                 LianLianKanCell brokenCell;
287                 if (MatchBroken1(cell, second, out brokenCell))
288                 {
289                     brokenCells.Add(cell);
290                     brokenCells.Add(brokenCell);
291                     return true;
292                 }
293             }
294 
295             return false;
296         }
297 
298         bool IsMatch(LianLianKanCell first, LianLianKanCell second, out List<LianLianKanCell> brokenCells)
299         {
300             brokenCells = new List<LianLianKanCell>();
301             if (first == second || first.Icon != second.Icon)
302                 return false;
303 
304             // 0个拐点
305             if (MatchBroken0(first, second))
306                 return true;
307 
308             // 1个拐点
309             LianLianKanCell brokenCell;
310             if (MatchBroken1(first, second, out brokenCell))
311             {
312                 brokenCells.Add(brokenCell);
313                 return true;
314             }
315 
316             // 2个拐点
317             if (MatchBroken2(first, second, ref brokenCells))
318                 return true;
319 
320             return false;
321         }
322 
323 
324     }
325 }
LianLianKanController

2. 封装了一个格子

 1 using System;
 2 
 3 namespace Modules.UI
 4 {
 5     public class LianLianKanCell
 6     {
 7         LianLianKanController m_controller;
 8         int m_icon;             // icon的索引,从0到7
 9         int m_position;         // 位置索引,从0到63
10         bool m_showing;         // 是否显示中
11 
12         public int Icon
13         {
14             get { return m_icon; }
15             set { m_icon = value; }
16         }
17 
18         public bool Showing
19         {
20             get { return m_showing; }
21             set { m_showing = value; }
22         }
23 
24         public int Position
25         {
26             get { return m_position; }
27             set { m_position = value; }
28         }
29 
30         public int X
31         {
32             get { return m_position % m_controller.RowCount; }
33         }
34 
35         public int Y
36         {
37             get { return m_position / m_controller.RowCount; }
38         }
39 
40         public LianLianKanCell(LianLianKanController controller)
41         {
42             if (controller == null)
43                 throw new ArgumentNullException("controller");
44 
45             m_controller = controller;
46         }
47 
48         public override string ToString()
49         {
50             return string.Format("{0}_{1}_{2}", m_icon, m_position, m_showing);
51         }
52     }
53 }
LianLianKanCell

3. 游戏界面

  1 using System;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 
  5 namespace Modules.UI
  6 {
  7     public class UI_LianLianKanWnd : UI_AutoSortDepthWnd, UI_LianLianKanCell.IHandler, LianLianKanController.IHandler
  8     {
  9         public static int RowCount = 8;
 10 
 11         [SerializeField]
 12         GameObject m_btnClose;
 13         [SerializeField]
 14         UI_LianLianKanCell m_cell;
 15         [SerializeField]
 16         Transform m_parentOfCell;
 17         [SerializeField]
 18         UI_LianLianKanLine m_line;
 19 
 20         LianLianKanController m_controller;
 21         UI_LianLianKanCell[] m_uiCells;
 22         Queue<UI_LianLianKanCell> m_selectedCells = new Queue<UI_LianLianKanCell>();
 23 
 24 
 25         public static void Create()
 26         {
 27             UIManager.ShowUISync(UIFlag.ui_entertainment_war, UIFlag.ui_lianliankan, UIFlag.none, false, null, UIFlag.none);
 28         }
 29 
 30         protected override UIFlag UIFlag
 31         {
 32             get { return UIFlag.ui_lianliankan; }
 33         }
 34 
 35         protected override void Awake()
 36         {
 37             base.Awake();
 38 
 39             UIEventListener.Get(m_btnClose).onClick = OnClickClose;
 40 
 41             // 生成icon
 42             m_controller = new LianLianKanController(RowCount, this);
 43             m_uiCells = new UI_LianLianKanCell[m_controller.Cells.Count];
 44             m_cell.Show = false;
 45             float posOfCellsParent = (m_controller.RowCount / 2f - 0.5f) * m_cell.Width;
 46             m_parentOfCell.localPosition = new Vector3(-posOfCellsParent, -posOfCellsParent);
 47             for (int i = 0; i < m_uiCells.Length; i++)
 48             {
 49                 UI_LianLianKanCell cell = m_cell.Instantiate<UI_LianLianKanCell>(m_parentOfCell);
 50                 cell.Init(m_controller.Cells[i], this);
 51                 m_uiCells[i] = cell;
 52             }
 53         }
 54 
 55         void OnClickClose(GameObject go)
 56         {
 57             Close();
 58         }
 59 
 60         public override void OnShowWnd(UIWndData wndData)
 61         {
 62             base.OnShowWnd(wndData);
 63 
 64             ResetWnd();
 65         }
 66 
 67         void ResetWnd()
 68         {
 69             m_controller.ResetPos();
 70         }
 71 
 72         void OnGameFinished()
 73         {
 74             UIMessageMgr.ShowMessageBoxOnlyOK("成功完成!", base.Close, null);
 75         }
 76 
 77         void UI_LianLianKanCell.IHandler.OnClick(UI_LianLianKanCell self)
 78         {
 79             if (m_selectedCells.Contains(self))
 80                 return;
 81 
 82             self.Selected = true;
 83             m_selectedCells.Enqueue(self);
 84 
 85             if (m_selectedCells.Count < 2)
 86                 return;
 87 
 88             var cells = m_selectedCells.ToArray();
 89             List<LianLianKanCell> brokenCells;
 90             bool succeed = m_controller.TryDrawLine(cells[0].Data, cells[1].Data, out brokenCells);
 91             if (succeed)
 92             {
 93                 cells[0].AnimHide();
 94                 cells[1].AnimHide();
 95                 m_selectedCells.Clear();
 96 
 97                 // 画线
 98                 DrawLine(cells[0], cells[1], brokenCells);
 99 
100                 if (m_controller.GameFinished)
101                     OnGameFinished();
102             }
103             else
104             {
105                 var removedCell = m_selectedCells.Dequeue();
106                 removedCell.Selected = false;
107             }
108         }
109 
110         // 画线
111         void DrawLine(UI_LianLianKanCell start, UI_LianLianKanCell end, List<LianLianKanCell> brokenCells)
112         {
113             List<Vector3> points = new List<Vector3>();
114             points.Add(start.transform.localPosition);
115             for (int i = 0; i < brokenCells.Count; i++)
116             {
117                 UI_LianLianKanCell cell = Array.Find<UI_LianLianKanCell>(m_uiCells, c => c.Data == brokenCells[i]);
118                 points.Add(cell.transform.localPosition);
119             }
120             points.Add(end.transform.localPosition);
121             m_line.DrawLine(points);
122         }
123 
124         void LianLianKanController.IHandler.OnResetPos()
125         {
126             for (int i = 0; i < m_uiCells.Length; i++)
127                 m_uiCells[i].Reset();
128             m_selectedCells.Clear();
129         }
130     }
131 }
UI_LianLianKanWnd

4. 游戏界面上的格子UI

 1 using System;
 2 using UnityEngine;
 3 
 4 namespace Modules.UI
 5 {
 6     public class UI_LianLianKanCell : UI_BaseWidget
 7     {
 8         [SerializeField]
 9         UISprite m_spriteIcon;
10         [SerializeField]
11         GameObject m_objSelected;
12         [SerializeField]
13         UILabel m_labelName;
14         [SerializeField]
15         BackAndForthWindow m_anim;
16 
17         LianLianKanCell m_data;
18         IHandler m_handler;
19 
20 
21         public int Width
22         {
23             get { return m_spriteIcon.width; }
24         }
25 
26         public bool Selected
27         {
28             set { m_objSelected.SetActive(value); }
29             get { return m_objSelected.activeSelf; }
30         }
31 
32         public LianLianKanCell Data
33         {
34             get { return m_data; }
35         }
36 
37 
38         public interface IHandler
39         {
40             void OnClick(UI_LianLianKanCell self);
41         }
42 
43 
44         void Awake()
45         {
46             UIEventListener.Get(m_spriteIcon.gameObject).onClick = OnClickSelf;
47         }
48 
49         void OnClickSelf(GameObject go)
50         {
51             m_handler.OnClick(this);
52         }
53 
54         // icon: 索引从0到7
55         public void Init(LianLianKanCell data, IHandler handler)
56         {
57             if (data == null)
58                 throw new ArgumentNullException("data");
59             if (handler == null)
60                 throw new ArgumentNullException("handler");
61 
62             m_data = data;
63             m_handler = handler;
64         }
65 
66         public void Reset()
67         {
68             m_spriteIcon.spriteName = "icon_" + m_data.Icon;
69 
70             transform.localPosition = new Vector3(m_data.X * Width, m_data.Y * Width);
71             transform.name = m_data.ToString();
72             m_labelName.text = string.Format("{0}({1},{2})", m_data.Position, m_data.X, m_data.Y);
73             m_labelName.gameObject.SetActive(false);
74 
75             base.Show = m_data.Showing;
76 
77             Selected = false;
78         }
79 
80         public void AnimHide()
81         {
82             m_anim.Hide();
83             m_anim.OnHide = () =>
84             {
85                 Show = false;
86             };
87         }
88 
89     }
90 }
UI_LianLianKanCell

5. 游戏界面上的线

 1 using System;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 
 5 namespace Modules.UI
 6 {
 7     public class UI_LianLianKanLine : UI_BaseWidget
 8     {
 9         [SerializeField]
10         UISprite m_spriteLine;
11 
12         List<UISprite> m_lines = new List<UISprite>();
13 
14         void DrawLine(Vector3 start, Vector3 end)
15         {
16             UISprite spriteLine = GetOrCreateLine();
17             Vector3 center = (start + end) / 2f;
18             Vector3 fromStart = end - start;
19             Vector3 horVector = Vector3.right;
20             Quaternion rot = Quaternion.FromToRotation(horVector, fromStart);
21 
22             spriteLine.transform.localPosition = center;
23             spriteLine.transform.localRotation = rot;
24             spriteLine.width = Mathf.CeilToInt(fromStart.magnitude);
25             spriteLine.alpha = 1;
26             spriteLine.gameObject.SetActive(true);
27 
28             // 播放消隐动画
29             var anim = spriteLine.GetComponent<BackAndForthWindow>();
30             anim.Hide();
31             anim.OnHide = () => { anim.gameObject.SetActive(false); };
32         }
33 
34         UISprite GetOrCreateLine()
35         {
36             for (int i = 0; i < m_lines.Count; i++)
37             {
38                 var line = m_lines[i];
39                 if (!line.gameObject.activeSelf)
40                     return line;
41             }
42 
43             GameObject obj = NGUITools.AddChild(gameObject, m_spriteLine.gameObject);
44             UISprite sprite = obj.GetComponent<UISprite>();
45             m_lines.Add(sprite);
46             return sprite;
47         }
48 
49         void Start()
50         {
51             m_spriteLine.gameObject.SetActive(false);
52         }
53 
54         public void DrawLine(List<Vector3> points)
55         {
56             if (points.Count < 2 || points.Count > 4)
57                 throw new ArgumentException("points.Count < 2 || points.Count > 4, points count is: " + points.Count);
58 
59             for (int i = 0; i <= points.Count - 2; i++)
60             {
61                 DrawLine(points[i], points[i + 1]);
62             }
63         }
64     }
65 }
UI_LianLianKanLine

转载请注明出处:https://www.cnblogs.com/jietian331/p/10653450.html

三,效果如下:

原文地址:https://www.cnblogs.com/jietian331/p/10653450.html