C++ 俄罗斯方块 | Tetris⚡YQW · Studio ⚡【无需下载图片】
一、游戏架构概述:符号化方块的视觉呈现与数据建模
俄罗斯方块的核心视觉元素是由不同形状的方块组成的 “Tetromino”(四格骨牌),在 C++ 实现中,我们采用符号化表示法,通过字符矩阵模拟方块的形状。例如,用
■
(ASCII 码可自定义)表示单个方块单元,每个方块类型对应一个二维数组,数组中的非零值代表该位置存在方块单元。这种符号化设计既简化了图形渲染逻辑,又便于进行碰撞检测和坐标变换。
⚡YQW · Studio ⚡
目录
一、游戏架构概述:符号化方块的视觉呈现与数据建模
⚡YQW · Studio ⚡
1.1 方块类型与形状定义
1.2 游戏区域的二维数组建模
二、核心功能模块解析:从用户输入到游戏状态更新
2.1 碰撞检测:游戏逻辑的基石
2.2 方块移动控制:响应玩家输入
2.3 方块旋转:形状变换的数学逻辑
三、游戏状态管理:从方块固定到得分系统
3.1 方块固定与满行消除
3.2 新方块生成与游戏结束判断
四、渲染系统设计:符号化界面的控制台实现
六、总结:从代码到编程思维的提升
五、完整代码框架与扩展方向
5.1 代码框架总览(简化版)
5.2 扩展功能建议
⚡YQW · Studio ⚡
1.1 方块类型与形状定义
游戏中共有 7 种基础方块类型(I、O、T、L、J、S、Z),每种类型包含 4 种旋转状态(0-3)。我们通过三维数组shapes[SHAPE_COUNT][ROTATION_COUNT][SIZE][SIZE]
存储所有方块的形状数据。以 I 型方块为例:
// I型方块的4种旋转状态(竖放、横放、竖放、横放)
{{ {1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0} }, // 竖放{ {0,0,0,0}, {0,0,0,0}, {4,4,4,4}, {0,0,0,0} }, // 横放{ {1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0} }, // 竖放(与状态0相同){ {0,0,0,0}, {0,0,0,0}, {4,4,4,4}, {0,0,0,0} } // 横放(与状态1相同)
}
数组中的数值代表方块的颜色或类型标识(如 1 代表 I 型,2 代表 O 型等),后续渲染时可根据数值映射到不同符号(如
■
、□
等)。
1.2 游戏区域的二维数组建模
游戏区域被抽象为一个FIELD_HEIGHT×FIELD_WIDTH
的二维数组field
,数组元素值为 0 表示空单元格,非零值表示该位置有方块。这种结构便于快速进行碰撞检测和满行判断。例如,当玩家操控的方块移动时,只需遍历方块的当前形状矩阵,将每个单元的坐标转换为field
中的索引,即可判断是否与边界或已固定方块冲突。
二、核心功能模块解析:从用户输入到游戏状态更新
2.1 碰撞检测:游戏逻辑的基石
碰撞检测是俄罗斯方块的核心机制,决定了方块是否可以移动、旋转或下落。该功能通过checkCollision()
函数实现,其逻辑可拆解为三个维度:
- 边界碰撞检测:确保方块不会超出游戏区域的左右边界(x∈[0, FIELD_WIDTH))和底部边界(y∈[0, FIELD_HEIGHT))。
- 固定方块碰撞检测:遍历游戏区域数组
field
,检查当前方块的目标位置是否已被其他方块占据(即field[realY][realX] != 0
)。 - 旋转碰撞预判:在尝试旋转方块时,预先计算旋转后的形状矩阵,若与边界或固定方块冲突,则撤销旋转操作。
bool checkCollision() {for (int y = 0; y < SHAPE_SIZE; y++) {for (int x = 0; x < SHAPE_SIZE; x++) {int cell = shapes[currentShape][currentRotation][y][x];if (cell == 0) continue; // 跳过空白单元格int realX = currentX + x;int realY = currentY + y;// 边界碰撞:左、右、底部边界检测if (realX < 0 || realX >= FIELD_WIDTH || realY >= FIELD_HEIGHT) {return true;}// 顶部边界无需检测(方块可在顶部生成)// 固定方块碰撞检测if (realY >= 0 && field[realY][realX] != 0) {return true;}}}return false; }
2.2 方块移动控制:响应玩家输入
玩家通过方向键(←→↑↓)控制方块移动,对应的函数
moveLeft()
、moveRight()
、moveDown()
和rotateShape()
均基于碰撞检测结果实现。以水平移动为例: - 左移逻辑:尝试将
currentX
减 1,调用checkCollision()
检测是否合法,若碰撞则回退坐标。 - 自动下落:通过定时器周期性调用
moveDown()
,方块逐步下落,触底后通过fixShape()
将方块固定到field
数组,并触发满行检测。void moveLeft() {currentX--;if (checkCollision()) {currentX++; // 碰撞回退} }void moveDown() {currentY++;if (checkCollision()) {currentY--; // 回退到碰撞前位置fixShape(); // 固定方块checkLines(); // 检查消除行spawnNewShape(); // 生成新方块} }
2.3 方块旋转:形状变换的数学逻辑
旋转功能通过改变
currentRotation
值实现,每次旋转时需重新计算方块的形状矩阵。以 T 型方块为例,其四种旋转状态对应不同的矩阵排列。旋转后若发生碰撞(如靠近边界或其他方块),则恢复原旋转状态,确保操作合法。void rotateShape() {int originalRotation = currentRotation;currentRotation = (currentRotation + 1) % ROTATION_COUNT; // 切换旋转状态if (checkCollision()) { // 检测旋转后的碰撞currentRotation = originalRotation; // 碰撞则回退} }
三、游戏状态管理:从方块固定到得分系统
3.1 方块固定与满行消除
当方块触底或接触其他方块时,通过
fixShape()
将方块的当前位置写入field
数组,标记为固定方块。随后调用checkLines()
遍历field
的每一行,若某行所有单元格均为非零值(即满行),则执行消除操作: - 得分计算:消除一行得 100 分,连续消除多行可叠加得分(如四行消除得 1000 分)。
- 行下移逻辑:从满行上方开始,将每一行数据复制到下一行,顶部生成新的空行。
void checkLines() {int linesCleared = 0;vector<int> fullRow(FIELD_WIDTH, 1); // 满行标识:全为非零值// 从下往上检查每一行for (int y = FIELD_HEIGHT - 1; y >= 0; y--) {if (field[y] == fullRow) { // 检测到满行// 删除该行,上方行下移for (int dy = y; dy > 0; dy--) {field[dy] = field[dy - 1];}// 顶部插入空行field[0] = vector<int>(FIELD_WIDTH, 0);linesCleared++;y++; // 重新检查当前行(因上方行下移后可能再次满行)}}// 更新得分(示例:每行100分,四行连消额外加分)if (linesCleared == 1) score += 100;else if (linesCleared == 2) score += 300;else if (linesCleared == 3) score += 700;else if (linesCleared == 4) score += 1500;
}
3.2 新方块生成与游戏结束判断
当固定方块后,通过spawnNewShape()
在游戏区域顶部中心生成新方块。若新方块生成时立即发生碰撞(即顶部已被填满),则判定游戏结束。
void spawnNewShape() {currentShape = rand() % SHAPE_COUNT; // 随机生成方块类型currentRotation = 0; // 初始旋转状态为0currentX = FIELD_WIDTH / 2 - SHAPE_SIZE / 2; // 居中生成currentY = 0; // 顶部起始位置// 检测是否生成失败(顶部已满)if (checkCollision()) {gameOver = true;cout << "Game Over! Score: " << score << endl;}
}
四、渲染系统设计:符号化界面的控制台实现
在控制台环境下,通过cout
输出符号矩阵实现游戏界面渲染。核心函数drawField()
和drawShape()
分别负责绘制固定方块和当前移动方块:
六、总结:从代码到编程思维的提升
俄罗斯方块的 C++ 实现涵盖了程序设计的多个核心要素:数据建模(二维数组、三维矩阵)、逻辑控制(碰撞检测、状态机)、用户交互(输入处理、界面渲染)。通过拆解这些模块,我们可以深入理解以下编程思维:
- 颜色映射:根据方块类型值(如 1-7)映射到不同颜色(通过 Windows API 设置控制台字体颜色)。
- 边框绘制:在游戏区域周围绘制边框,提升界面可读性。
void setColor(int color) {HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hConsole, color); }void drawField() {system("cls"); // 清屏setColor(15); // 白色边框// 绘制顶部边框cout << "╔";for (int i = 0; i < FIELD_WIDTH * 2; i++) cout << "═";cout << "╗" << endl;// 绘制游戏区域for (int y = 0; y < FIELD_HEIGHT; y++) {cout << "║";for (int x = 0; x < FIELD_WIDTH; x++) {int cell = field[y][x];if (cell == 0) {cout << " "; // 空单元格} else {setColor(cell); // 设置颜色cout << "■"; // 绘制方块符号}}setColor(15); // 恢复白色边框cout << "║" << endl;}// 绘制底部边框cout << "╚";for (int i = 0; i < FIELD_WIDTH * 2; i++) cout << "═";cout << "╝" << endl;// 绘制得分cout << "Score: " << score << endl; }
五、完整代码框架与扩展方向
5.1 代码框架总览(简化版)
#include <iostream> #include <vector> #include <cstdlib> #include <ctime> #include <windows.h>using namespace std;// 常量定义 const int SHAPE_COUNT = 7; const int ROTATION_COUNT = 4; const int SHAPE_SIZE = 4; const int FIELD_WIDTH = 10; const int FIELD_HEIGHT = 20; const int COLOR_I = 11; // 青色 const int COLOR_O = 14; // 黄色 const int COLOR_T = 10; // 绿色 // 其他颜色定义...// 方块形状数据(简化示例,仅I型和O型) int shapes[SHAPE_COUNT][ROTATION_COUNT][SHAPE_SIZE][SHAPE_SIZE] = {// I型{{{1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0}}, // 竖放{{0,0,0,0}, {0,0,0,0}, {1,1,1,1}, {0,0,0,0}}, // 横放// 其他旋转状态...},// O型{{{2,2}, {2,2}, {0,0}, {0,0}}, // 所有旋转状态相同// ...}// 其他方块类型... };// 游戏状态 vector<vector<int>> field(FIELD_HEIGHT, vector<int>(FIELD_WIDTH, 0)); int currentX, currentY, currentShape, currentRotation; int score = 0; bool gameOver = false;// 函数声明 void initGame(); void handleInput(); void updateGame(); void renderGame(); // 其他函数声明...int main() {initGame();while (!gameOver) {handleInput();updateGame();renderGame();Sleep(100); // 控制游戏节奏}return 0; }// 初始化游戏 void initGame() {srand(time(NULL));field = vector<vector<int>>(FIELD_HEIGHT, vector<int>(FIELD_WIDTH, 0));spawnNewShape(); }// 输入处理(简化,仅处理方向键) void handleInput() {if (GetAsyncKeyState(VK_LEFT)) moveLeft();if (GetAsyncKeyState(VK_RIGHT)) moveRight();if (GetAsyncKeyState(VK_UP)) rotateShape();if (GetAsyncKeyState(VK_DOWN)) moveDown(); }
5.2 扩展功能建议
- 音效系统:通过
Beep()
函数或第三方库添加移动、旋转、消除音效。 - 预览功能:在界面右侧显示下一个方块的形状。
- 难度系统:根据得分提升方块下落速度。
- 抽象思维:将物理实体(方块、游戏区域)抽象为数据结构。
- 边界条件处理:碰撞检测、满行消除等逻辑需全面考虑各种极端情况。
- 模块化设计:将功能拆解为独立函数(如
checkCollision()
、fixShape()
),提升代码可维护性。 - 性能优化:通过提前终止循环(如碰撞时立即返回)减少不必要计算。
- 存档功能:将最高分写入文件持久化存储。
- 图形化界面:使用 SFML、SDL 等库替换控制台渲染,实现更丰富的视觉效果。
⚡YQW · Studio ⚡
(好吧,其实只有我一个人,只是为了氛围)