这一章我们来讲一下如何在我们的小游戏中加入保存和加载的功能,让我们的游戏有记忆
第一步:完善 GameSaveData.cs
using System.Collections.Generic;
namespace MyGame
{
class GameSaveData
{
public int PlayerX { get; set; }
public int PlayerY { get; set; }
public int PlayerHp { get; set; }
public int PlayerMaxHp { get; set; }
public int Score { get; set; }
public List<string> InventoryItems { get; set; } = new List<string>();
}
}
这里存了所有需要恢复的游戏状态:玩家位置、血量、分数、背包。
第二步:给 InputHandler.cs 加 S 和 L 键
打开 InputHandler.cs,在 Command 枚举和 GetCommand 方法里加上存档和读档。
using System;
namespace MyGame
{
class InputHandler
{
public enum Command
{
None,
MoveUp,
MoveDown,
MoveLeft,
MoveRight,
Save, // ★ 新增
Load, // ★ 新增
Quit
}
public Command GetCommand()
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.UpArrow: return Command.MoveUp;
case ConsoleKey.DownArrow: return Command.MoveDown;
case ConsoleKey.LeftArrow: return Command.MoveLeft;
case ConsoleKey.RightArrow: return Command.MoveRight;
case ConsoleKey.S: return Command.Save; // ★ S 键存档
case ConsoleKey.L: return Command.Load; // ★ L 键读档
case ConsoleKey.Escape: return Command.Quit;
}
}
return Command.None;
}
}
}
第三步:在 Game.cs 里加入存档和读档逻辑
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 - WASD移动,S存档 L读档,ESC退出";
map = new GameMap(40, 20);
input = new InputHandler();
ui = new GameUI(map.Height);
battleManager = new BattleManager();
achievement = new AchievementSystem();
sound = new SoundSystem();
// ★ 检查是否有存档
bool loaded = TryLoadGame();
if (!loaded)
{
// 新游戏:用默认值初始化
player = new Player(map.Width / 2, map.Height / 2);
inventory = new Inventory();
score = 0;
coins = new List<Coin>();
enemies = new List<Enemy>();
}
isRunning = true;
// 初始化地图内容(金币和敌人)
if (coins.Count == 0)
SpawnCoins(totalCoins);
if (enemies.Count == 0)
SpawnEnemies(totalEnemies);
map.Draw();
DrawAllStaticObjects();
// 主循环
while (isRunning && player.Hp > 0)
{
Update();
Render();
Thread.Sleep(30);
}
// ★ 游戏结束自动存档
if (player.Hp > 0)
{
SaveGame();
}
Console.SetCursorPosition(0, map.Height + 4);
if (player.Hp <= 0)
{
Console.WriteLine("你倒下了...游戏结束。存档已保留,可加载重来。");
}
else
{
Console.WriteLine("游戏结束!感谢游玩。");
}
Console.WriteLine("按任意键退出...");
Console.ReadKey();
}
// ===== ★ 保存游戏 =====
private void SaveGame()
{
GameSaveData data = new GameSaveData
{
PlayerX = player.X,
PlayerY = player.Y,
PlayerHp = player.Hp,
PlayerMaxHp = player.MaxHp,
Score = score,
InventoryItems = inventory.GetAllItems() // 需要在 Inventory 里加这个方法
};
string json = JsonSerializer.Serialize(data);
File.WriteAllText(saveFilePath, json);
// 在 UI 上显示保存成功
Console.SetCursorPosition(0, map.Height + 3);
Console.Write(new string(' ', Console.WindowWidth));
Console.SetCursorPosition(2, map.Height + 3);
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("✅ 游戏已保存!");
Console.ResetColor();
}
// ===== ★ 加载游戏 =====
private bool TryLoadGame()
{
if (!File.Exists(saveFilePath))
{
Console.WriteLine("没有找到存档,开始新游戏。");
return false;
}
// 读取 JSON
string json = File.ReadAllText(saveFilePath);
GameSaveData? data = JsonSerializer.Deserialize<GameSaveData>(json);
if (data == null)
{
Console.WriteLine("存档损坏,开始新游戏。");
return false;
}
// 用存档数据恢复游戏状态
player = new Player(data.PlayerX, data.PlayerY);
player.Hp = data.PlayerHp;
// MaxHp 通过构造函数设定,如需恢复请给 Player 加 SetMaxHp 方法
score = data.Score;
inventory = new Inventory();
foreach (string item in data.InventoryItems)
{
inventory.AddItemSilent(item); // 需要在 Inventory 里加静默添加方法
}
coins = new List<Coin>();
enemies = new List<Enemy>();
Console.WriteLine("存档已加载!欢迎回来!");
return true;
}
// ===== 生成 =====
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();
break;
case InputHandler.Command.Load: // ★ 读档
LoadGameFromKey();
break;
case InputHandler.Command.Quit:
isRunning = false;
break;
}
CheckCoinCollision();
CheckEnemyCollision();
if (GetActiveCoinCount() == 0)
SpawnCoins(totalCoins);
if (GetActiveEnemyCount() == 0)
SpawnEnemies(totalEnemies);
}
// ★ 按键读档
private void LoadGameFromKey()
{
Console.Clear();
bool loaded = TryLoadGame();
if (loaded)
{
map.Draw();
DrawAllStaticObjects();
}
}
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);
}
}
}
第四步:给 Inventory.cs 加两个新方法
cs
// 静默添加(不打印"获得物品"),用于加载存档时批量恢复背包
public void AddItemSilent(string itemName)
{
items.Add(itemName);
}
// 获取所有物品列表,用于存档
public List<string> GetAllItems()
{
return new List<string>(items); // 返回副本,保护原始数据
}
好了,关于游戏的代码部分我们已经完成了很多了,下一章我们将会使用unity制作可以真正的2d游戏。关注我,下期更精彩!