一,部分游戏规则如下:
二,代码如下:
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 }
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 }
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 }
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 }
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 }
转载请注明出处:https://www.cnblogs.com/jietian331/p/10653450.html
三,效果如下: