上一章我们在我们的小游戏中加入了金币和背包,这一节课我们来往里面加入怪物,来丰富我们的小游戏
统一你的Enemy和Slime类
第一步:更新Enemy.cs
把Enemy.cs完整替换为以下代码。注意看,它保留了事件系统,但数据结构改成了属性。
using System; namespace MyGame { class Enemy { public string Name { get; set; } public int Hp { get; set; } public int AttackPower { get; set; } public string DropItem { get; set; } // 地图坐标(新增) public int X { get; set; } public int Y { get; set; } public bool IsActive { get; set; } // 事件:死亡时触发 public event Action<Enemy> OnEnemyKilled; public Enemy() { } // 无参构造函数,备用 public Enemy(string name, int hp, int attack, string drop) { Name = name; Hp = hp; AttackPower = attack; DropItem = drop; IsActive = true; } // 受伤逻辑 public virtual void TakeDamage(int damage) { Hp = Hp - damage; Console.WriteLine(Name + " 受到了 " + damage + " 点伤害!剩余HP:" + Hp); if (Hp <= 0) { Die(); } } // 死亡 protected virtual void Die() { Console.WriteLine(Name + " 被消灭了!"); IsActive = false; // 触发死亡事件 OnEnemyKilled?.Invoke(this); } // 攻击(虚方法,子类可重写) public virtual void Attack() { Console.WriteLine(Name + " 发动攻击,造成 " + AttackPower + " 点伤害!"); } } }第二步:更新Slime.cs
using System; namespace MyGame { class Slime : Enemy { public Slime() { } // 无参构造函数 public Slime(string name, int hp, int attack, string drop) : base(name, hp, attack, drop) { } // 史莱姆特有的攻击方式 public override void Attack() { Console.WriteLine(Name + " 跳起来砸向你!造成 " + AttackPower + " 点伤害。"); } // 死亡时特定表现 protected override void Die() { Console.WriteLine(Name + " 化为一滩液体..."); IsActive = false; OnEnemyKilled?.Invoke(this); } } }第三步:创建战斗管理器BattleManager.cs
战斗管理器负责回合制战斗流程。玩家碰到敌人后,战斗管理器接管控制,打完之后再回到地图模式。
using System;
namespace MyGame
{
class BattleManager
{
// 执行一场战斗,返回 true 表示玩家胜利
public bool StartBattle(Player player, Enemy enemy)
{
Console.Clear();
Console.WriteLine("========================================");
Console.WriteLine(" ⚔️ 遭遇了 " + enemy.Name + "! ⚔️");
Console.WriteLine("========================================\n");
int round = 1;
// 回合制战斗循环
while (player.Hp > 0 && enemy.Hp > 0)
{
Console.WriteLine("--- 第 " + round + " 回合 ---");
// 玩家攻击
Console.Write("你攻击! ");
enemy.TakeDamage(player.AttackPower);
if (enemy.Hp <= 0)
{
Console.WriteLine("\n🏆 你击败了 " + enemy.Name + "!");
Console.WriteLine("敌人掉落了:" + enemy.DropItem);
Console.WriteLine("\n按任意键继续冒险...");
Console.ReadKey(true);
return true; // 玩家赢
}
// 敌人反击
Console.Write(enemy.Name + " 反击! ");
enemy.Attack();
player.TakeDamage(enemy.AttackPower);
if (player.Hp <= 0)
{
Console.WriteLine("\n💀 你被 " + enemy.Name + " 打败了...");
Console.WriteLine("\n按任意键结束游戏...");
Console.ReadKey(true);
return false; // 玩家输
}
Console.WriteLine(); // 空行分隔回合
round++;
}
return false;
}
}
}
第四步:改造Player.cs,加入战斗属性
给你的Player.cs加上血量和攻击力。把原来的Player.cs完整替换为:
using System; namespace MyGame { class Player { public int X { get; set; } public int Y { get; set; } public char Symbol { get; private set; } public ConsoleColor Color { get; private set; } // 战斗属性(新增) public int Hp { get; set; } public int MaxHp { get; private set; } public int AttackPower { get; set; } private int previousX; private int previousY; public Player(int startX, int startY) { X = startX; Y = startY; previousX = X; previousY = Y; Symbol = '@'; Color = ConsoleColor.Yellow; // 初始战斗属性 MaxHp = 100; Hp = MaxHp; AttackPower = 15; } public void SavePosition() { previousX = X; previousY = Y; } public void EraseOld() { Console.SetCursorPosition(previousX, previousY); Console.Write(" "); } public void Draw() { Console.SetCursorPosition(X, Y); Console.ForegroundColor = Color; Console.Write(Symbol); Console.ResetColor(); } public void Move(int dx, int dy, int minX, int minY, int maxX, int maxY) { SavePosition(); int newX = X + dx; int newY = Y + dy; if (newX >= minX && newX <= maxX && newY >= minY && newY <= maxY) { X = newX; Y = newY; } } // 玩家受伤 public void TakeDamage(int damage) { Hp = Hp - damage; Console.WriteLine("你受到了 " + damage + " 点伤害!剩余血量:" + Hp); } // 治疗 public void Heal(int amount) { Hp = Hp + amount; if (Hp > MaxHp) Hp = MaxHp; Console.WriteLine("你恢复了 " + amount + " 点血量。当前血量:" + Hp); } } }第五步:把一切串起来 —— 改造Game.cs
这是最核心的一步。把Game.cs完整替换为以下代码:
using System;
using System.Collections.Generic;
using System.Threading;
namespace MyGame
{
class Game
{
private static Game? instance;
public static Game Instance
{
get
{
if (instance == null)
instance = new Game();
return instance;
}
}
private Game() { }
private bool isRunning;
private Player player = default!;
private GameMap map = default!;
private InputHandler input = default!;
private GameUI ui = default!;
private BattleManager battleManager = default!;
// 金币相关
private List<Coin> coins = default!;
private int score;
private int totalCoins = 5;
// 敌人相关(新增)
private List<Enemy> enemies = default!;
private int totalEnemies = 3;
// 背包与系统(新增)
private Inventory inventory = default!;
private AchievementSystem achievement = default!;
private SoundSystem sound = default!;
public void Start()
{
Console.CursorVisible = false;
Console.Title = "控制台RPG - 方向键移动,ESC退出";
map = new GameMap(40, 20);
player = new Player(map.Width / 2, map.Height / 2);
input = new InputHandler();
ui = new GameUI(map.Height);
battleManager = new BattleManager();
isRunning = true;
score = 0;
// 初始化背包和系统
inventory = new Inventory();
achievement = new AchievementSystem();
sound = new SoundSystem();
// 初始化金币
coins = new List<Coin>();
SpawnCoins(totalCoins);
// 初始化敌人
enemies = new List<Enemy>();
SpawnEnemies(totalEnemies);
// 首次绘制地图
map.Draw();
DrawAllStaticObjects();
// 主循环
while (isRunning && player.Hp > 0)
{
Update();
Render();
Thread.Sleep(30);
}
// 游戏结束
Console.SetCursorPosition(0, map.Height + 4);
if (player.Hp <= 0)
{
Console.WriteLine("你倒下了...游戏结束。");
}
else
{
Console.WriteLine("游戏结束!感谢游玩。");
}
Console.WriteLine("按任意键退出...");
Console.ReadKey();
}
// ===== 生成 =====
private void SpawnCoins(int count)
{
Random rng = new Random();
for (int i = 0; i < count; i++)
{
int x = rng.Next(1, map.Width - 1);
int y = rng.Next(1, map.Height - 1);
coins.Add(new Coin(x, y));
}
}
private void SpawnEnemies(int count)
{
Random rng = new Random();
for (int i = 1; i <= count; i++)
{
int x = rng.Next(1, map.Width - 1);
int y = rng.Next(1, map.Height - 1);
Slime slime = new Slime("绿色史莱姆" + i, 25 + i * 5, 6 + i, "史莱姆粘液");
slime.X = x;
slime.Y = y;
slime.IsActive = true;
// ★ 把各个系统挂载到敌人事件上
slime.OnEnemyKilled += achievement.OnEnemyKilled;
slime.OnEnemyKilled += sound.OnEnemyKilled;
// 死亡时掉落物品
slime.OnEnemyKilled += (Enemy e) =>
{
inventory.AddItem(e.DropItem);
};
enemies.Add(slime);
}
}
// 绘制所有静态对象(地图和初始金币、敌人)
private void DrawAllStaticObjects()
{
foreach (Coin coin in coins)
coin.Draw();
foreach (Enemy enemy in enemies)
DrawEnemy(enemy);
}
private void DrawEnemy(Enemy enemy)
{
if (!enemy.IsActive) return;
Console.SetCursorPosition(enemy.X, enemy.Y);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("S");
Console.ResetColor();
}
private void EraseEnemy(Enemy enemy)
{
Console.SetCursorPosition(enemy.X, enemy.Y);
Console.Write(" ");
}
// ===== 更新逻辑 =====
private void Update()
{
InputHandler.Command cmd = input.GetCommand();
switch (cmd)
{
case InputHandler.Command.MoveUp:
player.Move(0, -1, 1, 1, map.Width - 2, map.Height - 2);
break;
case InputHandler.Command.MoveDown:
player.Move(0, 1, 1, 1, map.Width - 2, map.Height - 2);
break;
case InputHandler.Command.MoveLeft:
player.Move(-1, 0, 1, 1, map.Width - 2, map.Height - 2);
break;
case InputHandler.Command.MoveRight:
player.Move(1, 0, 1, 1, map.Width - 2, map.Height - 2);
break;
case InputHandler.Command.Quit:
isRunning = false;
break;
}
// 检测金币碰撞
CheckCoinCollision();
// 检测敌人碰撞
CheckEnemyCollision();
// 金币捡完了就刷新
if (GetActiveCoinCount() == 0)
SpawnCoins(totalCoins);
// 敌人都打完了就刷新
if (GetActiveEnemyCount() == 0)
SpawnEnemies(totalEnemies);
}
// 金币碰撞
private void CheckCoinCollision()
{
foreach (Coin coin in coins)
{
if (coin.IsActive && coin.X == player.X && coin.Y == player.Y)
{
coin.IsActive = false;
coin.Erase();
score += coin.Value;
inventory.AddItem("金币");
}
}
}
// 敌人碰撞
private void CheckEnemyCollision()
{
foreach (Enemy enemy in enemies)
{
if (enemy.IsActive && enemy.X == player.X && enemy.Y == player.Y)
{
// 碰到敌人!先擦除这个敌人
EraseEnemy(enemy);
// 进入战斗
bool win = battleManager.StartBattle(player, enemy);
if (!win)
{
isRunning = false; // 玩家死了,退出游戏
return;
}
// 战斗胜利后,敌人消失,重新绘制地图
Console.Clear();
map.Draw();
DrawAllStaticObjects();
}
}
}
private int GetActiveCoinCount()
{
int count = 0;
foreach (Coin coin in coins)
if (coin.IsActive) count++;
return count;
}
private int GetActiveEnemyCount()
{
int count = 0;
foreach (Enemy enemy in enemies)
if (enemy.IsActive) count++;
return count;
}
// ===== 渲染 =====
private void Render()
{
player.EraseOld();
player.Draw();
ui.Draw(score, GetActiveCoinCount(), inventory.ItemCount, player.Hp, player.MaxHp);
}
}
}
第六步:微调 UI
using System;
namespace MyGame
{
class GameUI
{
private int uiLine;
public GameUI(int mapHeight)
{
uiLine = mapHeight + 1;
}
public void Draw(int score, int coinCount, int bagCount, int hp, int maxHp)
{
// 清空 UI 行
Console.SetCursorPosition(0, uiLine);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(0, uiLine + 1);
Console.Write(new string(' ', Console.WindowWidth));
// 分数
Console.SetCursorPosition(2, uiLine);
Console.ForegroundColor = ConsoleColor.White;
Console.Write($"mark 分数:{score}");
// 金币
Console.SetCursorPosition(18, uiLine);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write($"coin 金币:{coinCount}");
// 背包
Console.SetCursorPosition(34, uiLine);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write($"bag 背包:{bagCount}");
// 血量
Console.SetCursorPosition(50, uiLine);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write($"heart HP:{hp}/{maxHp}");
Console.ResetColor();
}
}
}
同时确认Inventory.cs有一个公开属性ItemCount:、
最后的运行结果,可以对照一下
地图上:黄色
@(玩家)、黄色$(金币)、红色S(史莱姆)走到
$上:金币消失,分数+10,背包增加“金币”走到
S上:屏幕清空,进入回合制战斗战斗中:你打一下,史莱姆打一下,直到一方倒下
战斗胜利:回到地图,史莱姆消失,背包获得掉落物,成就和音效系统触发
金币/敌人清空后:自动刷新,游戏无限进行
按 ESC:退出游戏
好了,今天的课到此结束,如果有报错或者什么问题,请在评论区留言,我每天都会看。关注我,下一期更精彩。