在游戏开发学习中,俄罗斯方块是经典的入门项目 —— 它涵盖了图形渲染、用户交互、物理逻辑等核心知识点,同时代码量适中,非常适合用来巩固 C++ 基础。最近我尝试用 AI 生成了一份完整的 C++ 俄罗斯方块代码,经过测试不仅能正常运行,还包含了经典玩法的全部核心功能。今天就带大家拆解这份代码,从结构分析到运行步骤,手把手教你理解并使用这份 AI 生成的游戏代码。

观前提示:本文使用AI写作

一、代码核心功能概览

在深入解析前,先明确这份代码的 “能力边界”—— 它基于 Windows 控制台实现(无需额外图形库),包含了俄罗斯方块的所有经典玩法,具体如下:

  • 7 种基础方块:I、J、L、O、S、T、Z 形方块,还原经典俄罗斯方块的所有形状
  • 完整交互逻辑:方向键控制(左右移动、上键旋转、下键加速)、空格键直接落底、ESC 键退出
  • 游戏机制:自动下落、行消除判断、分数计算、等级提升(难度随等级增加)
  • 可视化界面:控制台内渲染游戏区域、边框、彩色方块,同时显示分数、等级和操作说明

二、代码结构拆解:从核心模块到逻辑流程

这份代码总共约 500 行,结构清晰,可分为 “数据定义”“工具函数”“方块类”“主游戏逻辑” 四大模块。我们逐个拆解,理解 AI 是如何组织游戏代码的。

1. 基础数据定义:游戏的 “骨架”

代码开头先定义了游戏的核心常量和数据结构,这些是整个游戏的 “基础配置”,也是 AI 生成代码时首先考虑的 “游戏规则”:

// 1. 游戏区域尺寸:宽12列、高22行(含边框)
const int WIDTH = 12;
const int HEIGHT = 22;

// 2. 7种方块的形状与旋转状态(4x4矩阵存储)
int shapes[7][4][4][4] = {
    // I形方块:4种旋转状态(实际I形只有2种有效旋转,此处为统一格式)
    {
        {{0,0,0,0},{1,1,1,1},{0,0,0,0},{0,0,0,0}},
        {{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}},
        // 后两种与前两种重复,略...
    },
    // J、L、O、S、T、Z形方块同理,略...
};

// 3. 方块颜色:8种颜色(0为透明,1-7对应7种方块,8为边框)
int colors[8] = {0, 2, 3, 4, 5, 6, 7, 8};

// 4. 游戏区域矩阵:存储每个位置的“状态”(0=空白,1-7=方块,8=边框)
int board[HEIGHT][WIDTH] = {0};

这里有个细节值得注意:AI 用4x4 矩阵存储方块(即使 O 形方块只占 2x2),目的是统一所有方块的旋转和碰撞检测逻辑 —— 无论哪种方块,都能通过相同的代码判断 “是否能移动 / 旋转”,避免重复写逻辑。

2. 方块类(Block):游戏的 “核心演员”

AI 将方块的属性和行为封装成了Block类,这是面向对象思想的典型应用。方块的 “出生”“移动”“旋转”“固定到游戏板” 等操作,都通过类的成员函数实现:

class Block {
public:
    int x, y;       // 方块在游戏板的坐标(左上角为原点)
    int shape;      // 方块形状(0-6对应7种形状)
    int rotation;   // 旋转状态(0-3对应4种旋转)
    int color;      // 方块颜色(1-7)

    // 构造函数:生成新方块时自动随机形状、初始位置
    Block() {
        shape = rand() % 7;    // 随机选形状
        rotation = 0;          // 初始旋转状态
        color = shape + 1;     // 颜色与形状绑定
        x = WIDTH / 2 - 2;     // 初始x坐标(居中)
        y = 0;                 // 初始y坐标(顶部)
    }

    // 关键函数1:检查移动/旋转是否合法(避免穿墙、叠方块)
    bool checkMove(int dx, int dy, int dr, const int b[HEIGHT][WIDTH]) {
        int newRotation = (rotation + dr) % 4;  // 新旋转状态
        // 遍历4x4矩阵,判断每个“方块格子”是否超出边界或碰撞
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (shapes[shape][newRotation][i][j]) {  // 如果当前格子是方块
                    int newX = x + j + dx;  // 新x坐标
                    int newY = y + i + dy;  // 新y坐标
                    // 边界检测:x超出0-WIDTH,y超出HEIGHT(y<0允许,因为方块可能从顶部出现)
                    if (newX < 0 || newX >= WIDTH || newY >= HEIGHT)
                        return false;
                    // 碰撞检测:如果新位置已有方块(且不是空白)
                    if (newY >= 0 && b[newY][newX])
                        return false;
                }
            }
        }
        return true;
    }

    // 关键函数2:执行移动/旋转(先check再move,确保安全)
    void move(int dx, int dy, int dr) {
        if (checkMove(dx, dy, dr, board)) {
            x += dx;
            y += dy;
            rotation = (rotation + dr) % 4;
            if (rotation < 0) rotation += 4;  // 处理负旋转(如dr=-1)
        }
    }

    // 关键函数3:将方块“固定”到游戏板(下落到底后调用)
    void lockToBoard(int b[HEIGHT][WIDTH]) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (shapes[shape][rotation][i][j]) {
                    b[y + i][x + j] = color;  // 将方块颜色写入游戏板
                }
            }
        }
    }
};

Block类的核心是 “先检测再操作”:无论是移动还是旋转,都会先通过checkMove判断是否合法(避免穿墙、叠在已有方块上),再执行实际操作 —— 这是游戏逻辑不出现 “BUG” 的关键。

3. 工具函数:控制台的 “渲染与控制”

由于是控制台游戏,AI 封装了几个 Windows API 相关的工具函数,负责 “绘制界面” 和 “控制光标”:

(1)光标控制函数

  • setCursorPosition(int x, int y):将控制台光标移动到指定位置(避免界面闪烁)
  • hideCursor():隐藏控制台光标(让游戏界面更整洁)

(2)界面渲染函数

  • drawBoard():绘制游戏板(边框 + 已固定的方块)
    • 用■字符表示方块和边框
    • 通过SetConsoleTextAttribute设置文字颜色(实现彩色方块)
  • drawBlock(Block b):绘制当前正在下落的方块(单独绘制,方便后续刷新)
  • checkLines():检测并消除已满的行,同时将上方的行下移(核心逻辑)
  • gameOver():游戏结束时显示提示(当新方块无法生成时调用)

4. 主函数(main):游戏的 “总指挥”

main函数是整个游戏的 “流程控制器”,负责初始化、循环刷新、处理输入,具体步骤如下:
步骤 1:初始化游戏

srand(time(0));          // 初始化随机数种子(用于随机生成方块)
hideCursor();            // 隐藏光标
// 初始化游戏板边框(将第一列、最后一列、最后一行设为边框颜色8)
for (int i = 0; i < HEIGHT; i++) { board[i][0] = 8; board[i][WIDTH-1] = 8; }
for (int j = 0; j < WIDTH; j++) { board[HEIGHT-1][j] = 8; }
Block currentBlock;      // 生成第一个方块

步骤 2:游戏主循环(死循环,直到游戏结束)
主循环是游戏的 “心脏”,每一次循环完成 “界面刷新→输入处理→自动下落” 三件事:

int score = 0;           // 分数
int speed = 500;         // 初始下落速度(毫秒)
int level = 1;           // 等级
clock_t lastFall = clock();  // 记录上一次下落的时间

while (true) {
    // 1. 刷新界面:清屏→画游戏板→画当前方块→显示分数等级
    system("cls");
    drawBoard();
    drawBlock(currentBlock);
    setCursorPosition(WIDTH*2+2, 5); cout << "分数: " << score;
    setCursorPosition(WIDTH*2+2, 7); cout << "等级: " << level;

    // 2. 处理键盘输入(_kbhit()检测是否有按键按下)
    if (_kbhit()) {
        char key = _getch();  // 获取按键
        switch (key) {
            case 75: currentBlock.move(-1, 0, 0); break;  // 左箭头:左移
            case 77: currentBlock.move(1, 0, 0);  break;  // 右箭头:右移
            case 72: currentBlock.move(0, 0, 1);  break;  // 上箭头:旋转
            case 80: currentBlock.move(0, 1, 0);  break;  // 下箭头:加速下落
            case 32:  // 空格键:直接落底(循环检测直到不能下移)
                while (currentBlock.checkMove(0,1,0,board)) 
                    currentBlock.move(0,1,0);
                break;
            case 27: return 0;  // ESC键:退出游戏
        }
    }

    // 3. 自动下落(判断距离上一次下落是否超过speed毫秒)
    if (clock() - lastFall > speed) {
        if (currentBlock.checkMove(0,1,0,board)) {  // 能下移则下移
            currentBlock.move(0,1,0);
        } else {  // 不能下移:固定方块→检测消行→生成新方块→判断游戏结束
            currentBlock.lockToBoard(board);
            int lines = checkLines();  // 检测消行数
            if (lines > 0) {  // 有消行则更新分数和等级
                score += lines * 100;
                level = score / 1000 + 1;  // 每1000分升一级
                speed = max(100, 500 - (level-1)*50);  // 等级越高,速度越快
            }
            currentBlock = Block();  // 生成新方块
            // 如果新方块一开始就不能放,说明游戏结束
            if (!currentBlock.checkMove(0,0,0,board)) {
                gameOver();
            }
            lastFall = clock();  // 重置下落时间
        }
    }
    Sleep(10);  // 减少CPU占用(避免循环跑得太快)
}

三、代码运行指南:从编译到操作

这份代码基于 Windows 控制台,无需额外依赖库,直接用 C++ 编译器就能运行。以下是具体步骤:

1. 编译环境要求

  • 操作系统:Windows(因为用到了 Windows API,Linux/macOS 不支持)
  • 编译器:MinGW(推荐 Code::Blocks 自带)、MSVC(Visual Studio)、Dev-C++ 均可

2. 游戏操作说明

按键 功能
左箭头 ← 方块向左移动
右箭头 → 方块向右移动
上箭头 ↑ 方块旋转
下箭头 ↓ 方块加速下落
空格键 方块直接落到底部
ESC 键 退出游戏

四、AI 生成代码的优化空间

这份 AI 生成的代码已经能正常运行,但作为学习项目,还有一些可以优化的地方,适合大家进一步修改:

  1. 增加 “下一个方块预览”:当前代码没有预览功能,可在右侧界面增加一个小区域, 示下一个要生成的方块(需要新增一个nextBlock变量)
  2. 支持暂停功能:增加一个暂停键(如 P 键),暂停时停止自动下落和输入响应
  3. 优化界面美观度:当前用■字符绘制,可换成□或其他字符,同时调整颜色搭配
  4. 增加音效:通过 Windows API 的PlaySound函数添加下落、消行、游戏结束的音效
  5. 适配 Linux/macOS:将 Windows API 替换为 ncurses 库(跨平台控制台库),实现多系统支持

五、总结:从 AI 代码中学到什么?

这份 AI 生成的俄罗斯方块代码,不仅是一个可运行的游戏,更是一份优秀的 C++ 学习案例:

  • 面向对象思想:用Block类封装方块的属性和行为,逻辑清晰、可复用
  • 游戏开发核心逻辑:碰撞检测、物理下落、界面刷新的经典实现方式
  • 控制台交互技巧:Windows API 的光标控制、颜色设置,避免界面闪烁的方法

如果你是 C++ 初学者,建议先理解代码的 “逻辑流程”(尤其是checkMove和main循环),再尝试修改优化 —— 比如增加预览功能、调整速度曲线,这会让你对游戏开发和 C++ 编程有更深的理解。

最后,附上完整代码:

#include <iostream>
#include <vector>
#include <windows.h>
#include <conio.h>
#include <time.h>

using namespace std;

// 游戏区域尺寸
const int WIDTH = 12;
const int HEIGHT = 22;

// 方块的7种形状及其4种旋转状态
int shapes[7][4][4][4] = {
    // I
    {
        {{0,0,0,0},
         {1,1,1,1},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,0,0},
         {0,1,0,0},
         {0,1,0,0}},
        {{0,0,0,0},
         {1,1,1,1},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,0,0},
         {0,1,0,0},
         {0,1,0,0}}
    },
    // J
    {
        {{1,0,0,0},
         {1,1,1,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,1,0},
         {0,1,0,0},
         {0,1,0,0},
         {0,0,0,0}},
        {{0,0,0,0},
         {1,1,1,0},
         {0,0,1,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,0,0},
         {1,1,0,0},
         {0,0,0,0}}
    },
    // L
    {
        {{0,0,1,0},
         {1,1,1,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,0,0},
         {0,1,1,0},
         {0,0,0,0}},
        {{0,0,0,0},
         {1,1,1,0},
         {1,0,0,0},
         {0,0,0,0}},
        {{1,1,0,0},
         {0,1,0,0},
         {0,1,0,0},
         {0,0,0,0}}
    },
    // O
    {
        {{1,1,0,0},
         {1,1,0,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{1,1,0,0},
         {1,1,0,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{1,1,0,0},
         {1,1,0,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{1,1,0,0},
         {1,1,0,0},
         {0,0,0,0},
         {0,0,0,0}}
    },
    // S
    {
        {{0,1,1,0},
         {1,1,0,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,1,0},
         {0,0,1,0},
         {0,0,0,0}},
        {{0,1,1,0},
         {1,1,0,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,1,0},
         {0,0,1,0},
         {0,0,0,0}}
    },
    // T
    {
        {{0,1,0,0},
         {1,1,1,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {0,1,1,0},
         {0,1,0,0},
         {0,0,0,0}},
        {{0,0,0,0},
         {1,1,1,0},
         {0,1,0,0},
         {0,0,0,0}},
        {{0,1,0,0},
         {1,1,0,0},
         {0,1,0,0},
         {0,0,0,0}}
    },
    // Z
    {
        {{1,1,0,0},
         {0,1,1,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,0,1,0},
         {0,1,1,0},
         {0,1,0,0},
         {0,0,0,0}},
        {{1,1,0,0},
         {0,1,1,0},
         {0,0,0,0},
         {0,0,0,0}},
        {{0,0,1,0},
         {0,1,1,0},
         {0,1,0,0},
         {0,0,0,0}}
    }
};

// 方块颜色
int colors[8] = {0, 2, 3, 4, 5, 6, 7, 8};

// 游戏区域
int board[HEIGHT][WIDTH] = {0};

// 方块类
class Block {
public:
    int x, y; // 位置
    int shape; // 形状
    int rotation; // 旋转状态
    int color; // 颜色

    Block() {
        // 随机生成方块
        shape = rand() % 7;
        rotation = 0;
        color = shape + 1;
        x = WIDTH / 2 - 2;
        y = 0;
    }

    // 检查移动是否合法
    bool checkMove(int dx, int dy, int dr, const int b[HEIGHT][WIDTH]) {
        int newRotation = (rotation + dr) % 4;
        if (newRotation < 0) newRotation += 4;

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (shapes[shape][newRotation][i][j]) {
                    int newX = x + j + dx;
                    int newY = y + i + dy;
                    if (newX < 0 || newX >= WIDTH || newY >= HEIGHT)
                        return false;
                    if (newY >= 0 && b[newY][newX])
                        return false;
                }
            }
        }
        return true;
    }

    // 移动方块
    void move(int dx, int dy, int dr) {
        if (checkMove(dx, dy, dr, board)) {
            x += dx;
            y += dy;
            rotation = (rotation + dr) % 4;
            if (rotation < 0) rotation += 4;
        }
    }

    // 将方块固定到游戏板上
    void lockToBoard(int b[HEIGHT][WIDTH]) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (shapes[shape][rotation][i][j]) {
                    b[y + i][x + j] = color;
                }
            }
        }
    }
};

// 函数声明
void setCursorPosition(int x, int y);
void hideCursor();
void drawBoard();
void drawBlock(Block b);
int checkLines();
void gameOver();

// 设置光标位置
void setCursorPosition(int x, int y) {
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 隐藏光标
void hideCursor() {
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

// 绘制游戏板
void drawBoard() {
    // 绘制边框
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            setCursorPosition(j * 2, i);
            if (j == 0 || j == WIDTH - 1)
                cout << "■"; // 边框
            else if (i == HEIGHT - 1)
                cout << "■"; // 底部边框
            else if (board[i][j]) {
                // 设置颜色
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors[board[i][j]]);
                cout << "■";
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); // 恢复默认颜色
            } else
                cout << "  "; // 空白
        }
    }
}

// 绘制当前方块
void drawBlock(Block b) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors[b.color]);
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (shapes[b.shape][b.rotation][i][j]) {
                setCursorPosition((b.x + j) * 2, b.y + i);
                cout << "■";
            }
        }
    }
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); // 恢复默认颜色
}

// 检查并消除已满的行
int checkLines() {
    int lines = 0;
    for (int i = HEIGHT - 2; i > 0; i--) {
        bool full = true;
        for (int j = 1; j < WIDTH - 1; j++) {
            if (board[i][j] == 0) {
                full = false;
                break;
            }
        }
        if (full) {
            lines++;
            // 消除当前行,并将上面的行下移
            for (int k = i; k > 0; k--) {
                for (int j = 1; j < WIDTH - 1; j++) {
                    board[k][j] = board[k - 1][j];
                }
            }
            // 第一行清空
            for (int j = 1; j < WIDTH - 1; j++) {
                board[0][j] = 0;
            }
            i++; // 检查新下移的行
        }
    }
    return lines;
}

// 游戏结束
void gameOver() {
    setCursorPosition(WIDTH, HEIGHT / 2);
    cout << "游戏结束!";
    setCursorPosition(WIDTH, HEIGHT / 2 + 1);
    cout << "按任意键退出";
    _getch();
    exit(0);
}

int main() {
    srand(time(0));
    hideCursor();
    
    // 初始化边框
    for (int i = 0; i < HEIGHT; i++) {
        board[i][0] = 8;
        board[i][WIDTH - 1] = 8;
    }
    for (int j = 0; j < WIDTH; j++) {
        board[HEIGHT - 1][j] = 8;
    }

    Block currentBlock;
    int score = 0;
    int speed = 500; // 初始速度(毫秒)
    int level = 1;
    clock_t lastFall = clock();

    while (true) {
        // 绘制游戏
        system("cls");
        drawBoard();
        drawBlock(currentBlock);

        // 显示分数和等级
        setCursorPosition(WIDTH * 2 + 2, 5);
        cout << "分数: " << score;
        setCursorPosition(WIDTH * 2 + 2, 7);
        cout << "等级: " << level;
        setCursorPosition(WIDTH * 2 + 2, 10);
        cout << "控制:";
        setCursorPosition(WIDTH * 2 + 2, 11);
        cout << "← → 移动";
        setCursorPosition(WIDTH * 2 + 2, 12);
        cout << "↑ 旋转";
        setCursorPosition(WIDTH * 2 + 2, 13);
        cout << "↓ 加速下落";
        setCursorPosition(WIDTH * 2 + 2, 14);
        cout << "空格 直接落下";

        // 处理键盘输入
        if (_kbhit()) {
            char key = _getch();
            switch (key) {
                case 75: // 左箭头
                    currentBlock.move(-1, 0, 0);
                    break;
                case 77: // 右箭头
                    currentBlock.move(1, 0, 0);
                    break;
                case 72: // 上箭头
                    currentBlock.move(0, 0, 1);
                    break;
                case 80: // 下箭头
                    currentBlock.move(0, 1, 0);
                    break;
                case 32: // 空格
                    // 直接落下
                    while (currentBlock.checkMove(0, 1, 0, board)) {
                        currentBlock.move(0, 1, 0);
                    }
                    break;
                case 27: // ESC
                    return 0;
            }
        }

        // 自动下落
        if (clock() - lastFall > speed) {
            if (currentBlock.checkMove(0, 1, 0, board)) {
                currentBlock.move(0, 1, 0);
            } else {
                // 固定方块
                currentBlock.lockToBoard(board);
                
                // 检查消除的行数并更新分数
                int lines = checkLines();
                if (lines > 0) {
                    score += lines * 100;
                    // 每1000分升一级,加快速度
                    if (score / 1000 + 1 > level) {
                        level = score / 1000 + 1;
                        speed = max(100, 500 - (level - 1) * 50); // 最低100ms
                    }
                }
                
                // 生成新方块
                currentBlock = Block();
                
                // 检查游戏是否结束
                if (!currentBlock.checkMove(0, 0, 0, board)) {
                    gameOver();
                }
            }
            lastFall = clock();
        }

        // 小延迟,减少CPU占用
        Sleep(10);
    }

    return 0;
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐