消消乐游戏实现
1 前置知识
1.1 开发环境的准备
本次开发是一个消消乐的小游戏,使用的开发环境是Visual Studio 2022,且环境要安装easyx图形库。一般easyx图形库在编译器中未安装,因此需要下载该库函数然后进行手动放在C语言的库函数中。如果自己的VS 2022不能直接使用,可以按照一下方式进行安装,具体操作如下,首先下载好easyx库(是一个.exe的文件),右键将其解压,解压之后如图1.1所示,然后库函数中的头文件和lib文件导入到VS2022路径下相应include文件夹和lib文件夹中。如图1.2。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/d91bdf66febe4fd99b0d2cc78ab783fe.png#pic_center)
图1.1 解压easyx.exe后的文件目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6ccc7a91ba294057b7f35a7e308aacfa.png)
图1.2 复制路径
至此开发环境已经配置完成!
2 开发实现
2.1游戏的全局变量以及头文件的导入
#include
#include // easyx图形库的头文件
#include
#include
#include
#pragma comment(lib,"winmm.lib")
#define WIN_WIDHT 485
#define WIN_HEIGHT 917
#define ROWS 8
#define COLS 8
#define BLOCK_TYPE_COUNT 7
IMAGE imgBg;//表示背景图片
IMAGE imgBloccks[BLOCK_TYPE_COUNT];//图片数组
bool isMoving;
bool isSwap;
//定义一个结构体类型,表示方块
struct block {
int type;//表示方块类型,0:表示空白
int x, y;//坐标
int row, col;//行,列
int match;//标志是否满足消除的条件
};
//多两行两列易于判断边界
struct block map[ROWS+2][COLS+2];
//边界值
const int off_x = 17;
const int off_y = 274;
const int block_size = 52;
int click;//单击次数,当单击次数是两次的时候就会根据一定条件交换
int posX1, posY1;
int posX2, posY2;
2.2游戏的窗口初始化
void init() {
// 创建游戏窗口
initgraph(WIN_WIDHT,WIN_HEIGHT);
//背景图片
loadimage(&imgBg, "./res/bg.png");
//随机种子
srand(time(NULL));
// 初始化数组
for (int i = 1; i
map[i][j].type = 1 + rand()%7;
map[i][j].row = i;
map[i][j].col = j;
map[i][j].x = off_x + (j - 1) * (block_size + 5);
map[i][j].y = off_y + (i - 1) * (block_size + 5);
map[i][j].match = 0;
}
}
//初始化图片
char name[64];
for (int i = 0; i
BeginBatchDraw();
putimage(0,0,&imgBg);
for (int i = 1; i
if (map[i][j].type) {
IMAGE* img = &imgBloccks[map[i][j].type - 1];
putimage(map[i][j].x,map[i][j].y, img);
}
}
}
EndBatchDraw();
}
2.4添加游戏背景音乐
// 添加音乐
void music() {
mciSendString("play res/music.mp3 repeat", 0, 0, 0);
}
2.5实现交换两个方块的功能
void exchange(int x1, int y1, int x2, int y2) {
//将数组中的两个数据进行交换,交换完之后数组中图片渲染的地方仍不改变的
struct block temp = map[x1][y1];
map[x1][y1] = map[x2][y2];
map[x2][y2] = temp;
//将两个数据块中的坐标交换一下
map[x1][y1].row = x1;
map[x1][y1].col = y1;
map[x2][y2].row = x2;
map[x2][y2].col = y2;
}
2.6实现选中两个方块函数
//点击选项
void userClick() {
ExMessage msg;
if (peekmessage(&msg) && msg.message == WM_LBUTTONDOWN) {
//判断边界
if (msg.x ROWS) return;
printf("%d ,%d\n", row, col);
click++;
if (click == 1) {
posX1 = row;
posY1 = col;
}
else if (click == 2) {
posX2 = row;
posY2 = col;
if (abs(posX1 - posX2) + abs(posY1 - posY2) == 1) {
click = 0;
isSwap = true;
exchange(posX1,posY1,posX2,posY2);
}
}
else {
click = 1;
posX1 = posX2;
posY1 = posY2;
}
}
}
2.7确认选中交换执行两个方块移动
void move() {
isMoving = false;
//实现两个数据块的渲染位置
for (int i = 1; i
struct block* temp = &map[i][j];
// 通过行和列计算出渲染的位置;
//int col = (msg.x - off_x) / (block_size + 5) + 1;
//int row = (msg.y - off_y) / (block_size + 5) + 1;
int x = (temp->col - 1) * (block_size + 5) + off_x;
int y = (temp->row - 1) * (block_size + 5) + off_y;
//然后计算每个模块是否需要移动
int dx = temp->x - x;
int dy = temp->y - y;
if (dx) temp->x -= dx/abs(dx);
if (dy) temp->y -= dy/abs(dy);
if (dx || dy) isMoving = true;
}
}
}
2.8检查是否满足消除的条件
// 检查是否发生消除的条件
void check() {
for (int i = 1; i
//判断当前的块的行是否都相同
if (map[i - 1][j].type == map[i][j].type && map[i][j].type == map[i + 1][j].type) {
for (int k = -1; k
if (isSwap && !isMoving) {
//即当前点击满足条件(点击两次,且两次都是相邻点击),同时交换已经结束了。
int count = 0;
for (int i = 1; i
count += (map[i][j].match);
}
}
if (count==0) {
exchange(posX1,posY1,posX2,posY2);
//click = 0;
}
isSwap = false;
}
}
2.9消除之后填充方块
// 消除之后从顶部下落方块填充消失的方块
void downmap() {
for (int i = ROWS; i >= 1; i--) {
for (int j = 1; j
for (int k = i - 1; k >= 1; k--) {
if (map[k][j].match==0) {
exchange(k, j, i, j);
break;
}
}
}
}
}
for (int i = ROWS; i >= 1; i--) {
int n = 0;
for (int j = 1; j
map[i][j].type = 1 + rand() % 7;
map[i][j].y = off_y - ((n + 1) * (block_size + 5));
n++;
map[i][j].match = 0;
}
}
}
}
2.10主函数调用
int main() {
init();
updateWindow();
while (1) {
music();
//clear();
userClick();//处理点击操作
move();//
check();
//addother();
huanYuan();
if (!isMoving) downmap();
//如果不能消除就把他还原
updateWindow();//这个是处理消除
Sleep(10);//事关系优化的
}
system("pause");
return 0;
}
3 实现效果以及打包程序
3.1实现效果
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/91001200bb2a4625adf82000e818eebf.png#pic_center)
图3.1 游戏界面
3.2打包程序
安装VS 2022打包工具,可能在安装的时候速度有点慢,可以下载好之后再安装! ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/40af674bed2848cc91244be040ef54b6.png#pic_center)
图3.2 安装打包工具
然后右键解决方案
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/d4d8e94b57a449ed81a21366de303bd2.png#pic_center)
图3.3 选择解决方案
依次点击添加再点击新建项目 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a00383a762f044518d042fba4a8ebecd.png#pic_center)
图3.4 选择模块中的新建项目
选择setup project然后点击下一步 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0932d38ad4c643efa02c739405bc91ab.png#pic_center)
图3.5 选择打包工具
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/e83d61ebe50d42a88f3f7957804bf3ff.png#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/68945b2c05554aa8add5202b92a9daee.png#pic_center)
图3.6 设置打包的项目路径和名称
然后添加程序中需要的资源,比如程序中的图片和音乐。注意路径和你程序中的路径相同,例如你项目中的资源存放在src文件夹下,此时你应该在application Folder中也创建一个src文件夹把资源放进去。如果你担心打包的程序在其他pc中不能用也可以把程序的dll放进去。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c0baa535159d4a16927cdc899fccca3a.png#pic_center)
图3.7 设置项目资源
设置项目输出,所谓的项目输出就是为了该程序在在安装的过程中输出的一些文件我们可以选择主输出。然后创建一个桌面图标 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a0db3ad160014d7092556260c6d2ca4b.png#pic_center)
图3.8 设置主输出
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/4419fe11551f4197b7c9f63367d02799.png#pic_center)
图3.9 创建图标
生成图标之后剪切到user’s Desktop中,然后在添加图标的图片,注意图标图片的资源也应该存放在application Folder中。点击图标右键设置图片的路径。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ff1ff0a0b692469daebaacf8c03a829d.png#pic_center)
图3.10 剪切到桌面中
图标右键之后,就可以看到这个界面,然后选择图标的在application Folder中的位置。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/463633dce8554c79a467ad77c315637c.png#pic_center)
图3.11 设置图标图片
然后右点击项目名yes,重新生成就可以在项目路径中找到exe文件。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b5cd97b5f82e482299c8e81cb1c5f527.png#pic_center)
图3.12 重新生成
4 总结
总结不好多多包涵,如有不足欢迎指正!
|