# Tetris
**Repository Path**: Erick0412/Tetris
## Basic Information
- **Project Name**: Tetris
- **Description**: 用C写的俄罗斯方块。
- **Primary Language**: C
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-07-01
- **Last Updated**: 2025-07-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# **C语言俄罗斯方块项目 - 技术学习文档**
**版本:** 1.13
**作者:** 小火龙Erick
**前言**
本篇技术文档旨在对一个基于C语言实现的控制台版“俄罗斯方块”项目进行深入剖析。该项目不仅是C语言编程能力的综合体现,更是一个学习基本游戏开发原理的绝佳案例。文档将系统地介绍项目的功能、技术选型、核心数据结构与算法,帮助读者理解从静态数据到动态交互式游戏的完整构建过程。
## 1. 项目功能概述 (Functionality Overview)
- **经典游戏玩法**: 完整复刻了俄罗斯方块的核心机制,包括方块的随机生成、下落、旋转、移动以及行消除。
- **图形化控制台界面**: 利用Windows控制台API,实现了包含主游戏区、下一个方块预览、实时分数/等级/速度显示以及操作提示的完整游戏界面。
- **动态难度递增**: 游戏引入了等级系统,当分数累计到一定值时,等级提升,方块下落速度随之加快,增加了游戏的挑战性。
- **高分排行榜**: 游戏能够自动记录并持久化存储排名前10的玩家得分。当玩家创造新纪录时,系统会提示输入姓名并更新排行榜。
- **完善的游戏流程**: 提供了包含欢迎菜单、游戏规则、按键说明、游戏主循环、暂停/继续功能以及游戏结束界面的完整用户体验流程。
## 2. 技术实现方案 (Technical Implementation)
本项目利用C语言标准库结合Windows平台特有的API,构建了一个功能丰富的控制台应用。
| 依赖头文件 | 主要功能 |
| --- | --- |
| `stdio.h` | 负责标准输入/输出,如 `printf` 绘制界面,以及文件操作(`fopen`, `fprintf`, `fgets`)用于读写高分榜。 |
| `stdlib.h` | 提供关键的通用函数:`rand()`/`srand()` 用于生成随机方块,`system()` 用于执行清屏等系统命令,`atoi()` 用于将字符串转换为整数。 |
| `windows.h` | **(核心)** 提供访问Windows控制台API的接口,用于实现图形化效果:
- `SetConsoleCursorPosition`: 定位光标,是我们自定义 `gotoxy()` 函数的基础。
- `SetConsoleTextAttribute`: 设置文本颜色,封装为 `setColor()`。
- `SetConsoleCursorInfo`: 控制光标的显示与隐藏。 |
| `conio.h` | **(核心)** 提供非阻塞的键盘输入功能:
- `_kbhit()`: 检测是否有按键,不阻塞程序执行,是游戏实时响应的关键。
- `_getch()`: 直接获取按键码,无需等待回车。 |
| `time.h` | 使用 `time()` 获取当前时间作为 `srand()` 的种子,确保随机性。 |
- `string.h` | 提供字符串处理函数,如 `strcpy`、`strcmp`、`strlen` 和 `strcspn`,主要用于处理高分榜中的玩家姓名。 |
**实现概要**: 本项目通过C语言构建底层逻辑,并调用Windows API来渲染图形、处理颜色和实现实时输入,从而在纯文本的控制台环境中模拟出动态的游戏画面。
## 3. 核心原理剖析 (Core Principles)
### 3.1 核心数据结构
- **方块形态 (`BLOCK_SHAPES`)**:
```c
const int BLOCK_SHAPES[7][4][4][4] = { ... };
```
这是一个四维常量数组,是整个游戏的核心数据。它的维度定义如下:
- `[7]`: 代表7种不同形状的方块 (I, J, L, O, S, T, Z)。
- `[4]`: 代表每种方块的4个旋转形态。
- `[4][4]`: 代表一个4x4的网格,用于描述单个方块的形态。值为 `1` 表示该位置有实体方块,`0` 表示为空。
这种设计将所有方块的形态数据硬编码到程序中,使得渲染和碰撞检测逻辑变得统一和简化。
- **游戏区域 (`gameBoard`)**:
```c
int gameBoard[BOARD_HEIGHT][BOARD_WIDTH];
```
一个二维整数数组,是游戏主区域的逻辑表示。数组中的每个元素代表一个格子,`0` 表示空格,非 `0` 值(在此项目中为方块颜色代码)表示该格子已被固定的方块占据。
- **当前方块 (`currentBlock`)**:
```c
Block currentBlock; // typedef struct { int x, y, type, rotation; } Block;
```
一个 `Block` 类型的结构体变量,用于存储当前正在下落的方块的所有状态信息,包括其在 `gameBoard` 上的坐标 `(x, y)`、形状 `type` 以及当前的旋转形态 `rotation`。
### 3.2 游戏主循环 (`runGame`)
游戏的核心是一个由 `while (!isGameOver)` 控制的主循环。每一轮循环都模拟了游戏世界的一个“时间片”,主要包含以下步骤:
1. **处理输入 (`handleInput`)**: 使用 `_kbhit()` 检查是否有用户输入。如果有,则根据按键(移动、旋转、暂停、退出)更新 `currentBlock` 的状态。
2. **更新逻辑 (`updateGame`)**: 当达到预设的下落时间间隔(由 `speed` 变量控制)时,执行游戏逻辑更新。主要是尝试将 `currentBlock` 向下移动一格。
3. **碰撞检测与固化**: 在 `updateGame` 中,会调用 `checkCollision()` 来判断方块下方是否是边界或已有方块。如果发生碰撞,则调用 `lockBlock()` 将当前方块“固化”到 `gameBoard` 中,然后检查是否有可消除的行 (`clearLines()`),并生成新的方块 (`createNewBlock()`)。
4. **渲染**: 在每次状态更新后(如移动、下落),通过 `eraseBlock()` 和 `drawBlock()` 函数在控制台上擦除旧位置、绘制新位置,从而产生动画效果。
5. **游戏节奏控制 (`Sleep`)**: `Sleep()` 函数用于控制循环的频率,保证游戏平滑运行。
### 3.3 关键算法解析
- **碰撞检测 (`checkCollision`)**:
这是游戏中最关键的算法之一。它接收一个假定要移动到的位置 `(x, y)` 和形态 `(type, rotation)` 作为参数。算法逻辑如下:
1. 遍历该形态的4x4网格。
2. 对于网格中值为 `1` 的每一个点,计算其在 `gameBoard` 上的绝对坐标。
3. 检查该绝对坐标是否超出了游戏区域的左右下边界,或者是否与 `gameBoard` 中已存在的方块重叠。
4. 只要有任何一个点发生碰撞,函数立即返回 `1` (true)。如果所有点都合法,则返回 `0` (false)。
- **行消除 (`clearLines`)**:
当一个方块被固化后,此函数被调用。
1. 从 `gameBoard` 的最底行开始向上逐行检查。
2. 如果发现某一行所有格子都为非 `0` 值(即满行),则记录消除的行数,并将该行以上的所有行依次向下平移一行。
3. 最顶行被清空为 `0`。
4. 根据消除的行数更新分数和等级。
### 3.4 高分榜的持久化 (`load/saveHighScores`)
高分榜功能通过文件I/O实现数据持久化。
- **数据格式**: 本项目采用纯文本文件 (`.txt`) 存储高分榜,每条记录占用两行:第一行是玩家姓名,第二行是分数。这种格式易于人类阅读和调试。
- **`loadHighScores()`**: 程序启动时调用。它尝试打开 `tetris_scores.txt` 文件,并使用 `fgets()` 逐行读取姓名和分数,填充到 `highScores` 结构体数组中。
- **`saveHighScores()`**: 当有新纪录产生时调用。它以写入模式 (`"w"`) 打开文件(会覆盖旧内容),然后使用 `fprintf()` 将 `highScores` 数组中的所有记录按格式写回文件。
- **`checkAndSaveHighScore()`**: 游戏结束后调用此函数。它判断当前分数是否能进入排行榜。如果可以,则会绘制一个专门的界面,提示用户输入姓名,然后将新纪录插入到 `highScores` 数组的正确位置,并调用 `saveHighScores()` 保存。
## 4. 编译与运行指南 (Build & Run)
1. **环境要求**: Windows操作系统,并安装C语言编译环境(如 MinGW 或 Dev-C++)。
2. **保存文件**: 将源代码保存为 `tetris.c`。
3. **编译命令 (使用GCC)**:
```bash
gcc tetris.c -o tetris.exe
```
4. **运行程序**:
```bash
.\tetris.exe
```
首次运行时,`tetris_scores.txt` 文件会自动创建(当产生第一个高分记录时)。