参考

  1. 《C和C++游戏趣味编程》 童晶

十字消除游戏

用户点击空白方块,沿其上、下、左、右方向寻找一个彩色方块,如果有两个或两个以上颜色一致,就将其消除。在进度条时间结束前消除足够的方块,可以进入下一关

红色方块的表示与绘制

定义Block结构体,利用Block类型的二维数组存储画面中所有小方块的信息。在startup()中将所有方块设置为红色填充、白色线条,在show()中绘制出所有方块:

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define BlockSize 40           // 小方块的边长
#define RowNum 13              // 画面一共RowNum行
#define ColNum 21              // 画面一共ColNum列struct Block
{int x, y;                  // 在画面中的x, y坐标int i, j;                  // 在二维数组中的i, j下标
};// 全局变量
Block blocks[RowNum][ColNum];void startup()
{int i, j;int width = BlockSize * ColNum;int height = BlockSize * RowNum;initgraph(width, height);setbkcolor(RGB(220, 220, 220));setfillcolor(RGB(255, 0, 0));setlinestyle(PS_SOLID, 2);  // 设置线型、线宽cleardevice();              // 以背景颜色清屏BeginBatchDraw();for (i = 0; i < RowNum; i++){for (j = 0; j < ColNum; j++){blocks[i][j].x = j * BlockSize;blocks[i][j].y = i * BlockSize;blocks[i][j].i = i;blocks[i][j].j = j;}}
}void show()
{cleardevice();setlinecolor(RGB(255, 255, 255));int i, j;for (i = 0; i < RowNum; i++){for (j = 0; j < ColNum; j++){fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}}FlushBatchDraw();
}int main()
{startup();while (1){show();}return 0;
}

随机颜色方块的实现

定义colors数组记录所有可能的颜色,其中第0种为灰白色,其他为彩色:

COLORREF colors[ColorTypeNum + 1];

在startup()中对colors数组进行初始化:

colors[0] = RGB(220, 220, 220);
for (i = 1; i < ColorTypeNum + 1; i++)
{colors[i] = HSVtoRGB((i - 1) * 40, 0.6, 0.8);
}

在结构体Block中添加成员变量colorId:

struct Block
{int x, y;                  // 在画面中的x, y坐标int i, j;                  // 在二维数组中的i, j下标int colorId;               // 对应颜色下标
};

在startup()中对blocks初始化,设置其颜色序号为[0, ColorTypeNum]的随机数:

int t = rand() % (ColorTypeNum + 1);
blocks[i][j].colorId = t;

为了让空白比例更高,可以调整一下:

int t = rand() % (int(ColorTypeNum * 1.5));
if (t < ColorTypeNum + 1)
{blocks[i][j].colorId = t;
}
else
{blocks[i][j].colorId = 0;
}

在show()中绘制对应颜色的小方块:

setfillcolor(colors[blocks[i][j].colorId);
fillrectangle(blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);

鼠标点击与十字消除

添加updateWithInput()函数,根据鼠标点击位置(e.x, e.y)计算点中的小方块在二维数组中的行列号(clicked_i, clicked_j)

void updateWithInput()
{ExMessage e;if (peekmessage(&e)){if (e.message == WM_LBUTTONDOWN){int clicked_i = int(e.y) / BlockSize;int clicked_j = int(e.x) / BlockSize;}}
}

先判断被鼠标点击的方块是否为空白方块,如果不是则直接返回:

if (blocks[clicked_i][clicked_j].colorId != 0)
{return;
}

定义数组fourBlocks[4]存储上下左右4个方向找到的第一个不是空白的方块:

Block fourBlocks[4] = { blocks[clicked_i][clicked_j] };  // 初始化为点击的方块

首先向上寻找,找到第一个不是空白的方块,存储到fourBlocks[4]中:

int search;
for (search = 0; clicked_i - search >= 0; search++)      // 向上搜索
{if (blocks[clicked_i - search][clicked_j].colorId != 0){fourBlocks[0] = blocks[clicked_i - search][clicked_j];break;}
}

同理,向下、左、右分别找到第一个不是空白的方块:

for (search = 0; clicked_i + search < RowNum; search++)  // 向下搜索
{if (blocks[clicked_i + search][clicked_j].colorId != 0){fourBlocks[1] = blocks[clicked_i + search][clicked_j];break;}
}for (search = 0; clicked_j - search >= 0; search++)      // 向左搜索
{if (blocks[clicked_i][clicked_j - search].colorId != 0){fourBlocks[2] = blocks[clicked_i][clicked_j - search];break;}
}for (search = 0; clicked_j + search < ColNum; search++)
{if (blocks[clicked_i][clicked_j + search].colorId != 0){fourBlocks[3] = blocks[clicked_i][clicked_j + search];break;}
}

进一步,遍历fourBlocks,统计对应颜色方块的个数。如果某种颜色的方块个数colorStatistics[i] >= 2,则将对应方块的颜色序号设为0:

int colorStatistics[ColorTypeNum + 1] = { 0 };
for (i = 1; i <= ColorTypeNum; i++)
{for (j = 0; j < 4; j++){if (fourBlocks[j].colorId == i){colorStatistics[i]++;}}if (colorStatistics[i] >= 2){for (j = 0; j < 4; j++){if (fourBlocks[j].colorId == i){blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0;}}}
}

方块提示框的绘制

首先定义绘制提示框的函数:

void drawBlockHint(int i, int j, COLORREF color, int isfill)
{setlinecolor(color);setfillcolor(color);if (isfill == 1)           // 画填充方块{fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}if (isfill == 0)           // 画非填充的方块线框{rectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}
}

在updateWithInput()中,如果点击的是空白方块,则执行:

show();                                                  // 先绘制其他方块
drawBlockHint(clicked_i, clicked_j, RGB(100, 100, 100), 1); // 对被点击的空白方块,绘制填充灰色的空白方块

如果十字区域有要消除的彩色方块,则执行:

if (fourBlocks[j].colorId == i)
{drawBlockHint(fourBlocks[j].i, fourBlocks[j].j, RGB(0, 0, 0), 0);  // 要消除的方块绘制提示框blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0;
}

倒计时与进度条

添加全局变量:

float maxTime;                 // 游戏允许的总时长
float remainTime;              // 游戏剩余时长在startup()中,加大窗口高度用于显示倒计时进度条:int height = BlockSize * (RowNum + 2);

在updateWithoutInput()中,定义静态变量start,每次运行时获得当前时刻now,计算程序已运行的时间duration,求出游戏剩余时间:

void updateWithoutInput()
{static clock_t start = clock();                               // 记录第一次运行时刻clock_t now = clock();                                        // 获取当前时刻double duration = double(now - start) / CLOCKS_PER_SEC;       // 程序运行时间remainTime = maxTime - duration;
}

在show()中绘制倒计时进度条:

setlinecolor(RGB(255, 0, 0));                                 // 设置进度条颜色
setfillcolor(RGB(255, 0, 0));
fillrectangle(0, BlockSize * (RowNum + 0.2), remainTime * BlockSize * ColNum / maxTime, BlockSize * (RowNum + 0.8)); // 绘制进度条

得分计算与胜负判断

定义score记录玩家消去的方块个数,noZeroBlockNum记录游戏开始时彩色砖块的总数,设定当score >= 0.9 * noZeroBlockNum时游戏胜利:

int score;
int noZeroBlockNum;            // 彩色方块个数

在startup()中统计彩色砖块的总数:

if (blocks[i][j].colorId != 0)
{noZeroBlockNum++;
}

在updateWithInput()中,更新十字区域消除的方块个数:

score += colorStatistics[i];

在show()中,显示当前得分score:

TCHAR s[80];                                                  // 定义字符数组
setbkmode(TRANSPARENT);
settextcolor(RGB(0, 0, 0));
settextstyle(25, 0, _T("宋体"));
swprintf_s(s, _T("当前%d分,达到%d分游戏胜利"), level, score, int(0.9 * noZeroBlockNum));
outtextxy(BlockSize * (ColNum / 4.5), BlockSize * (RowNum + 1.1), s);

多关卡与增加游戏难度

在startup()中,随着level的增加,当前关的游戏总时长越来越短:

maxTime = 200 - level * 10;

在show()中,显示当前为第几关、已得分数、得到多少分可以进入下一关:

swprintf_s(s, _T("当前第%d关,已得%d分,达到%d分进入下一关"), level, score, int(0.9 * noZeroBlockNum));

在updateWithoutInput()中,如果得分达到要求,则将level加1,重新计时;否则重新开始:

if (score >= int(0.9 * noZeroBlockNum))
{level++;                                                  // 进入下一关start = clock();                                          // 重新开始计时startup();
}
else if (remainTime <= 0)
{start = clock();startup();
}

完整代码

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>
#define BlockSize 40           // 小方块的边长
#define RowNum 13              // 画面一共RowNum行
#define ColNum 21              // 画面一共ColNum列
#define ColorTypeNum 9         // 方块彩色颜色的个数struct Block
{int x, y;                  // 在画面中的x, y坐标int i, j;                  // 在二维数组中的i, j下标int colorId;               // 对应颜色下标
};// 全局变量
Block blocks[RowNum][ColNum];
COLORREF colors[ColorTypeNum + 1];
float maxTime;                 // 游戏允许的总时长
float remainTime;              // 游戏剩余时长
float punishTime;              // 点错扣除的时间
int score;
int noZeroBlockNum;            // 彩色方块个数
int level = 1;                 // 当前关卡序号void drawBlockHint(int i, int j, COLORREF color, int isfill)
{setlinecolor(color);setfillcolor(color);if (isfill == 1)           // 画填充方块{fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}if (isfill == 0)           // 画非填充的方块线框{rectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}
}void startup()
{int i, j;int width = BlockSize * ColNum;int height = BlockSize * (RowNum + 2);initgraph(width, height);setbkcolor(RGB(220, 220, 220));setfillcolor(RGB(255, 0, 0));setlinestyle(PS_SOLID, 2);  // 设置线型、线宽cleardevice();              // 以背景颜色清屏BeginBatchDraw();srand(time(0));maxTime = 300 - level * 10;remainTime = maxTime;punishTime = 0;colors[0] = RGB(220, 220, 220);for (i = 1; i < ColorTypeNum + 1; i++){colors[i] = HSVtoRGB((i - 1) * 40, 0.6, 0.8);}noZeroBlockNum = 0;for (i = 0; i < RowNum; i++){for (j = 0; j < ColNum; j++){int t = rand() % (int(ColorTypeNum * 1.5));if (t < ColorTypeNum + 1){blocks[i][j].colorId = t;}else{blocks[i][j].colorId = 0;}blocks[i][j].x = j * BlockSize;blocks[i][j].y = i * BlockSize;blocks[i][j].i = i;blocks[i][j].j = j;if (blocks[i][j].colorId != 0){noZeroBlockNum++;}}}score = 0;
}void show()
{cleardevice();setlinecolor(RGB(255, 255, 255));int i, j;for (i = 0; i < RowNum; i++){for (j = 0; j < ColNum; j++){setfillcolor(colors[blocks[i][j].colorId]);fillrectangle(blocks[i][j].x, blocks[i][j].y, blocks[i][j].x + BlockSize, blocks[i][j].y + BlockSize);}}setlinecolor(RGB(255, 0, 0));                                 // 设置进度条颜色setfillcolor(RGB(255, 0, 0));fillrectangle(0, BlockSize * (RowNum + 0.2), remainTime * BlockSize * ColNum / maxTime, BlockSize * (RowNum + 0.8)); // 绘制进度条TCHAR s[80];                                                  // 定义字符数组setbkmode(TRANSPARENT);settextcolor(RGB(0, 0, 0));settextstyle(25, 0, _T("宋体"));swprintf_s(s, _T("当前第%d关,已得%d分,达到%d分进入下一关"), level, score, int(0.9 * noZeroBlockNum));outtextxy(BlockSize * (ColNum / 4.5), BlockSize * (RowNum + 1.1), s);FlushBatchDraw();
}void updateWithoutInput()
{static clock_t start = clock();                               // 记录第一次运行时刻clock_t now = clock();                                        // 获取当前时刻double duration = double(now - start) / CLOCKS_PER_SEC;       // 程序运行时间remainTime = maxTime - duration - punishTime;if (score >= int(0.9 * noZeroBlockNum)){level++;                                                  // 进入下一关start = clock();                                          // 重新开始计时startup();}else if (remainTime <= 0){start = clock();startup();}
}void updateWithInput()
{if (remainTime <= 0){return;}int i, j;ExMessage e;if (peekmessage(&e)){if (e.message == WM_LBUTTONDOWN){int clicked_i = int(e.y) / BlockSize;int clicked_j = int(e.x) / BlockSize;if (blocks[clicked_i][clicked_j].colorId != 0){return;}show();                                                  // 先绘制其他方块drawBlockHint(clicked_i, clicked_j, RGB(100, 100, 100), 1); // 对被点击的空白方块,绘制填充灰色的空白方块Block fourBlocks[4] = { blocks[clicked_i][clicked_j] };  // 初始化为点击的方块int search;for (search = 0; clicked_i - search >= 0; search++)      // 向上搜索{if (blocks[clicked_i - search][clicked_j].colorId != 0){fourBlocks[0] = blocks[clicked_i - search][clicked_j];break;}}for (search = 0; clicked_i + search < RowNum; search++)  // 向下搜索{if (blocks[clicked_i + search][clicked_j].colorId != 0){fourBlocks[1] = blocks[clicked_i + search][clicked_j];break;}}for (search = 0; clicked_j - search >= 0; search++)      // 向左搜索 {if (blocks[clicked_i][clicked_j - search].colorId != 0){fourBlocks[2] = blocks[clicked_i][clicked_j - search];break;}}for (search = 0; clicked_j + search < ColNum; search++)  // 向右搜索{if (blocks[clicked_i][clicked_j + search].colorId != 0){fourBlocks[3] = blocks[clicked_i][clicked_j + search];break;}}int colorStatistics[ColorTypeNum + 1] = { 0 };int isBadClick = 1;for (i = 1; i <= ColorTypeNum; i++){for (j = 0; j < 4; j++){if (fourBlocks[j].colorId == i){colorStatistics[i]++;}}if (colorStatistics[i] >= 2){isBadClick = 0;for (j = 0; j < 4; j++){if (fourBlocks[j].colorId == i){drawBlockHint(fourBlocks[j].i, fourBlocks[j].j, RGB(0, 0, 0), 0);blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0;}}score += colorStatistics[i];}}if (isBadClick == 1)     // 如果错误点击{punishTime += 10;}FlushBatchDraw();Sleep(300);}}
}int main()
{startup();while (1){show();updateWithoutInput();updateWithInput();}return 0;
}

C++入门——实现十字消除游戏相关推荐

  1. C语言十字消除游戏(超简单详细),详细思路+源码分享

    十字消除,休闲小游戏,在规定时间内,只要是十字线能连接到的相同颜色的方块,就能获得相应的得分,如果点击后没有能够消除的方块会扣除时间,是一款益智小游戏. 我们将编写十字消除游戏,用户点击空白方块,沿其 ...

  2. H5 六边形消除游戏开发

    试玩地址,目前只适配pc端.源码 六边形游戏的鼻祖应该是这个 hex-frvr,原作者开发用的是 pixi 游戏引擎,本着快速开发的理念,本游戏采用 cocos creator,UI 延用 hex-f ...

  3. H5 六边形消除游戏开发 1

    六边形游戏的鼻祖应该是这个 hex-frvr,原作者开发用的是 pixi 游戏引擎,本着快速开发的理念,本游戏采用 cocos creator,UI 延用 hex-frvr.学习过程中,有借鉴各路实现 ...

  4. 游戏开发入门(九)游戏同步技术

    视频链接:游戏开发入门(九)游戏同步技术(3节课 时常:约1小时07分钟) 第三个视频后9分钟没有声音,不过核心内容都已涉及到 笔记与总结(请先学习视频内容): 1.网络同步的概念与意义 概念:任何一 ...

  5. C#游戏开发快速入门2.2改变游戏对象的状态

    C#游戏开发快速入门2.2改变游戏对象的状态 改变游戏对象的状态,就是要改变游戏对象的位置.朝向和大小.那么,为什么要改变游戏对象的状态呢?当然是因为游戏对象的状态不合适了.在具体说明之前,读者应该先 ...

  6. C#游戏开发快速入门 2.1 构建游戏场景

    C#游戏开发快速入门 2.1  构建游戏场景 如果已经计划好了要编写什么样的游戏,在打开Unity以后,要做的第一件事情就是构建游戏场景(Scene).游戏场景就是玩家游戏时,在游戏视图中看到的一切, ...

  7. 子菜单挤压下方块元素_小心上瘾!全新类型的消除游戏|《土耳其方块》

    谁能想到,一款休闲益智游戏居然超过<刺激战场>.<王者荣耀>,成为苹果免费排行榜第一.那么究竟是一款什么样的免费游戏能够登顶免费排行榜第一呢?今天就让新游组将这款手游推荐给大家 ...

  8. 消除游戏美术设计的这些套路,你都知道吗?

    本篇是设计师Cherry通过积累数年的消除游戏设计经验,对比市面上多款消除游戏进行研究,在交互及色彩搭配两方面进行分析,相信文中满满的专业干货能给大家带来更多新的思路. ■ 消除类产品交互区域对比 图 ...

  9. Egret 之 消除游戏 开发 PART 6 Egret elimination game development PART 6

    Egret 之 消除游戏 开发 PART 6 Egret elimination game development PART 6 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱: ...

  10. I00033 消除游戏

    消除游戏是众多游戏中的一种,貌似十分流行.其内部实现也许是程序员们所感兴趣的. 问题描述:可以输入多组测试用例,每组测试用例首先输入正整数m和n,分别为矩阵的行和列数,m,n≤1000,然后输入m行n ...

最新文章

  1. OpenCascade Primitives BRep-Cylinder
  2. ibatis时间比较大小
  3. 顺时针小球圆周运动Java编程_如何使用CSS实现圆周运动小球的实例
  4. Linux中使用tar打包解包查看的使用方法
  5. 对特殊字符编码js与c#中的处理方法
  6. Android TV框架TIF
  7. jeecgboot框架简介
  8. 2021年山东大学考研数字电路906真题
  9. 技术大众化--10款无需编程的App DIY开发工具
  10. 如何下载东四街道卫星地图高清版大图?
  11. 区块链数字货币应用场景不同决定了价值空间
  12. QT串口助手(串口的查找和打开)
  13. 概率图模型概率模型 及其应用
  14. 2018 美团校招笔试题详解
  15. 有赞 java_响应式架构与 RxJava 在有赞零售的实践
  16. 【知识点】Python 的np.prod函数详解
  17. 数据库原理 概念结构设计-E-R图及其设计
  18. 华为服务器安全系统,服务器安全增强系统
  19. SAP中采购交货时间取值物料主数据或采购协议配置分析测试
  20. typeScript学习(二)

热门文章

  1. typra + picgo + 腾讯云 配合使用编辑微信公众号内容
  2. java cron定时器在线生成规则
  3. 10年老台式机4分钟攻破量子加密算法,此前12年无人破解,核心原理来自25年前...
  4. roberts算子实现
  5. 2021年认证杯SPSSPRO杯数学建模D题(第一阶段)停车的策略全过程文档及程序
  6. python基础教程doc_python基础教程之Word Cloud (词云) - Python|python基础教程|python入门|python教程...
  7. 注册表修改系统分辨率
  8. java网上购物商城文献综述,JSP电子商务网上购物系统的设计(源代码+论文+开题报告+外文翻译+文献综述)...
  9. TOPSIS法 —— python
  10. c语言软件下载与配置