C++游戏开发,超简单的入门项目,50行代码搞定开心消消乐

一提到开发游戏,很多人都会觉得要很高深的技术,有一种望尘莫及的感觉。其实要编一款小游戏也没有想象的那么难,下面跟着小编一起来看看C++是如何一步步制作游戏的。

本文的代码下载地址在文章末尾,有需要的同学自取。

大家应该都玩过连连看,游戏规则不多说了,我们先看看设计思路。

第一件事要根据游戏玩法确定程序的数据结构,不同的数据结构决定了不同的算法设计,用错了数据结构可能直接让代码复杂好几倍。

连连看中玩家操作的数据是一个个的图片,多个图片组成一个棋盘式的矩阵界面。程序根据玩家的点击位置计算两个图片的连接路线,这要求程序以最快、最简单的方式获得矩阵中每个格子的数据。

【源码获取】:

由于平台原因,小编将完整源码放在小编自己的C语言/C++交流④群:836880131!资料共享在群文件里面,有需要的可以自行添加获取~

如果对代码有任何建议,都可以添加小编的学习交流群,欢迎大家来讨论~

用二维数组表示游戏中的矩阵界面比较合适,因为数组可以通过索引快速访问数据,二维数组的两个索引刚好对应矩阵界面的(x, y)坐标。例如:


image

图中矩阵数据在代码中应该这样表示:

data[1][2] = 0;
data[1][3] = 1;
data[2][2] = 2;

可以用不同的数字代表不同的图片,比如:


image

那么上面的矩阵绘制的时候就会是这样:


image

0表示空格,不显示图片。初始化时的空格或消除后的空格,都会被设置为0。

// 定义数组
#define WIDTH 10
#define HEIGHT 8
int data[HEIGHT][WIDTH] = { 0 };

接下来要初始化数据,我打算用8种不一样的图片,每种6张,随机放入矩阵中,矩阵最外一圈是空的。这个算法可以用标准库函数 std::random_shuffle 来完成。

std::random_shuffle 用于把容器内的数据随机打乱,因此按顺序把数据放入数组中,然后调用 std::random_shuffle 就可以完成初始化。

int tmpData[HEIGHT - 2][WIDTH - 2] = { 0 };   // 定义一个8 * 6的临时数组用于存放48个图片数据

int picNum = 1;
int curPicCount = 0;
for (int j = 0; j < 6; ++j)
{
    for (int i = 0; i < 8; ++i)
    {
        // 填入数据
        tmpData[j][i] = picNum;
        curPicCount++;

        if (curPicCount == picCount)
        {
            picNum++; // 图片用完,换下一种图片
            curPicCount = 0;
        }
    }
}

// 随机数据
std::random_shuffle((int*)tmpData, (int*)tmpData + (HEIGHT - 2) * (WIDTH - 2));

// 再填入10*8数组中
for (size_t i = 1; i < WIDTH - 1; i++)
{
    for (size_t j = 1; j < HEIGHT - 1; j++)
    {
        data[j][i] = tmpData[j - 1][i - 1];
    }
}

断点运行观察数组数据,和我们设计的一样:


image

贴上图片看起来还不错:


image

现在来分析游戏玩法。

这个游戏的难点是两个图片连接的判定算法,要求连接线只能转折两次。

我的第一反应这是一个寻路算法,要求找到转折两次以下的最短路径。教科书上常见的广度优先搜索、深度优先搜索、DijKstra算法或是游戏中常用的A星算法,稍作修改加上两次转折的限制都能解决这个问题。

但是如果我用这些比较复杂的算法来教新手,显然是在劝退。所以还是考虑找一找连线判定的算法有没有简单的规律。

多玩几次游戏,把不同种类的连线记录下来,总结后可以发现总共有3种连线类型,分别是不转折连接、转折一次和转折两次。

还是从最简单的情况开始考虑。这是解决难题的通用方法:从最简单的情况开始考虑,再逐步增加复杂的条件。

最简单的不转折连接,有两种情况,横向连线和纵向连线:


image

这两种情况很容易处理,横向、竖向依次检查每个格子是否被阻挡即可。

// 横向是否连接
bool IsHLinked(int x1, int y1, int x2, int y2)
{
    if (y1 != y2)
    {
        // 横向不在一条线
        return false;
    }

    int minX = std::min(x1, x2); // 找到左边的点
    int maxX = std::max(x1, x2); // 找到右边的点

    for (size_t i = minX +1; i < maxX - 1; i++) // 从左到右检查中间的点是不是空的
    {
        if (data[y1][i] != 0)
        {
            return false;
        }
    }

    return true;
}

// 纵向是否连接
bool IsVLinked(int x1, int y1, int x2, int y2)
{
// 代码类似
}

最后把这两个合并就是不转折的情况下:

// 不转折时判断
bool IsZeroTurnLinked(int x1, int y1, int x2, int y2)
{
    if (IsHLinked(x1, y1, x2, y2))
    {
        return true;
    }

    if (IsVLinked(x1, y1, x2, y2))
    {
        return true;
    }

    return false;
}

转折一次:


image

转折一次的算法也是比较明显的,像上图中的两种情况,找到绿色点的位置,如果这个点可以不转折连到两个红色的图片,那么这两个红色的图片就可以通过一次转折连接。

绿点的位置是由两个红点决定的,只有上图中的两种可能。

// 转折一次
bool IsOneTurnLinked(int x1, int y1, int x2, int y2)
{
    int tmpPointX[2] = { x1, x2 };
    int tmpPointY[2] = { y2, y1 };// 找到两个黄色点的坐标

    for (size_t i = 0; i < _countof(tmpPointX); i++)
    {
        if (IsZeroTurnLinked(tmpPointX[i], tmpPointY[i], x1, y1)
            && IsZeroTurnLinked(tmpPointX[i], tmpPointY[i], x2, y2))
        {
            return true;
        }
    }

    return false;
}

转折两次的情况就多了,下图同样是连接红色图片,要绕过绿色图片。


image

转折两次的情况很多,这里无法一一列举,但是仔细思考可以发现和转折一次本质上是一样的,就是找到两个点,这两个点可以分别和红色图片无转折连接,并且这两个点也可以无转折连接。

这两个点需要位于经过红色图片的十字线上,并且只要确定一个了其中一个点,就能对应地找到另一个点:


image

因此只要遍历其中一个图片的两条十字线经过的所有的点,并计算出另一个图片十字线上对应点的位置,检查这两个点和两个红色图片是否可以无转折连接:

bool IsTwoTurnLinked(int x1, int y1, int x2, int y2)
{
    // 顺着图1的延长线纵向遍历所有点
    for (size_t j = 0; j < HEIGHT; j++)
    {
        int tmpX1 = x1;
        int tmpY1 = j;

        if (j == y1)
        {
            continue; // 与图1重合
        }

        if (tmpX1 == x2 && tmpY1 == y2)
        {
            continue; // 与图2重合
        }

        int tmpX2 = x2;
        int tmpY2 = tmpY1; // 另一个点的坐标

        if (IsZeroTurnLinked(tmpX1, tmpY1, tmpX2, tmpY2)
            && IsZeroTurnLinked(tmpX1, tmpY1, x1, y1)
            && IsZeroTurnLinked(tmpX1, tmpY1, x2, y2))
        {
            return true;
        }
    }

    // 顺着图1的延长线横向遍历所有点
    // ... 省略

    return false;
}

代码码完了,添上图片和鼠标检测的代码跑一跑试试。


image

右边显示临时显示字符用于测试连通性,多次测试没有问题。

最后加上连线,并清除被点击的两个格子,就完成了连连看的核心逻辑:


image

文明看帖,点赞+关注+收藏一波走起~

代码获取方式

由于平台不能放文件小编将源码放在C语言/C++学习交流群:836880131!群里还整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269