糖果消消乐的算法实现
定义糖果枚举类型
public enum CandyType {
Type1=0,
Type2=1,
Type3=2,
Type4=3,
Type5=4,
Type6=5,
Type7=6,
}
定义糖果行为
public class Candy : MonoBehaviour
{
//糖果在地图上的二维坐标索引
internal int x, y;
//糖果类型
public CandyType candyType;
public void OnMouseDown()
{
EventManage.Instance.OnTriggerEvent("OnColorBlockDown",this);
}
public void OnMouseEnter()
{
EventManage.Instance.OnTriggerEvent("OnColorBlockEnter", this);
}
public void OnMouseUp()
{
EventManage.Instance.OnTriggerEvent("OnColorBlockUp", this);
}
public void Move(Vector3 pos)
{
Debug.Log("移动");
transform.DOLocalMove(pos, 0.2f);
}
}
定义地图
public class MapBlock
{
public int x,y;
public Vector3 localPos;
public Candy colorBlock;
/// <summary>
/// 填充糖果
/// </summary>
/// <param name="colorBlock"></param>
public void AddColorBlock(Candy colorBlock) {
this.colorBlock = colorBlock;
this.colorBlock.transform.localPosition = localPos;
this.colorBlock.x = x;
this.colorBlock.y = y;
}
public void AddColorBlockAnim(Candy colorBlock)
{
this.colorBlock = colorBlock;
this.colorBlock.Move(localPos);
this.colorBlock.x = x;
this.colorBlock.y = y;
}
/// <summary>
/// 糖果移除
/// </summary>
/// <param name="colorBlock"></param>
public void RemoveColorBlock()
{
this.colorBlock = null;
}
}
核心控制类
核心控制类包含填充,移动,交换,消除功能
// An highlighted block
public class BlockManage : MonoBehaviour
{
public static BlockManage Instance;
public int row;
public int column;
internal MapBlock[,] mapBlocks;
public Candy[] colorBlocks;
public GameObject blockBg;
private Candy downColorBlock;
private Candy upColorBlock;
private bool isOver;
private bool isClearFinish;//是否清理结束
private int clearCount;//单次清理数量
internal UnityAction<int> ClearEvent;
private void Awake()
{
Instance = this;
EventManage.Instance.AddEventListener("OnColorBlockDown", OnColorBlockDown);
EventManage.Instance.AddEventListener("OnColorBlockEnter", OnColorBlockEnter);
EventManage.Instance.AddEventListener("OnColorBlockUp", OnColorBlockUp);
StartGame();
}
public void StartGame() {
mapBlocks = new MapBlock[row, column];
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
MapBlock mapBlock = new MapBlock();
mapBlock.localPos = new Vector3(j, i, 0);
mapBlock.x = i;
mapBlock.y = j;
mapBlocks[i, j] = mapBlock;
GameObject bg = Instantiate(blockBg, transform);
bg.transform.localPosition = mapBlock.localPos;
}
}
StartCoroutine(FillBlock());
}
public void Restart() {
isOver = false;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
if (mapBlocks[i,j].colorBlock!=null) {
Destroy(mapBlocks[i, j].colorBlock.gameObject);
mapBlocks[i, j].RemoveColorBlock();
}
}
}
StartCoroutine(FillBlock());
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space)) {
Restart();
}
}
public void GameOver() {
isOver = true;
}
private void OnColorBlockDown(object colorBlock) {
if (isOver) return;
if (!isClearFinish) return;
if (this.downColorBlock == null)
{
this.downColorBlock = (Candy)colorBlock;
}
}
private void OnColorBlockEnter(object colorBlock)
{
if (isOver) return;
if (!isClearFinish) return;
if (this.downColorBlock!=null) {
if (this.upColorBlock==null) {
this.upColorBlock = (Candy)colorBlock;
Vector3 pos1 = upColorBlock.transform.localPosition;
Vector3 pos2 = downColorBlock.transform.localPosition;
downColorBlock.Move(pos1);
upColorBlock.Move(pos2);
}
}
}
private void OnColorBlockUp(object colorBlock)
{
if (isOver) return;
if (!isClearFinish) return;
if (upColorBlock != null && downColorBlock != null && upColorBlock.candyType != downColorBlock.candyType)
{
Swap(downColorBlock, upColorBlock);
this.downColorBlock = null;
this.upColorBlock = null;
}
}
private IEnumerator FillBlock()
{
while (true) {
for (int i = 0; i < row-1; i++)
{
for (int j = 0; j < column; j++)
{
if (mapBlocks[i, j].colorBlock == null)
{
if (i+1==row-1) {
if (mapBlocks[i + 1, j].colorBlock == null) {
mapBlocks[i+1, j].AddColorBlock(SpawnBlock());
}
}
if (mapBlocks[i + 1, j].colorBlock != null)
{
mapBlocks[i, j].AddColorBlock(mapBlocks[i + 1, j].colorBlock);
mapBlocks[i + 1, j].RemoveColorBlock();
}
}
}
}
if (!IsFill())
{
for (int j = 0; j < column; j++)
{
if (mapBlocks[row - 1, j].colorBlock == null)
{
mapBlocks[row - 1, j].AddColorBlock(SpawnBlock());
}
}
}
else {
break;
}
yield return new WaitForSeconds(0.02f);
}
Clear();
}
private bool IsFill() {
for (int j = 0; j < column; j++)
{
if (mapBlocks[row - 1, j].colorBlock == null)
{
return false;
}
}
return true;
}
private Candy SpawnBlock() {
CandyType colorBlockType = (CandyType)Random.Range(0, colorBlocks.Length);
return CreateColorBlock(colorBlockType);
}
private Candy CreateColorBlock(CandyType colorBlockType)
{
for (int i = 0; i < colorBlocks.Length; i++)
{
if (colorBlocks[i].candyType == colorBlockType)
{
return Instantiate(colorBlocks[i], transform);
}
}
return null;
}
private void Clear() {
for (int i = 0; i < row-1; i++)
{
for (int j = 0; j < column; j++)
{
if (mapBlocks[i,j].colorBlock!=null) {
if (CanRemoved(mapBlocks[i, j].colorBlock)) {
List<Candy> tempBlock=new List<Candy>();
tempBlock.Clear();
FindTheSameBlock(mapBlocks[i, j].colorBlock, in tempBlock);
if (tempBlock != null)
{
isClearFinish = false;
clearCount++;
StartCoroutine(IeClear(tempBlock));
return;
}
}
}
}
}
ClearEvent?.Invoke(clearCount);
clearCount = 0;
isClearFinish = true;
}
private IEnumerator IeClear(List<Candy> tempBlock) {
for (int k = 0; k < tempBlock.Count; k++)
{
if (tempBlock[k]!=null) {
DestroyImmediate(tempBlock[k].gameObject);
mapBlocks[tempBlock[k].x, tempBlock[k].y].RemoveColorBlock();
yield return new WaitForSeconds(0.01f);
}
}
yield return StartCoroutine(FillBlock());
}
private bool CanRemoved(Candy colorBlock) {
List<Candy> mathingBlock = new List<Candy>();
mathingBlock.Add(colorBlock);
int x = colorBlock.x;
int y = colorBlock.y;
bool isLeftOrUp = true;
bool isRightOrDown = true;
// 横向遍历
for (int j = 1; j < column; j++)
{
int leftIndex = y - j;
int rightIndex = y + j;
if (!isRightOrDown && !isLeftOrUp)
{
break;
}
if (leftIndex >= 0 && isLeftOrUp)
{
if (mapBlocks[x, leftIndex].colorBlock.candyType == colorBlock.candyType)
{
mathingBlock.Add(mapBlocks[x, leftIndex].colorBlock);
}
else
{
isLeftOrUp = false;
}
}
if (rightIndex < column && isRightOrDown)
{
if (mapBlocks[x, rightIndex].colorBlock.candyType == colorBlock.candyType)
{
mathingBlock.Add(mapBlocks[x, rightIndex].colorBlock);
}
else
{
isRightOrDown = false;
}
}
}
if (mathingBlock.Count < 3)
{
isLeftOrUp = true;
isRightOrDown = true;
mathingBlock.Clear();
mathingBlock.Add(colorBlock);
//纵向遍历
for (int i = 1; i < row; i++)
{
int downIndex = x - i;
int upIndex = x + i;
if (!isRightOrDown && !isLeftOrUp)
{
break;
}
if (downIndex >= 0 && isRightOrDown)
{
if (mapBlocks[downIndex, y].colorBlock.candyType == colorBlock.candyType)
{
mathingBlock.Add(mapBlocks[downIndex, y].colorBlock);
}
else
{
isRightOrDown = false;
}
}
if (upIndex < row && isLeftOrUp)
{
if (mapBlocks[upIndex, y].colorBlock.candyType == colorBlock.candyType)
{
mathingBlock.Add(mapBlocks[upIndex, y].colorBlock);
}
else
{
isLeftOrUp = false;
}
}
}
}
if (mathingBlock.Count<3) {
return false;
}
return true;
}
private void FindTheSameBlock(Candy colorBlock,in List<Candy> sameBlockList) {
sameBlockList.Add(colorBlock);
int i = colorBlock.x;
int j = colorBlock.y;
if (i-1>=0) {
if (mapBlocks[i-1,j].colorBlock.candyType== colorBlock.candyType) {
if (!sameBlockList.Contains(mapBlocks[i - 1, j].colorBlock)) {
sameBlockList.Add(mapBlocks[i - 1, j].colorBlock);
FindTheSameBlock(mapBlocks[i - 1, j].colorBlock, in sameBlockList);
}
}
}
if (i + 1 <row)
{
if (mapBlocks[i + 1, j].colorBlock.candyType == colorBlock.candyType)
{
if (!sameBlockList.Contains(mapBlocks[i + 1, j].colorBlock)) {
sameBlockList.Add(mapBlocks[i + 1, j].colorBlock);
FindTheSameBlock(mapBlocks[i + 1, j].colorBlock, in sameBlockList);
}
}
}
if (j + 1 < column)
{
if (mapBlocks[i, j+1].colorBlock.candyType == colorBlock.candyType)
{
if (!sameBlockList.Contains(mapBlocks[i, j + 1].colorBlock))
{
sameBlockList.Add(mapBlocks[i, j + 1].colorBlock);
FindTheSameBlock(mapBlocks[i, j + 1].colorBlock, in sameBlockList);
}
}
}
if (j - 1 >=0)
{
if (mapBlocks[i, j - 1].colorBlock.candyType == colorBlock.candyType)
{
if (!sameBlockList.Contains(mapBlocks[i, j - 1].colorBlock))
{
sameBlockList.Add(mapBlocks[i, j - 1].colorBlock);
FindTheSameBlock(mapBlocks[i, j - 1].colorBlock, in sameBlockList);
}
}
}
}
private void Swap(Candy downColorBlock,Candy upColorBlock) {
int i = Mathf.Abs(Mathf.Abs(downColorBlock.x) - Mathf.Abs(upColorBlock.x));
int j = Mathf.Abs(Mathf.Abs(downColorBlock.y) - Mathf.Abs(upColorBlock.y));
if ((i == 0 && j == 1)||(j == 0 && i == 1))
{
int x = upColorBlock.x;
int y = upColorBlock.y;
mapBlocks[downColorBlock.x, downColorBlock.y].AddColorBlock(upColorBlock);
mapBlocks[x, y].AddColorBlock(downColorBlock);
if (CanRemoved(upColorBlock) || CanRemoved(downColorBlock))
{
Clear();
}
else {
x = upColorBlock.x;
y = upColorBlock.y;
mapBlocks[downColorBlock.x, downColorBlock.y].AddColorBlockAnim(upColorBlock);
mapBlocks[x, y].AddColorBlock(downColorBlock);
}
}
}
}