【附C++源码】从零开始实现 2048 游戏
项目概述
2048 是一款经典的数字合并游戏,通过滑动方块使相同数字合并,目标是合成 2048。本文将详细介绍基于 EGE(Easy Graphics Engine)图形库实现的图形化版本。

核心技术架构
1. 游戏数据结构设计
cpp
const int GRID_SIZE = 100; // 网格尺寸
const int GRID_COUNT = 4; // 4x4 网格
const int WIN_SIZE = GRID_SIZE * GRID_COUNT;
const int MARGIN = 10; // 单元格间距
const int CELL_SIZE = GRID_SIZE - MARGIN * 2;
int board[4][4] = {0}; // 游戏棋盘
int score = 0; // 当前分数
bool gameOver = false; // 游戏结束标志
bool gameWin = false; // 胜利标志
设计要点:
- 使用二维数组
board[4][4]存储棋盘状态,0 表示空位 - 通过全局变量管理游戏状态,便于各函数访问
2. 视觉渲染系统
颜色映射机制
cpp
color_t getNumberColor(int num) {
switch(num) {
case 0: return EGERGB(205, 193, 180); // 空位灰
case 2: return EGERGB(238, 228, 218); // 浅黄
case 4: return EGERGB(237, 224, 200); // 米色
case 8: return EGERGB(242, 177, 121); // 橙色
// ... 更多颜色映射
default: return EGERGB(60, 58, 50); // 深色背景
}
}
技术细节 :采用经典 2048 配色方案,通过 EGE 的 EGERGB 宏实现 RGB 颜色值转换。
棋盘绘制流程
cpp
void drawGame() {
// 1. 清空画布并设置背景色
setbkcolor(EGERGB(187, 173, 160));
cleardevice();
// 2. 绘制每个单元格
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int x = j * GRID_SIZE + MARGIN;
int y = i * GRID_SIZE + MARGIN;
int num = board[i][j];
// 绘制单元格背景
setfillcolor(getNumberColor(num));
bar(x, y, x + CELL_SIZE, y + CELL_SIZE);
// 绘制数字(非空时)
if (num != 0) {
// 根据数字大小动态调整字体
if (num < 100) setfont(40, 0, "宋体");
else if (num < 1000) setfont(36, 0, "宋体");
else setfont(32, 0, "宋体");
// 居中绘制
outtextxy(x + (CELL_SIZE - textwidth(str)) / 2,
y + (CELL_SIZE - textheight(str)) / 2, str);
}
}
}
// 3. 绘制分数和状态信息
// ...
}
关键技术:
- 使用
bar()函数绘制填充矩形作为单元格 - 通过
textwidth()和textheight()实现文本居中 - 根据数字位数动态调整字体大小,保证显示美观
3. 核心游戏逻辑
方块移动算法
cpp
void mergeAndMoveLeft(int arr[4]) {
// 阶段1: 压缩------将非零数字移到左侧
int temp[4] = {0};
int idx = 0;
for (int i = 0; i < 4; i++) {
if (arr[i] != 0) {
temp[idx++] = arr[i];
}
}
// 阶段2: 合并------相邻相同数字合并
for (int i = 0; i < 3; i++) {
if (temp[i] != 0 && temp[i] == temp[i + 1]) {
temp[i] *= 2;
score += temp[i];
if (temp[i] == 2048) gameWin = true;
// 移除被合并的数字
for (int j = i + 1; j < 3; j++) {
temp[j] = temp[j + 1];
}
temp[3] = 0;
}
}
// 阶段3: 回写------将结果写回原数组
for (int i = 0; i < 4; i++) {
arr[i] = temp[i];
}
}
算法思路:采用"压缩-合并-回写"三阶段处理,确保逻辑清晰。
方向转换策略
cpp
void reverseRow(int arr[4]) {
// 反转数组,用于右移操作
int temp[4];
for (int i = 0; i < 4; i++) temp[i] = arr[3 - i];
for (int i = 0; i < 4; i++) arr[i] = temp[i];
}
void transpose() {
// 矩阵转置,用于上下移动
int temp[4][4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
temp[i][j] = board[j][i];
// 回写
}
设计模式:通过矩阵变换(反转、转置)将四个方向的移动统一为左移操作,显著减少代码重复。
游戏状态检测
cpp
bool checkGameOver() {
// 检查是否有空格
if (countEmpty() > 0) return false;
// 检查水平方向是否可合并
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == board[i][j + 1])
return false;
}
}
// 检查垂直方向是否可合并
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 3; i++) {
if (board[i][j] == board[i + 1][j])
return false;
}
}
return true;
}
4. 输入处理系统
cpp
int main() {
initgraph(WIN_SIZE, WIN_SIZE + 60); // 初始化图形窗口
while (is_run()) {
drawGame();
// 键盘事件处理
if (GetAsyncKeyState(VK_LEFT) & 0x8000) {
moveLeft();
delay_ms(130); // 防抖处理
}
// ... 其他方向键处理
// 状态更新
if (moved && boardChanged()) {
addRandomNumber();
gameOver = checkGameOver();
}
}
}
技术要点:
- 使用
GetAsyncKeyState()实现非阻塞键盘检测 - 通过
delay_ms()防止按键抖动导致的多次触发 - 合并检测
boardChanged()避免无效操作
开发经验总结
1. 代码组织策略
将游戏逻辑分为三个层次:
- 数据层:棋盘状态管理
- 逻辑层:移动、合并、判断算法
- 表现层:图形渲染、用户交互
2. EGE 库使用技巧
- 颜色系统 :使用
EGERGB(r, g, b)宏定义颜色,范围 0-255 - 字体处理 :通过
setfont()设置字体大小和样式 - 文本居中 :利用
textwidth()和textheight()计算居中偏移
3. 性能优化考虑
- 使用双缓冲机制(EGE 自动处理)
- 避免不必要的重绘,仅在状态改变时更新
- 合理使用
delay_fps()控制帧率
编译部署
依赖环境
- 编译器:MinGW-w64 (64位)
- 图形库:EGE 20.08+
- 系统:Windows
编译命令
bash
g++ 2048.cpp -o 2048.exe -ID:\mingw64\include -LD:\mingw64\lib -lgraphics -lgdi32 -lgdiplus -limm32 -lmsimg32 -lole32 -loleaut32 -lwinmm -luuid
运行方式
直接执行生成的 2048.exe 文件即可启动游戏。
扩展建议
- 音效系统:添加合并成功、游戏胜利等音效
- 存档功能:支持游戏进度保存和加载
- 难度模式:增加不同网格大小(如 5x5、6x6)
- AI 玩家:实现自动游戏算法
⚠️项目源码地址:https://github.com/anjuxi/2048-C_programming_language