C++入门——实现十字消除游戏
参考
- 《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++入门——实现十字消除游戏相关推荐
- C语言十字消除游戏(超简单详细),详细思路+源码分享
十字消除,休闲小游戏,在规定时间内,只要是十字线能连接到的相同颜色的方块,就能获得相应的得分,如果点击后没有能够消除的方块会扣除时间,是一款益智小游戏. 我们将编写十字消除游戏,用户点击空白方块,沿其 ...
- H5 六边形消除游戏开发
试玩地址,目前只适配pc端.源码 六边形游戏的鼻祖应该是这个 hex-frvr,原作者开发用的是 pixi 游戏引擎,本着快速开发的理念,本游戏采用 cocos creator,UI 延用 hex-f ...
- H5 六边形消除游戏开发 1
六边形游戏的鼻祖应该是这个 hex-frvr,原作者开发用的是 pixi 游戏引擎,本着快速开发的理念,本游戏采用 cocos creator,UI 延用 hex-frvr.学习过程中,有借鉴各路实现 ...
- 游戏开发入门(九)游戏同步技术
视频链接:游戏开发入门(九)游戏同步技术(3节课 时常:约1小时07分钟) 第三个视频后9分钟没有声音,不过核心内容都已涉及到 笔记与总结(请先学习视频内容): 1.网络同步的概念与意义 概念:任何一 ...
- C#游戏开发快速入门2.2改变游戏对象的状态
C#游戏开发快速入门2.2改变游戏对象的状态 改变游戏对象的状态,就是要改变游戏对象的位置.朝向和大小.那么,为什么要改变游戏对象的状态呢?当然是因为游戏对象的状态不合适了.在具体说明之前,读者应该先 ...
- C#游戏开发快速入门 2.1 构建游戏场景
C#游戏开发快速入门 2.1 构建游戏场景 如果已经计划好了要编写什么样的游戏,在打开Unity以后,要做的第一件事情就是构建游戏场景(Scene).游戏场景就是玩家游戏时,在游戏视图中看到的一切, ...
- 子菜单挤压下方块元素_小心上瘾!全新类型的消除游戏|《土耳其方块》
谁能想到,一款休闲益智游戏居然超过<刺激战场>.<王者荣耀>,成为苹果免费排行榜第一.那么究竟是一款什么样的免费游戏能够登顶免费排行榜第一呢?今天就让新游组将这款手游推荐给大家 ...
- 消除游戏美术设计的这些套路,你都知道吗?
本篇是设计师Cherry通过积累数年的消除游戏设计经验,对比市面上多款消除游戏进行研究,在交互及色彩搭配两方面进行分析,相信文中满满的专业干货能给大家带来更多新的思路. ■ 消除类产品交互区域对比 图 ...
- Egret 之 消除游戏 开发 PART 6 Egret elimination game development PART 6
Egret 之 消除游戏 开发 PART 6 Egret elimination game development PART 6 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱: ...
- I00033 消除游戏
消除游戏是众多游戏中的一种,貌似十分流行.其内部实现也许是程序员们所感兴趣的. 问题描述:可以输入多组测试用例,每组测试用例首先输入正整数m和n,分别为矩阵的行和列数,m,n≤1000,然后输入m行n ...
最新文章
- OpenCascade Primitives BRep-Cylinder
- ibatis时间比较大小
- 顺时针小球圆周运动Java编程_如何使用CSS实现圆周运动小球的实例
- Linux中使用tar打包解包查看的使用方法
- 对特殊字符编码js与c#中的处理方法
- Android TV框架TIF
- jeecgboot框架简介
- 2021年山东大学考研数字电路906真题
- 技术大众化--10款无需编程的App DIY开发工具
- 如何下载东四街道卫星地图高清版大图?
- 区块链数字货币应用场景不同决定了价值空间
- QT串口助手(串口的查找和打开)
- 概率图模型概率模型 及其应用
- 2018 美团校招笔试题详解
- 有赞 java_响应式架构与 RxJava 在有赞零售的实践
- 【知识点】Python 的np.prod函数详解
- 数据库原理 概念结构设计-E-R图及其设计
- 华为服务器安全系统,服务器安全增强系统
- SAP中采购交货时间取值物料主数据或采购协议配置分析测试
- typeScript学习(二)
热门文章
- typra + picgo + 腾讯云 配合使用编辑微信公众号内容
- java cron定时器在线生成规则
- 10年老台式机4分钟攻破量子加密算法,此前12年无人破解,核心原理来自25年前...
- roberts算子实现
- 2021年认证杯SPSSPRO杯数学建模D题(第一阶段)停车的策略全过程文档及程序
- python基础教程doc_python基础教程之Word Cloud (词云) - Python|python基础教程|python入门|python教程...
- 注册表修改系统分辨率
- java网上购物商城文献综述,JSP电子商务网上购物系统的设计(源代码+论文+开题报告+外文翻译+文献综述)...
- TOPSIS法 —— python
- c语言软件下载与配置