• 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

    三,效果如下:

  • 相关阅读:
    test
    结构体内存对齐
    单链表(指针的指针应用)
    C语言实现线程池
    线程私有数据和pthread_once
    fcntl函数
    同构树
    动态规划经典题
    DP--方格取数问题
    动态规划的基本模型
  • 原文地址:https://www.cnblogs.com/jietian331/p/10653450.html
Copyright © 2020-2023  润新知