当前位置: 首页 > news >正文

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()函数实现,其逻辑可拆解为三个维度:

  1. 边界碰撞检测:确保方块不会超出游戏区域的左右边界(x∈[0, FIELD_WIDTH))和底部边界(y∈[0, FIELD_HEIGHT))。
  2. 固定方块碰撞检测:遍历游戏区域数组field,检查当前方块的目标位置是否已被其他方块占据(即field[realY][realX] != 0)。
  3. 旋转碰撞预判:在尝试旋转方块时,预先计算旋转后的形状矩阵,若与边界或固定方块冲突,则撤销旋转操作。
    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()均基于碰撞检测结果实现。以水平移动为例:

  4. 左移逻辑:尝试将currentX减 1,调用checkCollision()检测是否合法,若碰撞则回退坐标。
  5. 自动下落:通过定时器周期性调用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的每一行,若某行所有单元格均为非零值(即满行),则执行消除操作:

  6. 得分计算:消除一行得 100 分,连续消除多行可叠加得分(如四行消除得 1000 分)。
  7. 行下移逻辑:从满行上方开始,将每一行数据复制到下一行,顶部生成新的空行。
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. 颜色映射:根据方块类型值(如 1-7)映射到不同颜色(通过 Windows API 设置控制台字体颜色)。
  2. 边框绘制:在游戏区域周围绘制边框,提升界面可读性。
    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 扩展功能建议

  3. 音效系统:通过Beep()函数或第三方库添加移动、旋转、消除音效。
  4. 预览功能:在界面右侧显示下一个方块的形状。
  5. 难度系统:根据得分提升方块下落速度。

  6. 抽象思维:将物理实体(方块、游戏区域)抽象为数据结构。
  7. 边界条件处理:碰撞检测、满行消除等逻辑需全面考虑各种极端情况。
  8. 模块化设计:将功能拆解为独立函数(如checkCollision()fixShape()),提升代码可维护性。
  9. 性能优化:通过提前终止循环(如碰撞时立即返回)减少不必要计算。
    • 存档功能:将最高分写入文件持久化存储。
    • 图形化界面:使用 SFML、SDL 等库替换控制台渲染,实现更丰富的视觉效果。

⚡YQW · Studio ⚡

(好吧,其实只有我一个人,只是为了氛围)

如系统不符或无此扩展库,可能无法执行 

相关文章:

  • 铅酸电池充电器方案EG1253+EG4321
  • JVM 学习
  • Spring Boot 版本与对应 JDK 版本兼容性
  • 雨滴传感器详解(STM32)
  • Sharding-JDBC 系列专题 - 第二篇:广播表(Broadcast Tables)
  • VuePress 使用教程:从入门到精通
  • 算法题(129):二维前缀和
  • RHCSA Linux 系统文件内容显示2
  • FPGA学习(五)——DDS信号发生器设计
  • 国产动漫记录
  • LangChain4j语言模型选型指南:主流模型能力全景对比
  • FreeRTOS中断管理
  • 【Agent】AI智能体评测基座AgentCLUE-General
  • python解压复制文件
  • Python多进程并发编程:深入理解Lock与Semaphore的实战应用与避坑指南
  • 【每日八股】复习 Redis Day1:Redis 的持久化(上)
  • 力扣DAY60-61 | 热100 | 回溯:单词搜索、分割回文串
  • 二、在springboot 中使用 AIService
  • 第38讲|AI + 农业病虫害预测建模
  • 2025-04-20 李沐深度学习4 —— 自动求导
  • 上海4-6月文博美展、剧目演出不断,将开设直播推出文旅优惠套餐
  • “仅退款”将成历史?电商平台集中调整售后规则
  • 格力电器:选举董明珠为公司第十三届董事会董事长
  • 全国人大常委会调研组在宁波调研,张庆伟带队钟山易炼红参加
  • 日方炒作中国社会治安形势不佳,外交部:政治操弄意图明显
  • 中方决定对在涉港问题上表现恶劣的美国国会议员、官员和非政府组织负责人实施制裁