一、引言
有天中午正好看到有同事在玩消消乐,也即是出名的三消类游戏,顿时引发了我想要探索实现一个三消类游戏的兴趣。
花了两天的探索,终于有了一个半成品,这篇博客就将我这两天的思考过程记录下来,以飨读者。
上图是我的半成品三消游戏 Demo 的效果展示。基本完成了以下功能:
1. 随机初始化网格
2. 消除操作
3. 消除提示
尚有以下功能尚未实现(其他三消游戏一般都有的):
1. 消除后重力随机补充
2. 分数计算
这个 Demo 尽管使用了一个不是那么恰当的 UI 库 SOUI(这是用来做应用软件的并非专长于游戏领域),但是秉承于重在体验研究算法轻于实现效果,本人还是怎么轻松怎么来了(T_T)。
那么,接下来就开始我们的三消游戏实现之旅吧!
二、需求探讨:参考游戏HeroEmblems
要做一个三消游戏,那么最简单的例子就是找现成的一个比较成功的游戏来观摩学习:
这是我比较钟爱的一款三消游戏(花了我25RMB呢!),我们看看这个界面,可以得到以下需求:
1. 一共有 7 行 8 列,共 56 个格子
2. 一共有 4 种图像按钮
3. 横向或者纵向至少连成 3 个即可消去这 3 个按钮,并且在重力影响下移动相应受影响格子;另外,在移动的过程中若遇到了 3 个相连则继续消去,直到没有 3 个相连元素为止
4. 初始化的时候,必然没有任意行或者列有 3 个元素相连
根据上述规则,我们很容易得知自己要做什么了,那么接下来,我们把自己要做的工作分为三个步骤:
1. 实现初始化随机网格(并且保证没有 3 个相连的情况发生)
2. 实现消除功能
3. 实现消除补充(尚未实现)
三、磨刀:数据结构设计
在开始我们的开发之前,我们还要注意最基本也就是非常重要的一步,那就是数据结构设计。
让我们看看,这里需要怎样的数据结构呢?
1. PosPoint: 表示一个坐标点。
这个毋庸置疑,我们要操作一个格子,必然要通过坐标来访问,这里定一个坐标点结构也能够方便我们的开发过程。
// 一个坐标点
struct PosPoint
{
PosPoint() : row(0), col(0) {}
PosPoint(int row, int col) : row(row), col(col) {}
PosPoint SetPos(int row, int col) {
row = row, col = col;
return PosPoint(row, col);
}
int row;
int col;
};
2. GridStatus: 表示一个格子的状态。
我们看到,我们的格子有四种图案按钮以及一个删除样式(总共五种),这里定义成 enum 类型方便我们使用。
// 一个格子的一种状态
enum GridStatus {
Grid_None = 0,
Grid_Star = 1,
Grid_Heart = 2,
Grid_Sword = 3,
Grid_Shield = 4,
Grid_Delete = 5
};
3. Grid: 表示一个格子。
我们定义了格子的坐标、状态,自然还要定义一个总的格子结构。通过它,我们可以访问到格子的坐标、状态等等信息。
// 一个格子
struct Grid {
Grid() : point(0, 0), status(Grid_None) {}
Grid(int row, int col, GridStatus status = Grid_None) :
point(row, col), st