2.总结
2.1 知识点

学习的主要内容

总结目的——养成良好的学习习惯

流程图

断点学习法

练习实践

程序员的最终目标

2.2 核心要点速览
项目架构
整体结构
- 场景管理:通过
E_SceneType枚举管理三个场景(开始、游戏、结束) - 主循环:
while(true)+switch实现场景切换 - 场景切换:修改
nowSceneType后break跳出当前场景循环
核心模块
| 模块 | 职责 | 关键函数/结构体 |
|---|---|---|
| 控制台初始化 | 设置窗口大小、隐藏光标 | consoleInit() |
| 开始/结束场景 | 菜单选择、场景切换 | beginOrEndScene() |
| 游戏场景 | 核心游戏逻辑 | gameScene() |
| 地图系统 | 格子生成、绘制 | Map、Grid |
| 玩家系统 | 移动、状态管理 | Player |
控制台设置
| API | 作用 | 示例 |
|---|---|---|
setConsoleSize(w, h) |
设置控制台大小 | setConsoleSize(50, 30) |
setCursorVisibility(bool) |
显示/隐藏光标 | setCursorVisibility(false) |
setCursorPosition(x, y) |
设置光标位置 | setCursorPosition(10, 5) |
setTextColor(color) |
设置文本颜色 | setTextColor(Red) |
system("cls") |
清屏 | 切换场景前调用 |
颜色系统
enum E_Color
{
Blue = 1, // 蓝色
Green = 2, // 绿色
Red = 4, // 红色
White = 7, // 白色
};
颜色组合:Red | Blue = 紫色,Green | Blue = 青色,Red | Green = 黄色
场景管理
场景枚举
enum E_SceneType
{
Begin, // 开始场景
Game, // 游戏场景
End, // 结束场景
};
场景切换流程
主循环 while(true)
↓
switch(nowSceneType)
├── Begin → beginOrEndScene() → 选择开始 → nowSceneType = Game
├── Game → gameScene() → 游戏结束 → nowSceneType = End
└── End → beginOrEndScene() → 选择返回 → nowSceneType = Begin
地图系统
格子类型
| 类型 | 枚举值 | 符号 | 颜色 | 效果 | 概率 |
|---|---|---|---|---|---|
| 普通格子 | Normal |
□ | 白色 | 无效果 | 85% |
| 炸弹 | Boom |
● | 红色 | 后退5格 | 5% |
| 暂停 | Pause |
‖ | 蓝色 | 暂停一回合 | 5% |
| 时空隧道 | Tunnel |
¤ | 黄色 | 随机效果 | 5% |
地图生成逻辑
- 蛇形布局:X 方向移动 10 格后,Y 方向移动 2 行,然后反向
- 动态内存:
new Grid[gridNum]分配格子数组 - 析构释放:
delete[] grids防止内存泄漏
玩家系统
玩家属性
| 属性 | 类型 | 说明 |
|---|---|---|
type |
E_PlayerType |
玩家/电脑 |
nowIndex |
int |
当前格子索引 |
isPause |
bool |
是否暂停 |
移动逻辑
扔骰子(1~6)
↓
nowIndex += 点数
↓
判断格子类型 → 触发效果
↓
重绘地图和玩家
↓
判断是否到达终点
时空隧道效果
| 随机数 | 效果 |
|---|---|
| 1 | 后退5格 |
| 2 | 暂停一回合 |
| 3 | 与对方交换位置 |
输入处理
| 按键 | ASCII | 作用 |
|---|---|---|
| W/w | 87/119 | 选择上一项 |
| S/s | 83/115 | 选择下一项 |
| J/j | 74/106 | 确认选择 |
| 任意键 | - | 扔骰子 |
注意:使用 _getch() 获取输入,无需回车确认。
2.3 面试题精选
基础题
1. 这个飞行棋项目的整体架构是怎么设计的?
题目
请简述这个飞行棋项目的整体架构设计思路。
深入解析
项目采用场景驱动的架构设计,核心思想是将游戏划分为多个独立场景,每个场景有独立的逻辑和渲染。
架构层次:
- 控制台层:封装底层 API,提供窗口大小、光标、颜色控制
- 场景管理层:通过枚举和主循环实现场景切换
- 游戏逻辑层:地图、玩家、格子效果等核心逻辑
- 渲染层:各模块的
draw()方法负责绘制
数据流向:
用户输入 → 场景逻辑 → 数据更新 → 渲染绘制 → 用户输入(循环)
关键设计:
- 使用
enum class定义类型,避免命名冲突 - 结构体封装数据和行为(如
Grid::draw()、Player::draw()) - 动态内存管理地图数据,析构时释放
答题示例
项目采用场景驱动架构,分为开始、游戏、结束三个场景。
主循环用
while + switch根据场景类型调用对应处理函数。每个场景独立处理输入、逻辑和渲染。数据层用结构体封装,比如
Map管理格子数组,Player管理玩家状态。控制台 API 封装成工具函数,方便调用。
参考文章
- 1.飞行棋实践
2. 如何实现场景切换?
题目
项目中是如何实现场景切换的?请说明具体实现方式。
深入解析
场景切换通过状态机模式实现,核心是维护一个当前场景状态变量。
实现要点:
- 状态变量:
E_SceneType nowSceneType记录当前场景 - 主循环分发:
switch(nowSceneType)根据状态调用对应函数 - 状态修改:在场景函数内修改
nowSceneType实现跳转 - 清屏重绘:切换场景前
system("cls")清除旧内容
代码示例:
E_SceneType nowSceneType = Begin;
while (true)
{
switch (nowSceneType)
{
case Begin:
system("cls");
beginOrEndScene(w, h, nowSceneType);
break;
case Game:
system("cls");
gameScene(w, h, nowSceneType);
break;
case End:
system("cls");
beginOrEndScene(w, h, nowSceneType);
break;
}
}
答题示例
用状态机模式实现。维护一个
nowSceneType枚举变量,主循环用switch根据它调用对应场景函数。场景函数内部通过修改
nowSceneType实现跳转,比如开始场景选「开始游戏」后设为Game。切换前调用
system("cls")清屏,保证新场景干净显示。
参考文章
- 1.飞行棋实践
进阶题
1. 地图生成算法是如何设计的?
题目
请说明地图格子的生成算法,包括布局和类型分布。
深入解析
地图生成包含布局算法和类型分布两部分。
布局算法(蛇形):
int stepNum = 2; // X方向步长
for (int i = 0; i < gridNum; i++)
{
grids[i].pos = Vector2(x, y);
if (indexX == 10)
{
y += 1;
++indexY;
if (indexY == 2)
{
stepNum = -stepNum;
indexX = 0;
indexY = 0;
}
}
else
{
x += stepNum;
++indexX;
}
}
类型分布(概率):
int randomNum = getRandom(0, 100);
if (randomNum < 85 || i == 0 || i == gridNum - 1)
grids[i].type = Normal;
else if (randomNum < 90)
grids[i].type = Boom;
else if (randomNum < 95)
grids[i].type = Pause;
else
grids[i].type = Tunnel;
设计考量:
- 首尾格子强制普通,避免开局/终点触发特殊效果
- 概率可调,通过修改随机数区间实现
答题示例
布局用蛇形算法:X 方向走 10 格,Y 方向下移 2 行,然后 X 反向,循环往复。
类型用概率分布:随机数 0-100,85% 普通格子,5% 炸弹,5% 暂停,5% 时空隧道。
首尾格子强制普通,避免玩家开局踩炸弹或终点触发特殊效果。
参考文章
- 1.飞行棋实践
2. 如何处理玩家和电脑重合的情况?
题目
项目中如何处理玩家和电脑在同一格子的重合情况?
深入解析
重合处理通过条件判断 + 特殊绘制实现。
判断逻辑:
void drawPlayer(Player& player, Player& computer, Map& map)
{
if (player.nowIndex == computer.nowIndex)
{
Grid grid = map.grids[player.nowIndex];
setCursorPosition(grid.pos.x, grid.pos.y);
setTextColor(White);
cout << "◎";
}
else
{
player.draw(map);
computer.draw(map);
}
}
设计要点:
- 比较索引:
nowIndex相同即为重合 - 特殊符号:重合时用
◎区分 - 颜色区分:玩家紫红色
★,电脑青色▲,重合白色◎ - 绘制时机:每次移动后重新绘制,保证状态同步
答题示例
通过比较
nowIndex判断重合。重合时绘制特殊符号◎,不重合时分别绘制玩家★和电脑▲。颜色也做区分:玩家紫红色,电脑青色,重合白色。
每次移动后调用
drawPlayer()重新绘制,保证显示状态实时更新。
参考文章
- 1.飞行棋实践
深度题
1. 如果要扩展这个项目,你会如何设计?
题目
如果要为这个飞行棋项目添加新功能(如多人游戏、道具系统、存档功能),你会如何设计架构?
深入解析
多人游戏扩展:
vector<Player> players;
int currentPlayerIndex = 0;
void nextTurn()
{
currentPlayerIndex = (currentPlayerIndex + 1) % players.size();
}
道具系统:
enum E_ItemType
{
Accelerate,
Shield,
Reverse,
};
struct Item
{
E_ItemType type;
int count;
};
// 在 Player 结构体中添加
map<E_ItemType, int> items;
存档功能:
struct SaveData
{
vector<int> playerPositions;
vector<bool> playerPauses;
vector<Grid> mapGrids;
};
void saveGame(const string& filename, const SaveData& data)
{
ofstream file(filename, ios::binary);
file.write((char*)&data, sizeof(data));
}
SaveData loadGame(const string& filename)
{
SaveData data;
ifstream file(filename, ios::binary);
file.read((char*)&data, sizeof(data));
return data;
}
架构优化建议:
- 场景基类:抽象出
Scene基类,各场景继承实现 - 事件系统:格子效果改为事件触发,便于扩展
- 配置文件:格子概率、地图大小等改为配置
答题示例
多人游戏:用
vector<Player>存储玩家,currentPlayerIndex记录当前回合,每回合结束取模切换。道具系统:定义道具枚举,在
Player中加map<E_ItemType, int>存储道具数量。存档功能:定义
SaveData结构体,用二进制文件读写保存玩家位置、暂停状态、地图信息。架构上可以抽象
Scene基类,格子效果改为事件系统,配置外置提高扩展性。
参考文章
- 1.飞行棋实践
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com