【附C++源码】从零开始实现 2048 游戏

【附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 文件即可启动游戏。

扩展建议

  1. 音效系统:添加合并成功、游戏胜利等音效
  2. 存档功能:支持游戏进度保存和加载
  3. 难度模式:增加不同网格大小(如 5x5、6x6)
  4. AI 玩家:实现自动游戏算法

⚠️项目源码地址:https://github.com/anjuxi/2048-C_programming_language

相关推荐
小小de风呀2 分钟前
de风——【从零开始学C++】(十三):优先级队列 priority_queue 全解析 & 仿函数入门
开发语言·c++
王老师青少年编程6 分钟前
信奥赛C++提高组csp-s之搜索进阶(记忆化搜索案例实践1)
c++·记忆化搜索·搜索·信奥赛·csp-s·提高组·滑雪
摇滚侠8 分钟前
git ignore 忽略 .idea 目录 全新项目(尚未提交过 .idea).idea 已经被 Git 跟踪(已提交过)
java·git·intellij-idea
linge_sun9 分钟前
SpringAI SQL 智能助手实战:用自然语言查询数据库
java·人工智能·ai编程
熟悉的新风景9 分钟前
maven常用依赖
java·maven
light blue bird10 分钟前
3C 数码电子BOM 协同工作台组件
java·开发语言·jvm·windows·.net·桌面端
落羽的落羽11 分钟前
【项目】JsonRpc框架——功能测试、项目总结
linux·服务器·开发语言·c++·qt·算法·机器学习
Lucis__15 分钟前
图的高阶算法:从构造最小生成树到求解最短路径问题
数据结构·c++·算法·图论
我是一颗柠檬18 分钟前
【Redis】Redis分布式锁Day13(2026年)
java·redis·分布式·缓存
好评1249 小时前
【C++】智能指针全解
c++·智能指针