NGUI之实现连连看小游戏

时间:2023-03-10 08:51:39
NGUI之实现连连看小游戏

一,部分游戏规则如下:

NGUI之实现连连看小游戏

二,代码如下:

1. 游戏逻辑核心代码

 using System.Collections.Generic;
using UnityEngine; namespace Modules.UI
{
// 逻辑与UI分离,这是逻辑类
public class LianLianKanController
{
int m_rowCount;
List<LianLianKanCell> m_cells = new List<LianLianKanCell>();
IHandler m_handler; public int RowCount
{
get { return m_rowCount; }
} public List<LianLianKanCell> Cells
{
get { return m_cells; }
} public bool GameFinished
{
get
{
for (int i = ; i < m_cells.Count; i++)
{
if (m_cells[i].Showing)
{
return false;
}
}
return true;
}
} public interface IHandler
{
void OnResetPos();
} public LianLianKanController(int rowCount, IHandler handler)
{
m_rowCount = rowCount + ; // 为了边缘上的格子也能连线
m_handler = handler; // 生成cell
for (int x = ; x < m_rowCount; x++)
{
for (int y = ; y < m_rowCount; y++)
{
int pos = m_rowCount * y + x;
LianLianKanCell cell = new LianLianKanCell(this);
cell.Position = pos;
cell.Showing = x != && x != m_rowCount - && y != && y != m_rowCount - ;
cell.Icon = y - ;
m_cells.Add(cell);
}
}
} // 打乱
public void ResetPos()
{
List<int> positions = new List<int>();
for (int i = ; i <= m_rowCount - ; i++)
{
for (int j = ; j <= m_rowCount - ; j++)
{
int pos = m_rowCount * j + i;
positions.Add(pos);
}
} for (int i = ; i < m_cells.Count; i++)
{
var cell = m_cells[i];
if (cell.Showing)
{
int ranIndex = Random.Range(, positions.Count);
int position = positions[ranIndex];
positions.RemoveAt(ranIndex);
cell.Position = position;
}
} bool canDraw = CanDrawAnyLine();
if (canDraw)
m_handler.OnResetPos();
else
ResetPos();
} bool CanDrawAnyLine(LianLianKanCell start)
{
for (int i = ; i < m_cells.Count; i++)
{
var end = m_cells[i];
if (start != end && end.Showing)
{
List<LianLianKanCell> brokenCells;
bool isMatch = IsMatch(start, end, out brokenCells);
if (isMatch)
return true;
}
} return false;
} bool CanDrawAnyLine()
{
for (int i = ; i < m_cells.Count; i++)
{
var start = m_cells[i];
if (start.Showing)
{
bool canDraw = CanDrawAnyLine(start);
if (canDraw)
return true;
}
} return false;
} // 尝试连线
public bool TryDrawLine(LianLianKanCell first, LianLianKanCell second, out List<LianLianKanCell> brokenCells)
{
bool isMatch = IsMatch(first, second, out brokenCells);
if (isMatch)
{
first.Showing = false;
second.Showing = false; if (!GameFinished && !CanDrawAnyLine())
{
ResetPos();
}
}
return isMatch;
} LianLianKanCell GetCellByPos(int x, int y)
{
for (int i = ; i < m_cells.Count; i++)
{
var cell = m_cells[i];
if (cell.X == x && cell.Y == y)
return cell;
}
return null;
} // 0个拐点
bool MatchBroken0(LianLianKanCell first, LianLianKanCell second)
{
// 如果不属于0折连接则返回false
if (first.X != second.X && first.Y != second.Y)
{
return false;
} int min, max;
// 如果两点的x坐标相等,则在竖直方向上扫描
if (first.X == second.X)
{
min = first.Y < second.Y ? first.Y : second.Y;
min++;
max = first.Y > second.Y ? first.Y : second.Y; for (int i = min; i < max; i++)
{
var cell = GetCellByPos(first.X, i);
if (cell.Showing)
return false;
}
}
// 如果两点的y坐标相等,则在水平方向上扫描
else
{
min = first.X < second.X ? first.X : second.X;
min++;
max = first.X > second.X ? first.X : second.X; for (int i = min; i < max; i++)
{
var cell = GetCellByPos(i, first.Y);
if (cell.Showing)
return false;
}
} return true;
} // 1个拐点
bool MatchBroken1(LianLianKanCell first, LianLianKanCell second, out LianLianKanCell brokenCell)
{
if (first.X == second.X || first.Y == second.Y)
{
brokenCell = null;
return false;
} // 测试对角点1
brokenCell = GetCellByPos(first.X, second.Y);
if (!brokenCell.Showing)
{
bool match = MatchBroken0(first, brokenCell) && MatchBroken0(brokenCell, second);
if (match)
return true;
} // 测试对角点2
brokenCell = GetCellByPos(second.X, first.Y);
if (!brokenCell.Showing)
{
bool match = MatchBroken0(first, brokenCell) && MatchBroken0(brokenCell, second);
if (match)
return true;
} return false;
} // 2个拐点
bool MatchBroken2(LianLianKanCell first, LianLianKanCell second, ref List<LianLianKanCell> brokenCells)
{
for (int i = first.Y + ; i < m_rowCount; i++)
{
var cell = GetCellByPos(first.X, i);
if (cell.Showing)
break; LianLianKanCell brokenCell;
if (MatchBroken1(cell, second, out brokenCell))
{
brokenCells.Add(cell);
brokenCells.Add(brokenCell);
return true;
}
} for (int i = first.Y - ; i > -; i--)
{
var cell = GetCellByPos(first.X, i);
if (cell.Showing)
break; LianLianKanCell brokenCell;
if (MatchBroken1(cell, second, out brokenCell))
{
brokenCells.Add(cell);
brokenCells.Add(brokenCell);
return true;
}
} for (int i = first.X + ; i < m_rowCount; i++)
{
var cell = GetCellByPos(i, first.Y);
if (cell.Showing)
break; LianLianKanCell brokenCell;
if (MatchBroken1(cell, second, out brokenCell))
{
brokenCells.Add(cell);
brokenCells.Add(brokenCell);
return true;
}
} for (int i = first.X - ; i > -; i--)
{
var cell = GetCellByPos(i, first.Y);
if (cell.Showing)
break; LianLianKanCell brokenCell;
if (MatchBroken1(cell, second, out brokenCell))
{
brokenCells.Add(cell);
brokenCells.Add(brokenCell);
return true;
}
} return false;
} bool IsMatch(LianLianKanCell first, LianLianKanCell second, out List<LianLianKanCell> brokenCells)
{
brokenCells = new List<LianLianKanCell>();
if (first == second || first.Icon != second.Icon)
return false; // 0个拐点
if (MatchBroken0(first, second))
return true; // 1个拐点
LianLianKanCell brokenCell;
if (MatchBroken1(first, second, out brokenCell))
{
brokenCells.Add(brokenCell);
return true;
} // 2个拐点
if (MatchBroken2(first, second, ref brokenCells))
return true; return false;
} }
}

LianLianKanController

2. 封装了一个格子

 using System;

 namespace Modules.UI
{
public class LianLianKanCell
{
LianLianKanController m_controller;
int m_icon; // icon的索引,从0到7
int m_position; // 位置索引,从0到63
bool m_showing; // 是否显示中 public int Icon
{
get { return m_icon; }
set { m_icon = value; }
} public bool Showing
{
get { return m_showing; }
set { m_showing = value; }
} public int Position
{
get { return m_position; }
set { m_position = value; }
} public int X
{
get { return m_position % m_controller.RowCount; }
} public int Y
{
get { return m_position / m_controller.RowCount; }
} public LianLianKanCell(LianLianKanController controller)
{
if (controller == null)
throw new ArgumentNullException("controller"); m_controller = controller;
} public override string ToString()
{
return string.Format("{0}_{1}_{2}", m_icon, m_position, m_showing);
}
}
}

LianLianKanCell

3. 游戏界面

 using System;
using System.Collections.Generic;
using UnityEngine; namespace Modules.UI
{
public class UI_LianLianKanWnd : UI_AutoSortDepthWnd, UI_LianLianKanCell.IHandler, LianLianKanController.IHandler
{
public static int RowCount = ; [SerializeField]
GameObject m_btnClose;
[SerializeField]
UI_LianLianKanCell m_cell;
[SerializeField]
Transform m_parentOfCell;
[SerializeField]
UI_LianLianKanLine m_line; LianLianKanController m_controller;
UI_LianLianKanCell[] m_uiCells;
Queue<UI_LianLianKanCell> m_selectedCells = new Queue<UI_LianLianKanCell>(); public static void Create()
{
UIManager.ShowUISync(UIFlag.ui_entertainment_war, UIFlag.ui_lianliankan, UIFlag.none, false, null, UIFlag.none);
} protected override UIFlag UIFlag
{
get { return UIFlag.ui_lianliankan; }
} protected override void Awake()
{
base.Awake(); UIEventListener.Get(m_btnClose).onClick = OnClickClose; // 生成icon
m_controller = new LianLianKanController(RowCount, this);
m_uiCells = new UI_LianLianKanCell[m_controller.Cells.Count];
m_cell.Show = false;
float posOfCellsParent = (m_controller.RowCount / 2f - 0.5f) * m_cell.Width;
m_parentOfCell.localPosition = new Vector3(-posOfCellsParent, -posOfCellsParent);
for (int i = ; i < m_uiCells.Length; i++)
{
UI_LianLianKanCell cell = m_cell.Instantiate<UI_LianLianKanCell>(m_parentOfCell);
cell.Init(m_controller.Cells[i], this);
m_uiCells[i] = cell;
}
} void OnClickClose(GameObject go)
{
Close();
} public override void OnShowWnd(UIWndData wndData)
{
base.OnShowWnd(wndData); ResetWnd();
} void ResetWnd()
{
m_controller.ResetPos();
} void OnGameFinished()
{
UIMessageMgr.ShowMessageBoxOnlyOK("成功完成!", base.Close, null);
} void UI_LianLianKanCell.IHandler.OnClick(UI_LianLianKanCell self)
{
if (m_selectedCells.Contains(self))
return; self.Selected = true;
m_selectedCells.Enqueue(self); if (m_selectedCells.Count < )
return; var cells = m_selectedCells.ToArray();
List<LianLianKanCell> brokenCells;
bool succeed = m_controller.TryDrawLine(cells[].Data, cells[].Data, out brokenCells);
if (succeed)
{
cells[].AnimHide();
cells[].AnimHide();
m_selectedCells.Clear(); // 画线
DrawLine(cells[], cells[], brokenCells); if (m_controller.GameFinished)
OnGameFinished();
}
else
{
var removedCell = m_selectedCells.Dequeue();
removedCell.Selected = false;
}
} // 画线
void DrawLine(UI_LianLianKanCell start, UI_LianLianKanCell end, List<LianLianKanCell> brokenCells)
{
List<Vector3> points = new List<Vector3>();
points.Add(start.transform.localPosition);
for (int i = ; i < brokenCells.Count; i++)
{
UI_LianLianKanCell cell = Array.Find<UI_LianLianKanCell>(m_uiCells, c => c.Data == brokenCells[i]);
points.Add(cell.transform.localPosition);
}
points.Add(end.transform.localPosition);
m_line.DrawLine(points);
} void LianLianKanController.IHandler.OnResetPos()
{
for (int i = ; i < m_uiCells.Length; i++)
m_uiCells[i].Reset();
m_selectedCells.Clear();
}
}
}

UI_LianLianKanWnd

4. 游戏界面上的格子UI

 using System;
using UnityEngine; namespace Modules.UI
{
public class UI_LianLianKanCell : UI_BaseWidget
{
[SerializeField]
UISprite m_spriteIcon;
[SerializeField]
GameObject m_objSelected;
[SerializeField]
UILabel m_labelName;
[SerializeField]
BackAndForthWindow m_anim; LianLianKanCell m_data;
IHandler m_handler; public int Width
{
get { return m_spriteIcon.width; }
} public bool Selected
{
set { m_objSelected.SetActive(value); }
get { return m_objSelected.activeSelf; }
} public LianLianKanCell Data
{
get { return m_data; }
} public interface IHandler
{
void OnClick(UI_LianLianKanCell self);
} void Awake()
{
UIEventListener.Get(m_spriteIcon.gameObject).onClick = OnClickSelf;
} void OnClickSelf(GameObject go)
{
m_handler.OnClick(this);
} // icon: 索引从0到7
public void Init(LianLianKanCell data, IHandler handler)
{
if (data == null)
throw new ArgumentNullException("data");
if (handler == null)
throw new ArgumentNullException("handler"); m_data = data;
m_handler = handler;
} public void Reset()
{
m_spriteIcon.spriteName = "icon_" + m_data.Icon; transform.localPosition = new Vector3(m_data.X * Width, m_data.Y * Width);
transform.name = m_data.ToString();
m_labelName.text = string.Format("{0}({1},{2})", m_data.Position, m_data.X, m_data.Y);
m_labelName.gameObject.SetActive(false); base.Show = m_data.Showing; Selected = false;
} public void AnimHide()
{
m_anim.Hide();
m_anim.OnHide = () =>
{
Show = false;
};
} }
}

UI_LianLianKanCell

5. 游戏界面上的线

 using System;
using System.Collections.Generic;
using UnityEngine; namespace Modules.UI
{
public class UI_LianLianKanLine : UI_BaseWidget
{
[SerializeField]
UISprite m_spriteLine; List<UISprite> m_lines = new List<UISprite>(); void DrawLine(Vector3 start, Vector3 end)
{
UISprite spriteLine = GetOrCreateLine();
Vector3 center = (start + end) / 2f;
Vector3 fromStart = end - start;
Vector3 horVector = Vector3.right;
Quaternion rot = Quaternion.FromToRotation(horVector, fromStart); spriteLine.transform.localPosition = center;
spriteLine.transform.localRotation = rot;
spriteLine.width = Mathf.CeilToInt(fromStart.magnitude);
spriteLine.alpha = ;
spriteLine.gameObject.SetActive(true); // 播放消隐动画
var anim = spriteLine.GetComponent<BackAndForthWindow>();
anim.Hide();
anim.OnHide = () => { anim.gameObject.SetActive(false); };
} UISprite GetOrCreateLine()
{
for (int i = ; i < m_lines.Count; i++)
{
var line = m_lines[i];
if (!line.gameObject.activeSelf)
return line;
} GameObject obj = NGUITools.AddChild(gameObject, m_spriteLine.gameObject);
UISprite sprite = obj.GetComponent<UISprite>();
m_lines.Add(sprite);
return sprite;
} void Start()
{
m_spriteLine.gameObject.SetActive(false);
} public void DrawLine(List<Vector3> points)
{
if (points.Count < || points.Count > )
throw new ArgumentException("points.Count < 2 || points.Count > 4, points count is: " + points.Count); for (int i = ; i <= points.Count - ; i++)
{
DrawLine(points[i], points[i + ]);
}
}
}
}

UI_LianLianKanLine

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

三,效果如下:

NGUI之实现连连看小游戏