从零开发游戏需要学习的c#模块,第十五章(一个完整的可以运行的小游戏)
这是这个系列的最后一课,如果你认真学习了之前的内容,关于c#游戏开发要学习的代码就差不多了。今天我们来进行最后的收尾,往我们之前的代码中加入一个开幕界面,保证保存和加载内容正常运行。
只用修改game.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
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!;
private string saveFilePath = "gamesave.json";
// ===== ★ 入口 =====
public void Start()
{
Console.CursorVisible = false;
Console.Title = "控制台RPG";
// 显示主菜单
ShowMainMenu();
}
// ===== ★ 主菜单 =====
private void ShowMainMenu()
{
Console.Clear();
string title = @"
╔══════════════════════════╗
║ 🗡️ 控制台 RPG 🛡️ ║
╚══════════════════════════╝
";
Console.WriteLine(title);
Console.WriteLine(" [1] 新游戏");
Console.WriteLine(" [2] 继续游戏");
Console.WriteLine(" [3] 退出");
Console.Write("\n 请选择:");
bool hasSave = File.Exists(saveFilePath);
if (hasSave)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\n 📁 检测到存档文件");
Console.ResetColor();
}
while (true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.KeyChar)
{
case '1':
NewGame();
return;
case '2':
if (hasSave)
{
LoadAndStart();
return;
}
else
{
Console.SetCursorPosition(0, 9);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(" 没有存档文件!按任意键返回...");
Console.ResetColor();
Console.ReadKey(true);
ShowMainMenu();
return;
}
case '3':
return; // 直接退出程序
}
}
Thread.Sleep(30);
}
}
// ===== ★ 新游戏 =====
private void NewGame()
{
Console.Clear();
Console.Write("请输入你的名字:");
string name = Console.ReadLine();
if (string.IsNullOrWhiteSpace(name))
name = "勇者";
InitGame();
player = new Player(map.Width / 2, map.Height / 2);
player.Hp = player.MaxHp;
score = 0;
inventory = new Inventory();
Console.Clear();
Console.WriteLine("欢迎," + name + "!冒险开始了...");
Thread.Sleep(800);
RunGameLoop();
}
// ===== ★ 读档并开始 =====
private void LoadAndStart()
{
Console.Clear();
Console.WriteLine("正在读取存档...");
Thread.Sleep(500);
InitGame();
player = new Player(map.Width / 2, map.Height / 2);
if (!LoadGame())
{
Console.WriteLine("存档读取失败,开始新游戏...");
Thread.Sleep(1000);
player.Hp = player.MaxHp;
score = 0;
inventory = new Inventory();
}
RunGameLoop();
}
// ===== 初始化组件 =====
private void InitGame()
{
map = new GameMap(40, 20);
input = new InputHandler();
ui = new GameUI(map.Height);
battleManager = new BattleManager();
achievement = new AchievementSystem();
sound = new SoundSystem();
coins = new List<Coin>();
enemies = new List<Enemy>();
SpawnCoins(totalCoins);
SpawnEnemies(totalEnemies);
isRunning = true;
}
// ===== 游戏主循环 =====
private void RunGameLoop()
{
Console.Clear();
Console.CursorVisible = false;
map.Draw();
DrawAllStaticObjects();
while (isRunning && player.Hp > 0)
{
Update();
Render();
Thread.Sleep(30);
}
// 游戏结束自动存档
SaveGame();
Console.SetCursorPosition(0, map.Height + 4);
if (player.Hp <= 0)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("💀 你倒下了...游戏结束。");
Console.ResetColor();
}
else
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("游戏结束!进度已保存。");
Console.ResetColor();
}
Console.WriteLine("按任意键返回主菜单...");
Console.ReadKey(true);
ShowMainMenu(); // 返回主菜单
}
// ===== 存档 =====
private void SaveGame()
{
try
{
GameSaveData data = new GameSaveData
{
PlayerX = player.X,
PlayerY = player.Y,
PlayerHp = player.Hp,
PlayerMaxHp = player.MaxHp,
Score = score,
InventoryItems = inventory.GetAllItems()
};
string json = JsonSerializer.Serialize(data);
File.WriteAllText(saveFilePath, json);
}
catch { }
}
// ===== 读档(返回 true 表示成功)=====
private bool LoadGame()
{
if (!File.Exists(saveFilePath)) return false;
try
{
string json = File.ReadAllText(saveFilePath);
GameSaveData? data = JsonSerializer.Deserialize<GameSaveData>(json);
if (data == null) return false;
player.X = data.PlayerX;
player.Y = data.PlayerY;
player.Hp = data.PlayerHp;
score = data.Score;
inventory = new Inventory();
if (data.InventoryItems != null)
{
foreach (string item in data.InventoryItems)
inventory.AddItemSilent(item);
}
coins.Clear();
enemies.Clear();
SpawnCoins(totalCoins);
SpawnEnemies(totalEnemies);
return true;
}
catch
{
return false;
}
}
// ===== 以下不变 ===== 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.Save: SaveGame(); ShowSaveMessage(); break; case InputHandler.Command.Load: LoadGame(); ShowLoadMessage(); break; case InputHandler.Command.Quit: isRunning = false; break; } CheckCoinCollision(); CheckEnemyCollision(); if (GetActiveCoinCount() == 0) SpawnCoins(totalCoins); if (GetActiveEnemyCount() == 0) SpawnEnemies(totalEnemies); } private void ShowSaveMessage() { Console.SetCursorPosition(2, map.Height + 3); Console.Write(new string(' ', 30)); Console.SetCursorPosition(2, map.Height + 3); Console.ForegroundColor = ConsoleColor.Green; Console.Write("✅ 已保存!"); Console.ResetColor(); } private void ShowLoadMessage() { Console.SetCursorPosition(2, map.Height + 3); Console.Write(new string(' ', 30)); Console.SetCursorPosition(2, map.Height + 3); Console.ForegroundColor = ConsoleColor.Cyan; Console.Write("📂 已加载!"); Console.ResetColor(); } 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); } } }