15.总结
15.1 知识点

学习的主要内容

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

流程图

断点学习法

练习

15.2 核心要点速览
控制台基础操作
| API | 作用 | 示例 | 注意 |
|---|---|---|---|
Console.CursorVisible |
光标显隐控制 | Console.CursorVisible = false; |
游戏开始时隐藏光标 |
Console.SetWindowSize |
设置窗口大小 | Console.SetWindowSize(50, 30); |
先设窗口,再设缓冲区 |
Console.SetBufferSize |
设置缓冲区大小 | Console.SetBufferSize(50, 30); |
缓冲区≥窗口大小 |
Console.Clear |
清空控制台 | Console.Clear(); |
切换场景时使用 |
Console.WriteLine |
输出并换行 | Console.WriteLine("Hello"); |
显示信息 |
Console.Write |
输出不换行 | Console.Write("■"); |
绘制图形 |
Console.ReadLine |
读取一行输入 | 返回string |
需要输入文本 |
Console.ReadKey |
读取单个按键 | Console.ReadKey(true).KeyChar |
true隐藏输入 |
Console.SetCursorPosition |
设置光标位置 | SetCursorPosition(x, y) |
指定位置绘制 |
Console.ForegroundColor |
设置文字颜色 | ConsoleColor.Red |
不同元素不同色 |
Console.BackgroundColor |
设置背景颜色 | ConsoleColor.White |
需配合Clear生效 |
Environment.Exit |
退出程序 | Environment.Exit(0); |
退出游戏 |
坐标系统:原点在左上角(0,0),X向右增加,Y向下增加,■占2个字符宽度,1y ≈ 2x(视觉上)。
随机数生成
// 创建随机数对象
Random r = new Random();
// 生成随机数
r.Next(); // 非负随机数
r.Next(100); // 0-99(右不包含)
r.Next(5, 100); // 5-99(左包含右不包含)
思路:战斗系统中用r.Next(min, max+1)生成攻击力,+1是因为右边界不包含。
项目调试
| 快捷键 | 作用 | 使用场景 |
|---|---|---|
F9 |
打断点/取消断点 | 标记需要暂停的代码行 |
F11 |
逐语句执行 | 进入函数内部查看 |
F10 |
逐过程执行 | 跳过函数内部,直接看结果 |
F5 |
继续执行 | 跳到下一个断点 |
Shift+F5 |
停止调试 | 结束调试会话 |
思路:游戏逻辑复杂时,用断点调试跟踪玩家坐标、场景ID等关键变量。
项目概述
项目名称:营救公主控制台游戏
游戏流程:开始界面 → 游戏界面(移动、战斗、营救) → 结束界面
核心玩法:玩家控制角色移动,击败Boss后营救公主通关
各界面功能:
- 开始界面:显示游戏名 + 菜单(开始游戏/退出游戏)+ WS切换选项 + J确认
- 游戏界面:红墙围成的战斗区域,WASD控制移动,贴住Boss按J战斗,击败Boss后营救公主
- 结束界面:显示结果(通关/失败)+ 菜单(回到开始/退出游戏)
场景管理系统
核心思路:用switch+场景ID实现多场景,每个场景有自己的死循环。
int nowSceneID = 1; // 1开始 2游戏 3结束
while (true) // 游戏主循环
{
switch (nowSceneID)
{
case 1: // 开始场景
while (true)
{
// 绘制菜单 + 处理输入
// 按J后设置nowSceneID=2,break跳出本循环
}
break;
case 2: // 游戏场景
while (true) { ... }
break;
case 3: // 结束场景
while (true) { ... }
break;
}
}
关键点:通过修改nowSceneID实现场景切换,配合break跳出当前场景死循环。
开始场景实现
实现思路:
- 绘制标题和菜单选项
- 用
nowSelIndex记录当前选中项 - 选中项用红色高亮,其他白色
- 按J确认后修改
nowSceneID切换场景
int nowSelIndex = 0; // 0开始游戏 1退出
while (true)
{
// 绘制选项(选中项红色,其他白色)
Console.ForegroundColor = nowSelIndex == 0 ?
ConsoleColor.Red : ConsoleColor.White;
Console.Write("开始游戏");
// 处理输入
char input = Console.ReadKey(true).KeyChar;
switch (input)
{
case 'w': nowSelIndex = 0; break;
case 's': nowSelIndex = 1; break;
case 'j':
nowSceneID = nowSelIndex == 0 ? 2 : 退出;
break;
}
}
游戏场景 - 地图绘制
思路:用循环绘制红墙,只需绘制一次(放在游戏场景死循环外)
Console.ForegroundColor = ConsoleColor.Red;
// 横墙(i+=2因为■占2字符)
for (int i = 0; i < w; i += 2)
{
Console.SetCursorPosition(i, 0); // 上墙
Console.Write("■");
Console.SetCursorPosition(i, h - 1); // 下墙
Console.Write("■");
Console.SetCursorPosition(i, h - 6); // 中间墙
Console.Write("■");
}
// 竖墙
for (int i = 0; i < h; i++)
{
Console.SetCursorPosition(0, i); // 左墙
Console.Write("■");
Console.SetCursorPosition(w - 2, i); // 右墙
Console.Write("■");
}
游戏场景 - 玩家系统
属性定义:
int playerX = 4;
int playerY = 5;
int playerAtkMin = 8;
int playerAtkMax = 12;
int playerHp = 100;
string playerIcon = "●";
ConsoleColor playerColor = ConsoleColor.Yellow;
移动实现思路:擦除旧位置 → 计算新位置 → 边界/碰撞检测 → 绘制新位置
// 擦除旧位置
Console.SetCursorPosition(playerX, playerY);
Console.Write(" ");
// 根据输入移动
switch (input)
{
case 'w': playerY--; break;
case 's': playerY++; break;
case 'a': playerX -= 2; break; // ■占2字符
case 'd': playerX += 2; break;
}
// 边界检测(不能穿墙)
if (playerY < 1) playerY = 1;
if (playerY > h - 7) playerY = h - 7;
// Boss碰撞检测(活着时不能穿过)
if (playerX == bossX && playerY == bossY && bossHp > 0)
{
playerY++; // 拉回去
}
// 绘制新位置
Console.SetCursorPosition(playerX, playerY);
Console.Write(playerIcon);
游戏场景 - Boss系统
属性定义:
int bossX = 24;
int bossY = 15;
int bossAtkMin = 7;
int bossAtkMax = 13;
int bossHp = 100;
string bossIcon = "■";
ConsoleColor bossColor = ConsoleColor.Green;
绘制Boss(每帧绘制):
if (bossHp > 0) // Boss活着时才绘制
{
Console.SetCursorPosition(bossX, bossY);
Console.ForegroundColor = bossColor;
Console.Write(bossIcon);
}
游戏场景 - 战斗系统
思路:用isFight状态机管理,非战斗状态处理移动,战斗状态处理攻击
bool isFight = false; // 战斗状态标识
// 检测是否在Boss身边(上下左右一格)
bool nearBoss = (playerX == bossX && Math.Abs(playerY - bossY) == 1) ||
(playerY == bossY && Math.Abs(playerX - bossX) == 2);
// 非战斗状态下按J进入战斗
if (!isFight && input == 'j' && nearBoss && bossHp > 0)
{
isFight = true;
// 显示战斗信息
}
// 战斗状态下按J进行攻击
if (isFight && input == 'j')
{
// 玩家攻击Boss
int atk = r.Next(playerAtkMin, playerAtkMax);
bossHp -= atk;
// Boss反击(如果还活着)
if (bossHp > 0)
{
atk = r.Next(bossAtkMin, bossAtkMax);
playerHp -= atk;
}
// 判断胜负
if (playerHp <= 0) { /* 失败,切换场景 */ }
if (bossHp <= 0) { /* 胜利,退出战斗状态 */ }
}
游戏场景 - 公主营救
属性定义:
int princessX = 24;
int princessY = 5;
string princessIcon = "★";
ConsoleColor princessColor = ConsoleColor.Blue;
实现思路:Boss死亡后显示公主,走到公主身边按J通关
// Boss死亡时绘制公主
if (bossHp <= 0)
{
Console.SetCursorPosition(princessX, princessY);
Console.ForegroundColor = princessColor;
Console.Write(princessIcon);
}
// 玩家移动时增加公主碰撞检测
if (playerX == princessX && playerY == princessY && bossHp <= 0)
{
playerY++; // 不能穿过公主
}
// 在公主身边按J通关
if (input == 'j' && nearPrincess && bossHp <= 0)
{
nowSceneID = 3; // 切换到结束场景
gameOverInfo = "游戏通关";
break;
}
结束场景
实现思路:与开始场景类似,根据gameOverInfo显示不同结果
Console.SetCursorPosition(w / 2 - 4, 7);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(gameOverInfo); // "游戏通关"或"游戏失败"
// 选项:回到开始界面 / 退出游戏
// 选择"回到开始"设置nowSceneID=1
制作流程建议
- 控制台设置 → 隐藏光标、设置窗口大小
- 搭建场景框架 → 主循环 + switch + 场景ID
- 开始场景 → 标题 + 菜单 + 场景切换
- 游戏场景:
- 画红墙(循环)
- 添加玩家移动(擦除→移动→检测→绘制)
- 添加Boss(属性+绘制+碰撞)
- 添加战斗系统(状态机+随机数)
- 添加公主(通关条件)
- 结束场景 → 结果显示 + 选项
15.3 面试题精选
基础题
1. Random.Next 边界规则
题目
Random.Next(5, 10) 生成的随机数范围是多少?如果要生成 5 到 10(包含 10),应该怎么写?
深入解析
Random.Next(min, max) 是左包含右不包含,即 [min, max)。
Random.Next(5, 10) 生成 5、6、7、8、9,不包含 10。
要生成 5-10(包含 10):
int num = r.Next(5, 11); // 右边界 +1
游戏中的实际应用:
int atk = r.Next(8, 13); // 攻击力 8-12
答题示例
Next 是左闭右开,Next(5, 10) 生成 5 到 9。
想包含 10 就写 Next(5, 11)。
做游戏时经常用来生成攻击力范围,比如 8 到 12 就写 Next(8, 13)。
参考文章
- 2.必备知识点-随机数
2. 控制台坐标系统
题目
控制台坐标系的原点在哪里?为什么横向移动要 X+=2 而不是 X+=1?
深入解析
控制台坐标系:
- 原点在左上角 (0, 0)
- X 向右为正,Y 向下为正
横向移动要 X+=2 的原因:
- 中文字符(如 ■)占2 个字符宽度
- X+=1 会出现半个字符的错位
case 'd': playerX += 2; break; // 横向
case 's': playerY += 1; break; // 竖向
视觉上 1y ≈ 2x,所以控制台游戏看起来是「扁」的。
答题示例
原点在左上角,X 向右 Y 向下。
横向加 2 是因为中文字符比如方块符号占两个字符宽度,加 1 会错位。竖向加 1 就行。
视觉上 1 个 Y 大概等于 2 个 X,所以控制台游戏看起来是扁的。
参考文章
- 1.必备知识点-控制台相关方法
进阶题
1. 场景管理设计
题目
如何设计一个多场景的游戏系统?比如开始界面、游戏界面、结束界面之间的切换。
深入解析
核心思路:场景 ID + switch + 死循环
int nowSceneID = 1; // 1开始 2游戏 3结束
while (true) // 主循环
{
switch (nowSceneID)
{
case 1: // 开始场景
while (true) // 场景自己的循环
{
// 绘制菜单、处理输入
if (确认开始)
{
nowSceneID = 2;
break;
}
}
break;
case 2: // 游戏场景
// ...
break;
}
}
关键点:
- 用变量记录当前场景
- 每个场景有自己的循环
- 切换场景改 ID + break
答题示例
用场景 ID 配合 switch 管理。
主循环根据 ID 进入不同分支,每个场景有自己的死循环处理逻辑。
切换场景就改 ID 然后 break,下一轮主循环就进新场景了。
这样各场景逻辑隔离,扩展也方便。
参考文章
- 6.多个场景
2. 状态机实现战斗系统
题目
如何用状态机实现「移动」和「战斗」两种状态的切换?
深入解析
用布尔变量作为状态标识:
bool isFight = false;
while (true)
{
if (isFight)
{
// 战斗状态:只处理攻击
if (input == 'j')
{
// 攻击逻辑
if (bossHp <= 0)
isFight = false;
}
}
else
{
// 非战斗状态:处理移动
switch (input)
{
case 'w': playerY--; break;
case 'j':
if (在Boss身边)
isFight = true;
break;
}
}
}
状态机核心:变量记录状态 → 不同状态不同逻辑 → 条件触发切换。
答题示例
用一个布尔变量记录状态。
循环里根据变量走不同分支:true 时只处理攻击,false 时处理移动。
在 Boss 身边按 J 就设成 true 进入战斗,Boss 死了设回 false。
这就是最简单的状态机。
参考文章
- 11.游戏场景-玩家战斗相关
深度题
1. 项目制作思路
题目
如果让你从零开始制作这个营救公主的控制台游戏,你会怎么规划?
深入解析
项目概述:控制台回合制游戏,玩家移动、击败 Boss、营救公主通关。
模块划分:
- 控制台基础设置(光标、窗口大小)
- 场景管理(开始/游戏/结束三个场景)
- 游戏场景(地图、玩家、Boss、战斗、公主)
开发顺序:
- 控制台设置 → 隐藏光标、固定窗口
- 场景框架 → 主循环 + switch + ID
- 开始场景 → 菜单 + 选项切换
- 游戏场景:
- 画地图(循环绘制红墙)
- 玩家移动(擦除→移动→检测→绘制)
- Boss 系统(属性 + 绘制 + 碰撞)
- 战斗系统(状态机 + 随机攻击)
- 公主营救(通关条件)
- 结束场景 → 结果显示 + 重玩选项
关键技术点:
- 场景切换:ID + switch + break
- 移动逻辑:擦除旧位置 → 计算新位置 → 边界碰撞检测 → 绘制新位置
- 战斗系统:状态机 + 随机数
- 嵌套循环跳出:标识变量
难点与解决:
- 玩家不能穿过 Boss:移动后检测坐标重合,重合就拉回去
- 战斗时不能移动:用状态机隔离两种逻辑
- 嵌套循环跳出:用标识变量从 switch 里跳出外层 while
答题示例
先做控制台基础设置,隐藏光标固定窗口。
然后搭场景框架,用 ID 加 switch 管理三个场景。
游戏场景是核心,先画地图,再做玩家移动。移动的逻辑是擦除旧位置、算新位置、边界和碰撞检测、画新位置。
然后加 Boss 和战斗,战斗用状态机控制。
最后加公主做通关条件。
难点主要是碰撞检测和嵌套循环跳出,用坐标判断和标识变量解决。
参考文章
- 4.需求分析
- 5.控制台基础设置
- 6.多个场景
- 7.开始场景
- 8.游戏场景-不变的红墙
- 9.游戏场景-Boss相关
- 10.游戏场景-玩家移动相关
- 11.游戏场景-玩家战斗相关
- 12.游戏场景-公主相关
- 13.结束场景
- 14.代码汇总
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com