目录
目录
目录
写在前面
游戏简介
Easyx 图形库
编写游戏
预编译代码
第一步:初始化棋盘
第二步:绘制棋盘
第三步:用户操作
第四步:封装函数
完整代码
效果展示
写在前面
大家好!本人是一个12岁六年级小学生,今年9月开始学习C++,曾经学过1年Python。
这是我的第一篇博客,决定分享一个游戏给大家!请多指教!
游戏简介
2048这款游戏相信大家都听说过,编写代码分为以下几个步骤:
----------- 1.初始化棋盘
----------- 2. 绘制棋盘
----------- 3. 用户操作
Easyx 图形库
官网网址:
官网上有详细的教程,而且可以自动匹配 vs 版本,我不说了。
顺便说一下,我用的是 vs。
编写游戏
预编译代码
#include <stdio.h>#include <graphics.h>#include <conio.h>#define MAX_SIZE 4 // 格子数量#define GRID_WIDTH 100 // 格子宽度#define INTERVAL 15 // 格子距离#define WIN_SIZE MAX_SIZE * GRID_WIDTH + 5 * INTERVAL // 窗口宽度
第一步:初始化棋盘
首先,我们要定义一个二维数组,来表示棋盘。
int canvas[MAX_SIZE][MAX_SIZE];
接下来,要在其中随机生成数字。
// 生成2或4int Rand_2_4(){if (rand() % 10 == 0) return 4;return 2;}// 随机生成数字void CreateNum(){while (true){int x = rand() % MAX_SIZE;int y = rand() % MAX_SIZE;if (canvas[x][y] == 0){canvas[x][y] = Rand_2_4();break;}}}
第二步:绘制棋盘
我们要遍历二维数组,在每一个位置绘制圆角矩形,并绘制数字、分数。
在此之前我们要先定义颜色,我用枚举类型来储存颜色,以及数组来储存位置。
// 枚举颜色enum Color{zero = RGB(205, 193, 180),twoto1 = RGB(238, 228, 218),twoto2 = RGB(237, 224, 200),twoto3 = RGB(242, 177, 121),twoto4 = RGB(245, 140, 99),twoto5 = RGB(246, 124, 95),twoto6 = RGB(246, 94, 59),twoto7 = RGB(242, 177, 121),twoto8 = RGB(237, 204, 97),twoto9 = RGB(255, 0, 128),twoto10 = RGB(145, 0, 72),twoto11 = RGB(242, 17, 158),bk = RGB(187, 173, 160),};Color arr[] = { zero, twoto1, twoto2, twoto3, twoto4, twoto5, twoto6, twoto7, twoto8, twoto9, twoto10, twoto11, bk };int num[] = {0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};POINT pos[MAX_SIZE][MAX_SIZE];int score = 0;
然后就是绘图。
// 绘制屏幕void DrawScreen(){// 背景颜色setbkcolor(Color::bk);cleardevice();for (int i = 0; i < MAX_SIZE; i++){for (int j = 0; j < MAX_SIZE; j++){for (int k = 0; k < 12; k++){if (canvas[i][j] == num[k]){DWORD nowc = arr[k];setfillcolor(nowc);solidroundrect(pos[i][j].x, pos[i][j].y, pos[i][j].x + GRID_WIDTH, pos[i][j].y + GRID_WIDTH, 5, 5);if (num[k] != 0) // 显示数字{char number[5];sprintf_s(number, "%d", num[k]);setbkmode(TRANSPARENT);if (num[k] <= 4) settextcolor(RGB(119, 110, 101));else settextcolor(WHITE);settextstyle(50, 0, "黑体");int temp = (GRID_WIDTH - textwidth(number)) / 2;outtextxy(pos[i][j].x + temp, pos[i][j].y + 25, number);}}}}}settextcolor(WHITE);settextstyle(30, 0, "黑体");char text[20];sprintf_s(text, "Score: %d", score);outtextxy(INTERVAL, WIN_SIZE - 10, text);}
效果预览:
然后是重头戏——用户操作。
第三步:用户操作
算法比较复杂(至少我真么觉得):
// 移动格子// 向上移动void MoveUp(){for (int i = 0; i < MAX_SIZE; i++) // 枚举列{int temp = 0; // 此列最上面for (int j = 1; j < MAX_SIZE; j++) // 枚举行{if (canvas[j][i] != 0) // 这个格子有数字{if (canvas[temp][i] == 0) // 最上面空着 -> 上去{canvas[temp][i] = canvas[j][i];canvas[j][i] = 0;}else if (canvas[temp][i] == canvas[j][i]) // 上面是同样数字 -> 合并{canvas[temp][i] += canvas[j][i];score += canvas[j][i];canvas[j][i] = 0;temp++;}else{canvas[temp + 1][i] = canvas[j][i]; // 上到前一个格子if (temp + 1 != j){canvas[j][i] = 0;}temp++;}}}}}// 向下移动void MoveDown(){for (int i = 0; i < MAX_SIZE; i++) // 枚举列{int temp = MAX_SIZE - 1; // 此列最下面for (int j = MAX_SIZE - 2; j >= 0; j--) // 枚举行{if (canvas[j][i] != 0) // 这个格子有数字{if (canvas[temp][i] == 0) // 最下面空着 -> 下去{canvas[temp][i] = canvas[j][i];canvas[j][i] = 0;}else if (canvas[temp][i] == canvas[j][i]) // 下面是同样数字 -> 合并{canvas[temp][i] += canvas[j][i];score += canvas[j][i];canvas[j][i] = 0;temp--;}else{canvas[temp - 1][i] = canvas[j][i]; // 下到前一个格子if (temp - 1 != j){canvas[j][i] = 0;}temp--;}}}}}// 向右移动void MoveRight(){for (int i = 0; i < MAX_SIZE; i++) // 枚举行{int temp = MAX_SIZE - 1; // 此行最右面for (int j = MAX_SIZE - 2; j >= 0; j--) // 枚举列{if (canvas[i][j] != 0) // 这个格子有数字{if (canvas[i][temp] == 0) // 最右面空着 -> 右去{canvas[i][temp] = canvas[i][j];canvas[i][j] = 0;}else if (canvas[i][temp] == canvas[i][j]) // 右面是同样数字 -> 合并{canvas[i][temp] += canvas[i][j];score += canvas[i][j];canvas[i][j] = 0;temp--;}else{canvas[i][temp - 1] = canvas[i][j]; // 到前一个格子if (temp - 1 != j){canvas[i][j] = 0;}temp--;}}}}}// 向左移动void MoveLeft(){for (int i = 0; i < MAX_SIZE; i++) // 枚举行{int temp = 0; // 此行最左面for (int j = 1; j < MAX_SIZE; j++) // 枚举列{if (canvas[i][j] != 0) // 这个格子有数字{if (canvas[i][temp] == 0) // 最左面空着 -> 左去{canvas[i][temp] = canvas[i][j];canvas[i][j] = 0;}else if (canvas[i][temp] == canvas[i][j]) // 左面是同样数字 -> 合并{canvas[i][temp] += canvas[i][j];score += canvas[i][j];canvas[i][j] = 0;temp++;}else{canvas[i][temp + 1] = canvas[i][j]; // 到前一个格子if (temp + 1 != j){canvas[i][j] = 0;}temp++;}}}}}// 用户键盘输入void GetKey(){char input = _getch();switch (input){case 72:case 'w':case 'W':MoveUp();CreateNum();break;case 80:case 's':case 'S':MoveDown();CreateNum();break;case 75:case 'a':case 'A':MoveLeft();CreateNum();break;case 77:case 'd':case 'D':MoveRight();CreateNum();break;case 'r':case 'R':Init();break;}}
第四步:封装函数
就是把它们都放到 main 函数里去……
int main(){start:// 初始化窗口initgraph(WIN_SIZE, WIN_SIZE + 30);Init();while (true){DrawScreen();GetKey();}return 0;}
完整代码
/****************************** 项目名称:2048小游戏* 作者:轩* 完成时间:.12.28* 用时:2.5 小时*****************************/#include <stdio.h>#include <graphics.h>#include <conio.h>#define MAX_SIZE 4 // 格子数量#define GRID_WIDTH 100 // 格子宽度#define INTERVAL 15 // 格子距离#define WIN_SIZE MAX_SIZE * GRID_WIDTH + 5 * INTERVAL // 窗口宽度// 枚举颜色enum Color{zero = RGB(205, 193, 180),twoto1 = RGB(238, 228, 218),twoto2 = RGB(237, 224, 200),twoto3 = RGB(242, 177, 121),twoto4 = RGB(245, 140, 99),twoto5 = RGB(246, 124, 95),twoto6 = RGB(246, 94, 59),twoto7 = RGB(242, 177, 121),twoto8 = RGB(237, 204, 97),twoto9 = RGB(255, 0, 128),twoto10 = RGB(145, 0, 72),twoto11 = RGB(242, 17, 158),bk = RGB(187, 173, 160),};Color arr[] = { zero, twoto1, twoto2, twoto3, twoto4, twoto5, twoto6, twoto7, twoto8, twoto9, twoto10, twoto11, bk };int num[] = {0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};int canvas[MAX_SIZE][MAX_SIZE];POINT pos[MAX_SIZE][MAX_SIZE];int score = 0;// 生成2或4int Rand_2_4(){if (rand() % 10 == 0) return 4;return 2;}// 随机生成数字void CreateNum(){while (true){int x = rand() % MAX_SIZE;int y = rand() % MAX_SIZE;if (canvas[x][y] == 0){canvas[x][y] = Rand_2_4();break;}}}// 初始化格子位置 void Init(){score = 0;srand(GetTickCount());for (int i = 0; i < MAX_SIZE; i++){for (int j = 0; j < MAX_SIZE; j++){canvas[i][j] = 0;}}CreateNum();CreateNum();// 每个格子坐标for (int i = 0; i < MAX_SIZE; i++){for (int j = 0; j < MAX_SIZE; j++) {pos[i][j].x = j * GRID_WIDTH + (j + 1) * INTERVAL;pos[i][j].y = i * GRID_WIDTH + (i + 1) * INTERVAL;}}}// 绘制屏幕void DrawScreen(){// 背景颜色setbkcolor(Color::bk);cleardevice();for (int i = 0; i < MAX_SIZE; i++){for (int j = 0; j < MAX_SIZE; j++){for (int k = 0; k < 12; k++){if (canvas[i][j] == num[k]){DWORD nowc = arr[k];setfillcolor(nowc);solidroundrect(pos[i][j].x, pos[i][j].y, pos[i][j].x + GRID_WIDTH, pos[i][j].y + GRID_WIDTH, 5, 5);if (num[k] != 0) // 显示数字{char number[5];sprintf_s(number, "%d", num[k]);setbkmode(TRANSPARENT);if (num[k] <= 4) settextcolor(RGB(119, 110, 101));else settextcolor(WHITE);settextstyle(50, 0, "黑体");int temp = (GRID_WIDTH - textwidth(number)) / 2;outtextxy(pos[i][j].x + temp, pos[i][j].y + 25, number);}}}}}settextcolor(WHITE);settextstyle(30, 0, "黑体");char text[20];sprintf_s(text, "Score: %d", score);outtextxy(INTERVAL, WIN_SIZE - 10, text);}// 移动格子// 向上移动void MoveUp(){for (int i = 0; i < MAX_SIZE; i++) // 枚举列{int temp = 0; // 此列最上面for (int j = 1; j < MAX_SIZE; j++) // 枚举行{if (canvas[j][i] != 0) // 这个格子有数字{if (canvas[temp][i] == 0) // 最上面空着 -> 上去{canvas[temp][i] = canvas[j][i];canvas[j][i] = 0;}else if (canvas[temp][i] == canvas[j][i]) // 上面是同样数字 -> 合并{canvas[temp][i] += canvas[j][i];score += canvas[j][i];canvas[j][i] = 0;temp++;}else{canvas[temp + 1][i] = canvas[j][i]; // 上到前一个格子if (temp + 1 != j){canvas[j][i] = 0;}temp++;}}}}}// 向下移动void MoveDown(){for (int i = 0; i < MAX_SIZE; i++) // 枚举列{int temp = MAX_SIZE - 1; // 此列最下面for (int j = MAX_SIZE - 2; j >= 0; j--) // 枚举行{if (canvas[j][i] != 0) // 这个格子有数字{if (canvas[temp][i] == 0) // 最下面空着 -> 下去{canvas[temp][i] = canvas[j][i];canvas[j][i] = 0;}else if (canvas[temp][i] == canvas[j][i]) // 下面是同样数字 -> 合并{canvas[temp][i] += canvas[j][i];score += canvas[j][i];canvas[j][i] = 0;temp--;}else{canvas[temp - 1][i] = canvas[j][i]; // 下到前一个格子if (temp - 1 != j){canvas[j][i] = 0;}temp--;}}}}}// 向右移动void MoveRight(){for (int i = 0; i < MAX_SIZE; i++) // 枚举行{int temp = MAX_SIZE - 1; // 此行最右面for (int j = MAX_SIZE - 2; j >= 0; j--) // 枚举列{if (canvas[i][j] != 0) // 这个格子有数字{if (canvas[i][temp] == 0) // 最右面空着 -> 右去{canvas[i][temp] = canvas[i][j];canvas[i][j] = 0;}else if (canvas[i][temp] == canvas[i][j]) // 右面是同样数字 -> 合并{canvas[i][temp] += canvas[i][j];score += canvas[i][j];canvas[i][j] = 0;temp--;}else{canvas[i][temp - 1] = canvas[i][j]; // 到前一个格子if (temp - 1 != j){canvas[i][j] = 0;}temp--;}}}}}// 向左移动void MoveLeft(){for (int i = 0; i < MAX_SIZE; i++) // 枚举行{int temp = 0; // 此行最左面for (int j = 1; j < MAX_SIZE; j++) // 枚举列{if (canvas[i][j] != 0) // 这个格子有数字{if (canvas[i][temp] == 0) // 最左面空着 -> 左去{canvas[i][temp] = canvas[i][j];canvas[i][j] = 0;}else if (canvas[i][temp] == canvas[i][j]) // 左面是同样数字 -> 合并{canvas[i][temp] += canvas[i][j];score += canvas[i][j];canvas[i][j] = 0;temp++;}else{canvas[i][temp + 1] = canvas[i][j]; // 到前一个格子if (temp + 1 != j){canvas[i][j] = 0;}temp++;}}}}}// 用户键盘输入void GetKey(){char input = _getch();switch (input){case 72:case 'w':case 'W':MoveUp();CreateNum();break;case 80:case 's':case 'S':MoveDown();CreateNum();break;case 75:case 'a':case 'A':MoveLeft();CreateNum();break;case 77:case 'd':case 'D':MoveRight();CreateNum();break;case 'r':case 'R':Init();break;}}int main(){start:// 初始化窗口initgraph(WIN_SIZE, WIN_SIZE + 30);Init();while (true){DrawScreen();GetKey();}return 0;}
效果展示
学业繁忙,精力有限,多多见谅!
如果觉得《【C/C++小游戏】2048 大作战!(基于Easyx图形窗口实现)》对你有帮助,请点赞、收藏,并留下你的观点哦!