C#控制台应用-勇者斗恶龙

 

从零开发《勇者斗恶龙》控制台游戏的逻辑拆解


第一步:搭建基础框架

目标 :创建窗口和基础循环 怎么做

  1. 添加类成员
// 定义场景类型
enum Scene { startScene, gameScene, endScene };

// 窗口大小
static int windowHeight = 30;
static int windowWidth = 50;

// 界面选项数量
static int startIndexCount = 3;
static int endIndexCount = 2;

// 当前场景
static Scene scene;
// 是否获胜
static bool isWin = false;
// 用于生成伤害随机数,避免重复创造实例
static Random random = new Random();
  1. 初始化控制台窗口大小,隐藏光标:

    // 隐藏光标
    Console.CursorVisible = false;
    // 设置窗口大小
    Console.SetWindowSize(windowWidth, windowHeight);
    Console.SetBufferSize(windowWidth, windowHeight);
    
  2. 定义场景枚举(开始、游戏、结束):

    enum Scene { startScene, gameScene, endScene };
    
  3. 主循环通过 switch 切换场景:

    while (true)
    {
        // 场景切换
        switch (scene)
        {
            // 切换到开始场景
            case Scene.startScene:StartScene();break;
            // 切换到游戏场景
            case Scene.gameScene:GameScene();break;
            // 切换到结束场景
            case Scene.endScene:EndScene();break;
        }
    }
    

    作用 :建立游戏运行的基本骨架,确保场景能切换。


第二步:实现开始界面

目标 :让玩家选择开始游戏或退出 怎么做

  1. 清空控制台并显示标题:

    // 清空原场景
    Console.Clear();
    // 设置光标位置,打印标题
    Console.SetCursorPosition(windowWidth / 2 - 5, 3);
    Console.ForegroundColor = ConsoleColor.White;
    Console.Write("勇者斗恶龙");
    
  2. 用循环监听 W/S 键移动选项,J 键确认:

    int nowSetIndex = 0;
    // 处于开始场景
    while (scene == Scene.startScene)
    {
        // 显示选项,二则选项用三目运算符简化
        Console.SetCursorPosition(windowWidth / 2 - 4, 6);
        Console.ForegroundColor = (nowSetIndex == 0) ? ConsoleColor.Red : ConsoleColor.White;
        Console.Write("开始游戏");
        Console.SetCursorPosition(windowWidth / 2 - 4, 9);
        Console.ForegroundColor = (nowSetIndex == 1) ? ConsoleColor.Red : ConsoleColor.White;
        Console.Write("假的设置");
        Console.SetCursorPosition(windowWidth / 2 - 4, 12);
        Console.ForegroundColor = (nowSetIndex == 2) ? ConsoleColor.Red : ConsoleColor.White;
        Console.Write("退出游戏");
       
        // 获取输入
        char input = Console.ReadKey(true).KeyChar;
        switch (input)
        {
            case 'w':
            case 'W':
                // 两个选项直接赋值,没必要加减 导致增加不必要的判断,如果是多个,则加减取模.
                // 从0开始,向下移动是加,向上是减
                nowSetIndex = (nowSetIndex - 1 + startIndexCount) % startIndexCount;
                break;
            case 'S':
            case 's':
                nowSetIndex = (nowSetIndex + 1) % startIndexCount;
                break;
            // 确认
            case 'j':
            case 'J':
                // 开始游戏
                if (nowSetIndex == 0)
                {
                    // 改变场景,退出循环
                    scene = Scene.gameScene;
                }
                else if (nowSetIndex == 2)
                {
                    Environment.Exit(0);
                }
                break;
        }
    }
    

    作用 :实现菜单交互,玩家可以进入游戏或退出。


第三步:设计游戏对象

目标 :定义玩家、Boss、奖励的共同行为 怎么做

  1. 创建 GameObject 基类(位置、图标、绘制/擦除方法):

    public class GameObject
    {
        // 基础属性(所有对象共有)
        public int X { get; set; }
        public int Y { get; set; }
        public string Icon { get; set; }
        public ConsoleColor Color { get; set; }
       
        // 构造函数
        public GameObject(int x, int y, string icon, ConsoleColor color)
        {
            X = x;
            Y = y;
            Icon = icon;
            Color = color;
        }
       
        // 绘制方法
        public virtual void Draw()
        {
            Console.ForegroundColor = Color;
            Console.SetCursorPosition(X, Y);
            Console.Write(Icon);
        }
       
        // 擦除方法
        public virtual void Erase()
        {
            Console.SetCursorPosition(X, Y);
            Console.Write("  "); // 擦除占两个字符的位置
        }
       
        // 碰撞检测(静态工具方法)
        public static bool CheckCollision(GameObject a, GameObject b)
        {
            return Math.Abs(a.X - b.X) <= 2 &&
                   Math.Abs(a.Y - b.Y) <= 1;
        }
    }
    
  2. 继承基类实现 Character(添加血量、攻击等属性):

    public class Character : GameObject
    {
        // 战斗属性(Boss/Player共有)
        public int HP { get; set; }
        public int DEF { get; set; }
        public int MinATK { get; set; }
        public int MaxATK { get; set; }
       
        // 构造函数
        public Character(int x, int y, string icon, ConsoleColor color,
            int hp, int def, int minATK, int maxATK)
            : base(x, y, icon, color)
        {
            HP = hp;
            DEF = def;
            MinATK = minATK;
            MaxATK = maxATK;
        }
       
        /// <summary>
        /// 攻击方法
        /// </summary>
        /// <param name="random">随机实例</param>
        /// <param name="character">攻击的对象</param>
        /// <returns>造成的最终伤害</returns>
        public int Attack(Random random, Character character)
        {
            return random.Next(MinATK, MaxATK + 1) - character.DEF;
        }
       
        // 受击方法
        public void TakeDamage(int damage)
        {
            HP -= Math.Max(damage, 0);
        }
    }
    

    作用 :统一管理游戏中的可交互元素。


第四步:实现游戏场景

目标 :让玩家移动、战斗、触发事件 怎么做

  1. 绘制地图 :用 字符画墙:
// 方块占两个字符的位置
// 上 中 下 三行
for (int i = 0; i < windowWidth; i += 2)
{
    Console.SetCursorPosition(i, 0);
    Console.Write("■");
    Console.SetCursorPosition(i, windowHeight - 6);
    Console.Write("■");
    Console.SetCursorPosition(i, windowHeight - 1);
    Console.Write("■");
}
// 左 和 右 
// 如果设置光标位置后打印字符串,会从该位置开始覆盖,所以重复的方块会覆盖而不是上中下三行各多两个
for (int i = 0; i < windowHeight; i++)
{
    Console.SetCursorPosition(0, i);
    Console.Write("■");
    Console.SetCursorPosition(windowWidth - 2, i);
    Console.Write("■");
}
  1. 初始化角色
Character boss = new Character(16, 16, "▲", ConsoleColor.Green, 100, 5, 10, 15);
Character player = new Character(4, 4, "★", ConsoleColor.Blue, 100, 4, 9, 20);
  1. 处理移动输入
// 擦除上个位置的玩家
player.Erase();
switch (playerInput)
{
    case 'W':
    case 'w':
        player.Y--;
        // 上边界
        if (player.Y < 1)
        {
            player.Y = 1;
        }
        else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
        {
            // 回到贴着的位置
            player.Y++;
        }
        else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
        {
            // 回到贴着的位置
            player.Y++;
        }
        break;
    case 'A':
    case 'a':
        player.X -= 2;
        // 左边界
        if (player.X < 2)
        {
            player.X = 2;
        }
        else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
        {
            // 回到贴着的位置
            player.X += 2;
        }
        else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
        {
            // 回到贴着的位置
            player.X += 2;
        }
        break;
    case 'S':
    case 's':
        player.Y++;
        // 中间墙 在 windowHeight - 6
        if (player.Y > windowHeight - 7)
        {
            player.Y = windowHeight - 7;
        }
        else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
        {
            // 回到贴着的位置
            player.Y--;
        }
        else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
        {
            // 回到贴着的位置
            player.Y--;
        }
        break;
    case 'D':
    case 'd':
        player.X += 2;
        // 右边界
        if (player.X > windowWidth - 4)
        {
            player.X = windowWidth - 4;
        }
        else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
        {
            // 回到贴着的位置
            player.X -= 2;
        }
        else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
        {
            // 回到贴着的位置
            player.X -= 2;
        }
        break;
    case 'J':
    case 'j':
        // 如果靠近BOSS 开始战斗
        if (GameObject.CheckCollision(player,boss) && boss.HP > 0)
        {
            isFight = true;
            //可以开始战斗
            Console.SetCursorPosition(2, windowHeight - 5);
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("开始和Boss战斗了,按J键继续");
            Console.SetCursorPosition(2, windowHeight - 4);
            Console.Write("玩家当前血量为{0}", player.HP);
            Console.SetCursorPosition(2, windowHeight - 3);
            Console.Write("boss当前血量为{0}", boss.HP);
        }
        // 是否在奖励身边
        else if (GameObject.CheckCollision(player, boss) && boss.HP <= 0)
        {
            // 切换到结束界面
            scene = Scene.endScene;
            // 获得奖励
            break;
            
        }
        break;
}
  1. 战斗逻辑 :回合制互相攻击:
if (isFight)
{
    //如果是战斗状态 只处理J键 
    if (playerInput == 'J' || playerInput == 'j')
    {
        // 玩家或者怪物 是否死亡 
        if (player.HP <= 0)
        {
            //游戏结束
            scene = Scene.endScene;
            break;
        }
        else if (boss.HP <= 0)
        {
            // 战斗胜利 boss擦除
            boss.Erase();
            isFight = false;
        }
        else
        {
            // 玩家打怪物
            int damage = player.Attack(random,boss);
            boss.TakeDamage(damage);

            Console.ForegroundColor = ConsoleColor.Green;
            // 先擦除这一行 上次显示的内容
            Console.SetCursorPosition(2, windowHeight - 4);
            Console.Write(new string(' ', windowWidth - 4));
            // 再写新的信息
            Console.SetCursorPosition(2, windowHeight - 4);
            Console.Write("你对boss造成了{0}点伤害,boss剩余血量为{1}", damage, boss.HP);

            // 怪物打玩家
            if (boss.HP > 0)
            {
                damage = boss.Attack(random,player) ;
                player.TakeDamage(damage);

                Console.ForegroundColor = ConsoleColor.Yellow;
                //先擦除这一行 上次显示的内容
                Console.SetCursorPosition(2, windowHeight - 3);
                Console.Write(new string(' ', windowWidth - 4));
                // 再写新的信息
                // 如果boss把玩家打死
                if (player.HP <= 0)
                {
                    Console.SetCursorPosition(2, windowHeight - 3);
                    Console.Write("很遗憾,你未能通过boss的试炼,战败了");
                }
                else
                {
                    Console.SetCursorPosition(2, windowHeight - 3);
                    Console.Write("boss对你造成了{0}点伤害,你的剩余血量为{1}", damage, player.HP);
                }
            }
            else
            {
                isWin = true;
                // 擦除之前的战斗信息 ,如果写信息的地方宽度不够,信息可能会连在一起,比如两行攻击信息显示在同一行,而第三行信息不会刷新,得加宽hhhh
                Console.SetCursorPosition(2, windowHeight - 5);
                Console.Write(new string(' ', windowWidth - 4));

                Console.SetCursorPosition(2, windowHeight - 4);
                Console.Write(new string(' ', windowWidth - 4));

                Console.SetCursorPosition(2, windowHeight - 3);
                Console.Write(new string(' ', windowWidth-4));

                // 显示胜利的信息
                Console.SetCursorPosition(2, windowHeight - 5);
                Console.Write("你战胜了boss,快去领取奖励吧。按J继续");
                Console.SetCursorPosition(2, windowHeight - 4);
                Console.Write("前往奖励旁边按J键继续");
            }
        }
    }        Console.Write("前往奖励旁边按J键继续");
            }
        }
    }
}

作用 :实现核心玩法,玩家可以探索地图并与敌人交互。


第五步:处理结束场景

目标 :显示游戏结果并提供选项 怎么做

  1. 根据胜负显示不同文本:

    if (isWin)
    {
        Console.ForegroundColor = ConsoleColor.White;
        Console.SetCursorPosition(windowWidth / 2 - 8, 3);
        Console.WriteLine("恭喜你完成了游戏。");
    }
    
  2. 监听玩家选择“重玩”或“退出”:

    // 获取输入
    char input = Console.ReadKey(true).KeyChar;
    switch (input)
    {
        case 'w':
        case 'W':
            nowSetIndex = (nowSetIndex - 1 + endIndexCount) % endIndexCount;
            break;
        case 'S':
        case 's':
            nowSetIndex = (nowSetIndex + 1) % endIndexCount;
            break;
        // 确认
        case 'j':
        case 'J':
            // 开始游戏
            if (nowSetIndex == 0)
            {
                // 改变场景,退出循环
                scene = Scene.startScene;
            }
            else if (nowSetIndex == 1)
            {
                Environment.Exit(0);
            }
            break;
    }
    

    作用 :提供游戏结束后的闭环体验。


开发中的关键问题与解决

  1. 全角字符对齐问题

    • 现象 移动时错位
    • 解决 :确保角色的 X 坐标为偶数(玩家.X = (x % 2 == 0) ? x : x-1;
  2. 战斗信息覆盖

    • 现象 :多行文字重叠
    • 解决 :用空格清空旧内容:
    Console.SetCursorPosition(2, 窗口高度-5);
    Console.Write(new string(' ', 40)); // 清空40个字符宽度
    
  3. 随机数重复生成

    • 现象 :伤害值不随机
    • 解决 :全局共享一个 Random 实例:
    static Random random = new Random();
    
  4. 场景切换残留

    • 现象 :切换场景后画面残留
    • 解决 :每次切换场景前调用 Console.Clear()

总结

开发顺序:搭框架 → 做界面 → 实现对象 → 写交互 → 处理细节 关键技巧:

  • Console.SetCursorPosition 控制输出位置
  • 通过 Console.ReadKey(true) 隐藏输入回显
  • 全屏字符绘制时注意坐标对齐

代码总览

Program.cs

using System;
using System.Diagnostics;
using System.Numerics;

namespace IntroductionProject
{
    class Program
    {
        // 定义场景类型
        enum Scene { startScene, gameScene, endScene };

        // 窗口大小
        static int windowHeight = 30;
        static int windowWidth = 50;

        // 界面选项数量
        static int startIndexCount = 3;
        static int endIndexCount = 2;

        // 当前场景
        static Scene scene;
        // 是否获胜
        static bool isWin = false;
        // 用于生成伤害随机数,避免重复创造实例
        static Random random = new Random();

        static void Main(string[] args)
        {
            // 隐藏光标
            Console.CursorVisible = false;
            // 设置窗口大小
            Console.SetWindowSize(windowWidth, windowHeight);
            Console.SetBufferSize(windowWidth, windowHeight);

            scene = Scene.startScene;
            while (true)
            {
                // 场景切换
                switch (scene)
                {
                    // 切换到开始场景
                    case Scene.startScene:StartScene();break;
                    // 切换到游戏场景
                    case Scene.gameScene:GameScene();break;
                    // 切换到结束场景
                    case Scene.endScene:EndScene();break;
                }
            }
        }

        /// <summary>
        /// 开始场景
        /// </summary>
        static void StartScene()
        {
            // 清空原场景
            Console.Clear();
            // 设置光标位置,打印标题
            Console.SetCursorPosition(windowWidth / 2 - 5, 3);
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("勇者斗恶龙");
            int nowSetIndex = 0;
            // 处于开始场景
            while (scene == Scene.startScene)
            {
                // 显示选项,二则选项用三目运算符简化
                Console.SetCursorPosition(windowWidth / 2 - 4, 6);
                Console.ForegroundColor = (nowSetIndex == 0) ? ConsoleColor.Red : ConsoleColor.White;
                Console.Write("开始游戏");
                Console.SetCursorPosition(windowWidth / 2 - 4, 9);
                Console.ForegroundColor = (nowSetIndex == 1) ? ConsoleColor.Red : ConsoleColor.White;
                Console.Write("假的设置");
                Console.SetCursorPosition(windowWidth / 2 - 4, 12);
                Console.ForegroundColor = (nowSetIndex == 2) ? ConsoleColor.Red : ConsoleColor.White;
                Console.Write("退出游戏");

                // 获取输入
                char input = Console.ReadKey(true).KeyChar;
                switch (input)
                {
                    case 'w':
                    case 'W':
                        // 两个选项直接赋值,没必要加减 导致增加不必要的判断,如果是多个,则加减取模.
                        // 从0开始,向下移动是加,向上是减
                        nowSetIndex = (nowSetIndex - 1 + startIndexCount) % startIndexCount;
                        break;
                    case 'S':
                    case 's':
                        nowSetIndex = (nowSetIndex + 1) % startIndexCount;
                        break;
                    // 确认
                    case 'j':
                    case 'J':
                        // 开始游戏
                        if (nowSetIndex == 0)
                        {
                            // 改变场景,退出循环
                            scene = Scene.gameScene;
                        }
                        else if (nowSetIndex == 2)
                        {
                            Environment.Exit(0);
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// 游戏场景
        /// </summary>
        static void GameScene()
        {
            // 重置状态
            isWin = false;
            // 清空原场景
            Console.Clear();
            // 设置墙体颜色
            Console.ForegroundColor = ConsoleColor.Red;

            // 画墙 windowHeight  windowWidth 
            // 方块占两个字符的位置
            // 上 中 下 三行
            for (int i = 0; i < windowWidth; i += 2)
            {
                Console.SetCursorPosition(i, 0);
                Console.Write("■");
                Console.SetCursorPosition(i, windowHeight - 6);
                Console.Write("■");
                Console.SetCursorPosition(i, windowHeight - 1);
                Console.Write("■");
            }
            // 左 和 右 
            // 如果设置光标位置后打印字符串,会从该位置开始覆盖,所以重复的方块会覆盖而不是上中下三行各多两个
            for (int i = 0; i < windowHeight; i++)
            {
                Console.SetCursorPosition(0, i);
                Console.Write("■");
                Console.SetCursorPosition(windowWidth - 2, i);
                Console.Write("■");
            }

            // 让我回忆起了曾经这样写程序算崩三小游戏夏活那个战斗的胜率,还因为给樱闪避的数值填错导致算错了,其他倒是没问题
            // 因为特殊字符占两个字符的位置,01是一个字符的开头和结束,所以横坐标位置应该是偶数,23,45应该在2和4的位置
            // 初始化游戏对象
            Character boss = new Character(16, 16, "▲", ConsoleColor.Green, 100, 5, 10, 15);
            Character player = new Character(4, 4, "★", ConsoleColor.Blue, 100, 4, 9, 20);
            GameObject reward = new GameObject(10, 10, "☆", ConsoleColor.White);
            // 玩家输入标识
            char playerInput;

            // 是否是战斗状态
            bool isFight = false;

            // 处于游戏场景
            while (scene == Scene.gameScene)
            {
                // 绘制BOSS
                if (boss.HP > 0)
                {
                    boss.Draw();
                }
                else
                {
                    // 绘制奖励
                    reward.Draw();
                }
                // 绘制玩家
                player.Draw();

                // 接收玩家输入,并且隐藏输入文本
                playerInput = Console.ReadKey(true).KeyChar;

                if (isFight)
                {
                    //如果是战斗状态 只处理J键 
                    if (playerInput == 'J' || playerInput == 'j')
                    {
                        // 玩家或者怪物 是否死亡 
                        if (player.HP <= 0)
                        {
                            //游戏结束
                            scene = Scene.endScene;
                            break;
                        }
                        else if (boss.HP <= 0)
                        {
                            // 战斗胜利 boss擦除
                            boss.Erase();
                            isFight = false;
                        }
                        else
                        {
                            // 玩家打怪物
                            int damage = player.Attack(random,boss);
                            boss.TakeDamage(damage);

                            Console.ForegroundColor = ConsoleColor.Green;
                            // 先擦除这一行 上次显示的内容
                            Console.SetCursorPosition(2, windowHeight - 4);
                            Console.Write(new string(' ', windowWidth - 4));
                            // 再写新的信息
                            Console.SetCursorPosition(2, windowHeight - 4);
                            Console.Write("你对boss造成了{0}点伤害,boss剩余血量为{1}", damage, boss.HP);

                            // 怪物打玩家
                            if (boss.HP > 0)
                            {
                                damage = boss.Attack(random,player) ;
                                player.TakeDamage(damage);

                                Console.ForegroundColor = ConsoleColor.Yellow;
                                //先擦除这一行 上次显示的内容
                                Console.SetCursorPosition(2, windowHeight - 3);
                                Console.Write(new string(' ', windowWidth - 4));
                                // 再写新的信息
                                // 如果boss把玩家打死
                                if (player.HP <= 0)
                                {
                                    Console.SetCursorPosition(2, windowHeight - 3);
                                    Console.Write("很遗憾,你未能通过boss的试炼,战败了");
                                }
                                else
                                {
                                    Console.SetCursorPosition(2, windowHeight - 3);
                                    Console.Write("boss对你造成了{0}点伤害,你的剩余血量为{1}", damage, player.HP);
                                }
                            }
                            else
                            {
                                isWin = true;
                                // 擦除之前的战斗信息 ,如果写信息的地方宽度不够,信息可能会连在一起,比如两行攻击信息显示在同一行,而第三行信息不会刷新,得加宽hhhh
                                Console.SetCursorPosition(2, windowHeight - 5);
                                Console.Write(new string(' ', windowWidth - 4));

                                Console.SetCursorPosition(2, windowHeight - 4);
                                Console.Write(new string(' ', windowWidth - 4));

                                Console.SetCursorPosition(2, windowHeight - 3);
                                Console.Write(new string(' ', windowWidth-4));

                                // 显示胜利的信息
                                Console.SetCursorPosition(2, windowHeight - 5);
                                Console.Write("你战胜了boss,快去领取奖励吧。按J继续");
                                Console.SetCursorPosition(2, windowHeight - 4);
                                Console.Write("前往奖励旁边按J键继续");
                            }
                        }
                    }
                }
                else
                {
                    // 擦除上个位置的玩家
                    player.Erase();
                    switch (playerInput)
                    {
                        case 'W':
                        case 'w':
                            player.Y--;
                            // 上边界
                            if (player.Y < 1)
                            {
                                player.Y = 1;
                            }
                            else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
                            {
                                // 回到贴着的位置
                                player.Y++;
                            }
                            else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
                            {
                                // 回到贴着的位置
                                player.Y++;
                            }
                            break;
                        case 'A':
                        case 'a':
                            player.X -= 2;
                            // 左边界
                            if (player.X < 2)
                            {
                                player.X = 2;
                            }
                            else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
                            {
                                // 回到贴着的位置
                                player.X += 2;
                            }
                            else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
                            {
                                // 回到贴着的位置
                                player.X += 2;
                            }
                            break;
                        case 'S':
                        case 's':
                            player.Y++;
                            // 中间墙 在 windowHeight - 6
                            if (player.Y > windowHeight - 7)
                            {
                                player.Y = windowHeight - 7;
                            }
                            else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
                            {
                                // 回到贴着的位置
                                player.Y--;
                            }
                            else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
                            {
                                // 回到贴着的位置
                                player.Y--;
                            }
                            break;
                        case 'D':
                        case 'd':
                            player.X += 2;
                            // 右边界
                            if (player.X > windowWidth - 4)
                            {
                                player.X = windowWidth - 4;
                            }
                            else if (player.X == boss.X && player.Y == boss.Y && boss.HP > 0)
                            {
                                // 回到贴着的位置
                                player.X -= 2;
                            }
                            else if (player.X == reward.X && player.Y == reward.Y && boss.HP <= 0)
                            {
                                // 回到贴着的位置
                                player.X -= 2;
                            }
                            break;
                        case 'J':
                        case 'j':
                            // 如果靠近BOSS 开始战斗
                            if (GameObject.CheckCollision(player,boss) && boss.HP > 0)
                            {
                                isFight = true;
                                //可以开始战斗
                                Console.SetCursorPosition(2, windowHeight - 5);
                                Console.ForegroundColor = ConsoleColor.White;
                                Console.Write("开始和Boss战斗了,按J键继续");
                                Console.SetCursorPosition(2, windowHeight - 4);
                                Console.Write("玩家当前血量为{0}", player.HP);
                                Console.SetCursorPosition(2, windowHeight - 3);
                                Console.Write("boss当前血量为{0}", boss.HP);
                            }
                            // 是否在奖励身边
                            else if (GameObject.CheckCollision(player, reward) && boss.HP <= 0)
                            {
                                // 切换到结束界面
                                scene = Scene.endScene;
                                // 获得奖励
                                break;
                                
                            }
                            break;
                    }

                }

            }
        }



        /// <summary>
        /// 结束场景
        /// </summary>
        static void EndScene()
        {
            // 清空原场景
            Console.Clear();
            int nowSetIndex = 0;
            while (scene == Scene.endScene)
            {
                if (isWin)
                {
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.SetCursorPosition(windowWidth / 2 - 8, 3);
                    Console.WriteLine("恭喜你完成了游戏。");
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.SetCursorPosition(windowWidth / 2 - 8, 3);
                    Console.WriteLine("很遗憾你失败了。");
                }
                // 显示选项,二则选项用三目运算符简化
                Console.SetCursorPosition(windowWidth / 2 - 5, 6);
                Console.ForegroundColor = (nowSetIndex == 0) ? ConsoleColor.Red : ConsoleColor.White;
                Console.Write("回到主界面");
                Console.SetCursorPosition(windowWidth / 2 - 4, 9);
                Console.ForegroundColor = (nowSetIndex == 1) ? ConsoleColor.Red : ConsoleColor.White;
                Console.Write("退出游戏");

                // 获取输入
                char input = Console.ReadKey(true).KeyChar;
                switch (input)
                {
                    case 'w':
                    case 'W':
                        // 两个选项直接赋值,没必要加减 导致增加不必要的判断,如果是多个,则加减取模.
                        // 从0开始,向下移动是加,向上是减
                        nowSetIndex = (nowSetIndex - 1 + endIndexCount) % endIndexCount;
                        break;
                    case 'S':
                    case 's':
                        nowSetIndex = (nowSetIndex + 1) % endIndexCount;
                        break;
                    // 确认
                    case 'j':
                    case 'J':
                        // 开始游戏
                        if (nowSetIndex == 0)
                        {
                            // 改变场景,退出循环
                            scene = Scene.startScene;
                        }
                        else if (nowSetIndex == 1)
                        {
                            Environment.Exit(0);
                        }
                        break;
                }
            }
            
        }

    }
}

GameObject.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IntroductionProject
{
    public class GameObject
    {
        // 基础属性(所有对象共有)
        public int X { get; set; }
        public int Y { get; set; }
        public string Icon { get; set; }
        public ConsoleColor Color { get; set; }

        // 构造函数
        public GameObject(int x, int y, string icon, ConsoleColor color)
        {
            X = x;
            Y = y;
            Icon = icon;
            Color = color;
        }

        // 绘制方法
        public virtual void Draw()
        {
            Console.ForegroundColor = Color;
            Console.SetCursorPosition(X, Y);
            Console.Write(Icon);
        }

        // 擦除方法
        public virtual void Erase()
        {
            Console.SetCursorPosition(X, Y);
            Console.Write("  "); // 擦除占两个字符的位置
        }

        // 碰撞检测(静态工具方法)
        public static bool CheckCollision(GameObject a, GameObject b)
        {
            return Math.Abs(a.X - b.X) <= 2 &&
                   Math.Abs(a.Y - b.Y) <= 1;
        }
    }

}

Character.cs