15.C#入门实践项目总结

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跳出当前场景死循环。

开始场景实现

实现思路

  1. 绘制标题和菜单选项
  2. nowSelIndex记录当前选中项
  3. 选中项用红色高亮,其他白色
  4. 按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

制作流程建议

  1. 控制台设置 → 隐藏光标、设置窗口大小
  2. 搭建场景框架 → 主循环 + switch + 场景ID
  3. 开始场景 → 标题 + 菜单 + 场景切换
  4. 游戏场景
    • 画红墙(循环)
    • 添加玩家移动(擦除→移动→检测→绘制)
    • 添加Boss(属性+绘制+碰撞)
    • 添加战斗系统(状态机+随机数)
    • 添加公主(通关条件)
  5. 结束场景 → 结果显示 + 选项

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、营救公主通关。

模块划分

  1. 控制台基础设置(光标、窗口大小)
  2. 场景管理(开始/游戏/结束三个场景)
  3. 游戏场景(地图、玩家、Boss、战斗、公主)

开发顺序

  1. 控制台设置 → 隐藏光标、固定窗口
  2. 场景框架 → 主循环 + switch + ID
  3. 开始场景 → 菜单 + 选项切换
  4. 游戏场景:
    • 画地图(循环绘制红墙)
    • 玩家移动(擦除→移动→检测→绘制)
    • Boss 系统(属性 + 绘制 + 碰撞)
    • 战斗系统(状态机 + 随机攻击)
    • 公主营救(通关条件)
  5. 结束场景 → 结果显示 + 重玩选项

关键技术点

  • 场景切换:ID + switch + break
  • 移动逻辑:擦除旧位置 → 计算新位置 → 边界碰撞检测 → 绘制新位置
  • 战斗系统:状态机 + 随机数
  • 嵌套循环跳出:标识变量

难点与解决

  • 玩家不能穿过 Boss:移动后检测坐标重合,重合就拉回去
  • 战斗时不能移动:用状态机隔离两种逻辑
  • 嵌套循环跳出:用标识变量从 switch 里跳出外层 while
答题示例

先做控制台基础设置,隐藏光标固定窗口。

然后搭场景框架,用 ID 加 switch 管理三个场景。

游戏场景是核心,先画地图,再做玩家移动。移动的逻辑是擦除旧位置、算新位置、边界和碰撞检测、画新位置。

然后加 Boss 和战斗,战斗用状态机控制。

最后加公主做通关条件。

难点主要是碰撞检测和嵌套循环跳出,用坐标判断和标识变量解决。

参考文章
  • 4.需求分析
  • 5.控制台基础设置
  • 6.多个场景
  • 7.开始场景
  • 8.游戏场景-不变的红墙
  • 9.游戏场景-Boss相关
  • 10.游戏场景-玩家移动相关
  • 11.游戏场景-玩家战斗相关
  • 12.游戏场景-公主相关
  • 13.结束场景
  • 14.代码汇总


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏