Easyx 图形库

# 游戏简介

2048 这款游戏相信大家都听说过，编写代码分为以下几个步骤：

----------- 1. 初始化棋盘

----------- 2. 绘制棋盘

----------- 3. 用户操作

# 编写游戏

## 预编译代码

``````#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或4
int 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;
}
}``````

## 第四步：封装函数

``````int main()
{
start:
// 初始化窗口
initgraph(WIN_SIZE, WIN_SIZE + 30);
Init();
while (true)
{
DrawScreen();
GetKey();
}
return 0;
}``````

# 完整代码

``````/*****************************
* 项目名称：2048小游戏
* 作者：轩
* 完成时间：2022.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或4
int 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;
}``````

THE END