消消乐游戏原理(附部分代码)

您所在的位置:网站首页 消消乐4391 消消乐游戏原理(附部分代码)

消消乐游戏原理(附部分代码)

2023-06-25 11:22| 来源: 网络整理| 查看: 265

在vs里看见一些方法上次修改是501天以前,乖乖,为了复试我也算是把陈谷子烂芝麻都翻出来读了。

一.存储

格子+格子哈希表[id],格子的属性:x,y,id,type

其中id=x*10+y

x=id/10

y=id%10

type代表格子属于什么类型,相同的3个相连可以消除

比如一个9*9的棋盘,x横轴,y是纵轴

818283848586878887172737475767778761626364656667686515253545556575854142434445464748431323334353637383212223242526272821112131415161718101020304050607080

为什么要这样设计呢?这样计算格子id是按照格子的坐标位置来的,x和y分别乘100就是格子在局部坐标系里的位置

二.生成一个没有三消情况的棋盘

生成写在二重循环里,每次加载一个格子都要进行一些判断↓

刷新的顺序是从下到上,从左到右,所以如果要判断有无可以直接消除的情况,只需看每个格子的左边和下边

所以我们检查格子的左边和左边的左边,以及下边和下边的下边,如果有两个重样的,记录下type,随机给type赋值的时候去掉

                              

 

至此,一个没有三连的棋盘就生成了

三.点击,移动

给格子添加点击事件,记录如果玩家两次分别点了两个不一样的格子,那么

判断两个格子是不是紧挨着,否则无法移动

如果可以,则修改两者的目标位置为彼此,然后将其中一个格子添加到移动列表中,并在哈希中交换两个格子的数据信息

,最后,修改在格子管理器内的update中用于检查消除的key为true。

格子管理器update部分代码如下

void Update() { if (RemoveKye) //目前仅需关注这个 { if (IsMove.Count == 0) { RemoveGrid(); RemoveKye = false; } } if (IsDownKey)//目前仅需关注这个 { if (IsMove.Count == 0) { IsDownKey = false; ReSetNullGrid(); } } if (PlayKey) { mTime -= Time.deltaTime* factor; if (mTime < 0) { totalSeconds++; mTime = 1; GameTime -= 1; TimeText.text = GameTime.ToString(); timeCounter.UpdateCombo(); TimeBar.size = GameTime / GameTimeAll; } if (totalSeconds==60 ) { factor+=0.5f; totalSeconds = 0; } if (GameTime == 0) { Global.instance.SoundManager.PlayBGM("ScoreSubmit"); PlayKey = false; ScoreUpdateTransform.gameObject.SetActive(true); ScoreUp.text = numScore.ToString(); AverCombo.text = timeCounter.CalculateAverCombo().ToString("f2"); ComboCommit.text = timeCounter.GetComboCommit(); timeCounter.InitTimeCounter(); foreach (int id in DicGrid.Keys) { Destroy(DicGrid[id].transform.gameObject); } DicGrid.Clear(); } } }

而检查消除的方法在移动列表为空时才会执行,所以,现在两个格子正在朝彼此的位置移动。

如何实现朝彼此移动?在格子的update中添加判断

void Update() { if (transform.localPosition.x == TragetPos.x && transform.localPosition.y == TragetPos.y) { if (GridController.Instance.IsMove.Contains(GridId)) { GridController.Instance.IsMove.Remove(GridId); } } if (transform.localPosition.x != TragetPos.x) { if (transform.localPosition.x > TragetPos.x) { Vector2 pos = transform.localPosition; pos.x -= (Speed * Time.deltaTime); pos.x = pos.x < TragetPos.x ? TragetPos.x : pos.x; transform.localPosition = pos; } else { Vector2 pos = transform.localPosition; pos.x += (Speed * Time.deltaTime); pos.x = pos.x > TragetPos.x ? TragetPos.x : pos.x; transform.localPosition = pos; } } if (transform.localPosition.y != TragetPos.y) { if (transform.localPosition.y > TragetPos.y) { Vector2 pos = transform.localPosition; pos.y -= (Speed * Time.deltaTime); pos.y = pos.y < TragetPos.y ? TragetPos.y : pos.y; transform.localPosition = pos; } else { Vector2 pos = transform.localPosition; pos.y += (Speed * Time.deltaTime); pos.y = pos.y > TragetPos.y ? TragetPos.y : pos.y; transform.localPosition = pos; } } }

由此可见,当格子到达指定位置时,停止移动,移动列表也将会删除该格子

同时,格子管理器内的update方法检测到key为true同时移动列表为空,即所有格子到达目标位置,则开始判断棋盘中的三消情况

四.检查消除

遍历整个棋盘,判断每个格子的上面2个和右边两个是否三个相等,是就查重后添加到删除列表中(事实上上面也有些操作需要查重,基本操作不需提)

然后判断如果消除列表不为0,则顺着删除列表依次把格子删除,此时,三消完成

如果不能消除,则先判断鼠标点的那两个格子是否都存在,若都存在,则交换两个格子的位置,再换回来。

五.下落,生成新的格子

先下落

遍历棋盘,从下到上,从左往右,找到每列第一个空位,标记下来,再把上面所有非空格都挪下来。

代码示范

public void AllGridMoveDown() { for (int x = 0; x < 7; x++) { int NullGridPos = -1; for (int y = 0; y < 7; y++) { if (!DicGrid.ContainsKey(GetGridID(x, y))) { if (NullGridPos == -1) { NullGridPos = y; } } else if (NullGridPos != -1) { Vector2 pos = DicGrid[GetGridID(x, y)].transform.localPosition; pos.y = NullGridPos * 100; DicGrid[GetGridID(x, y)].TragetPos = pos; if (!IsMove.Contains(GetGridID(x, NullGridPos))) { IsMove.Add(GetGridID(x, NullGridPos)); } GridUnit t = DicGrid[GetGridID(x, y)]; DicGrid.Remove(GetGridID(x, y)); DicGrid.Add(GetGridID(x, NullGridPos), t); t.GridId = GetGridID(x, NullGridPos); NullGridPos++; } } } IsDownKey = true; }

等待移动列表为空,也就是上面的格子完成下落动作后,然后生成新格子,很简单,遍历棋盘,找到空位,按照生成棋盘的方法随机产生新格子即可。

产生格子完成后,重新检查能不能有三消,如果有,重复上述过程,如果没有,则检查地图内有无可以消除的隐藏情况,如果没有能消除的(死棋),则重新生成棋盘

bool ReStart() { for (int x = 0; x < xl; x++) { for (int y = 0; y < yl; y++) { if ( //尖括号种类消除 Comparator(GetGridID(x, y), GetGridID(x - 1, y - 1), GetGridID(x - 1, y + 1), GetGridID(x-1,y)) || Comparator(GetGridID(x, y), GetGridID(x + 1, y + 1), GetGridID(x - 1, y + 1),GetGridID(x,y+1)) || Comparator(GetGridID(x, y), GetGridID(x + 1, y - 1), GetGridID(x + 1, y + 1),GetGridID(x+1,y)) || Comparator(GetGridID(x, y), GetGridID(x - 1, y - 1), GetGridID(x - 1, y + 1),GetGridID(x-1,y)) //感叹号种类消除 || Comparator(GetGridID(x, y), GetGridID(x - 2, y), GetGridID(x - 3, y),GetGridID(x-1,y)) || Comparator(GetGridID(x, y), GetGridID(x + 2, y), GetGridID(x + 3, y),GetGridID(x+1,y)) || Comparator(GetGridID(x, y), GetGridID(x, y - 2), GetGridID(x, y - 3),GetGridID(x,y-1)) || Comparator(GetGridID(x, y), GetGridID(x, y + 2), GetGridID(x, y + 3),GetGridID(x,y+1)) //小拐弯种类 || Comparator(GetGridID(x, y), GetGridID(x - 1, y - 1), GetGridID(x - 1, y - 2),GetGridID(x-1,y)) || Comparator(GetGridID(x, y), GetGridID(x + 1, y - 1), GetGridID(x + 1, y - 2),GetGridID(x+1,y)) || Comparator(GetGridID(x, y), GetGridID(x - 1, y + 1), GetGridID(x - 1, y + 2),GetGridID(x-1,y)) || Comparator(GetGridID(x, y), GetGridID(x + 1, y + 1), GetGridID(x + 1, y + 2),GetGridID(x+1,y)) || Comparator(GetGridID(x, y), GetGridID(x - 1, y - 1), GetGridID(x - 2, y - 1),GetGridID(x,y-1)) || Comparator(GetGridID(x, y), GetGridID(x - 1, y + 1), GetGridID(x - 2, y + 1),GetGridID(x,y+1)) || Comparator(GetGridID(x, y), GetGridID(x + 1, y - 1), GetGridID(x + 2, y - 1),GetGridID(x,y-1)) || Comparator(GetGridID(x, y), GetGridID(x + 1, y + 1), GetGridID(x + 2, y + 1),GetGridID(x,y+1)) ) { return true; } } } return false; }

找个图画一下,大致就是把各种移动一下就能消除的情况都列出来判断,代码不怕麻烦。

 

想到的一些其他功能

 

1.空格子,空格子也是一种格子,只是无法移动且无法消除,在格子下落和三消判断的那里添加相关注意就可以了

2.提示道具,跟上面检查有没有可以消除的隐藏位置原理相同。

3.地图编辑器,消消乐这种关卡游戏肯定需要地图编辑器,要不一个一个关卡手改也怪麻烦的

将关卡的相关信息,比如尺寸,空格子位置,道具数量等,专门定义一个类的对象来保存,在编辑器内做相关修改,完事用json导出到文本就可以了。需要的时候按照文本名字作为关卡名再用json导回。

 

我几乎不玩消消乐类游戏,应该还有其他很多的花样,不过在弄懂原理之后,修改起来也就有的放矢了。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3