从零开发游戏需要学习的c#模块,第九章(保存与加载)
你辛辛苦苦打了半天史莱姆,攒了一背包东西。关掉程序再打开——什么都没了。因为到目前为止,所有数据都只存在于内存里,断电就消失。
我们需要把数据保存到硬盘上,下次启动时再读回来。这就是序列化(把对象变成可以存储的格式)和文件读写(把数据写入硬盘文件)。
我们今天要学习的内容是,保存与加载,序列化与文件。
1. 什么是序列化?
你要把一辆乐高车寄给远方的朋友。你不能直接把拼好的车塞进信封,而是拆成零件,列个清单,装进盒子。朋友收到后,按照清单重新拼装。
-
序列化:把对象拆成可传输/存储的格式(如 JSON 字符串)
-
反序列化:把 JSON 字符串重新组装成对象
JSON 是什么?
JSON 是一种用纯文本表示数据的格式,人和机器都能轻松读懂。
{
"name": "绿色史莱姆",
"hp": 30,
"attackPower": 5
}
2. 把史莱姆变成 JSON 字符串
C# 提供了内置的 JSON 序列化工具 System.Text.Json。
第一步,在文件最上面引入命名空间:
using System.Text.Json;
第二步,给要序列化的类加一个标记(只有 public 属性会被序列化):
我们现在把 Slime 类改造一下,使用属性而不是字段(因为 JSON 序列化需要属性):
using System;
using System.Text.Json;
namespace MyGame
{
class Slime
{
public string Name { get; set; }
public int Hp { get; set; }
public int AttackPower { get; set; }
public string DropItem { get; set; }
public Slime() { } // 无参构造函数,反序列化时需要
public Slime(string name, int hp, int attack, string drop)
{
Name = name;
Hp = hp;
AttackPower = attack;
DropItem = drop;
}
public void ShowInfo()
{
Console.WriteLine($" {Name} | HP:{Hp} | 攻击:{AttackPower} | 掉落:{DropItem}");
}
}
}
第三步,序列化一个史莱姆对象:
// 创建一个史莱姆
Slime slime = new Slime("绿色史莱姆", 30, 5, "史莱姆粘液");
// 序列化成 JSON 字符串
string jsonString = JsonSerializer.Serialize(slime);
Console.WriteLine(jsonString);
// 输出:{"Name":"绿色史莱姆","Hp":30,"AttackPower":5,"DropItem":"史莱姆粘液"}
第四步,反序列化——从 JSON 字符串变回对象:
string savedJson = "{\"Name\":\"蓝色史莱姆\",\"Hp\":20,\"AttackPower\":8,\"DropItem\":\"蓝色碎片\"}";
Slime loadedSlime = JsonSerializer.Deserialize<Slime>(savedJson);
loadedSlime.ShowInfo();
// 输出:蓝色史莱姆 | HP:20 | 攻击:8 | 掉落:蓝色碎片
3. 把数据写入文件(保存)
文件读写的核心类在 System.IO 命名空间里。
using System.IO;
// ...
string filePath = "save.txt";
// 1. 创建要保存的数据
Slime mySlime = new Slime("黄金史莱姆", 50, 12, "金币");
// 2. 序列化成 JSON
string json = JsonSerializer.Serialize(mySlime);
// 3. 写入文件
File.WriteAllText(filePath, json);
Console.WriteLine("保存成功!文件路径:" + filePath);
运行后,你的项目文件夹里会多一个 save.txt,打开就能看到 JSON 内容。
4. 从文件读取数据(加载)
string filePath = "save.txt";
// 1. 检查文件是否存在
if (File.Exists(filePath))
{
// 2. 读取文件内容
string json = File.ReadAllText(filePath);
// 3. 反序列化成对象
Slime loadedSlime = JsonSerializer.Deserialize<Slime>(json);
loadedSlime.ShowInfo();
}
else
{
Console.WriteLine("存档文件不存在!");
}
5. 保存一个列表(多个对象)
游戏里你需要保存整队敌人或整个背包,这需要序列化列表。
// 创建一个敌人列表
List<Slime> slimes = new List<Slime>
{
new Slime("红色史莱姆", 40, 10, "火焰碎片"),
new Slime("蓝色史莱姆", 25, 6, "冰霜碎片"),
new Slime("绿色史莱姆", 30, 5, "史莱姆粘液")
};
// 序列化整个列表
string json = JsonSerializer.Serialize(slimes);
File.WriteAllText("slimes.json", json);
Console.WriteLine("敌人列表已保存!");
// 读取列表
string loadedJson = File.ReadAllText("slimes.json");
List<Slime> loadedSlimes = JsonSerializer.Deserialize<List<Slime>>(loadedJson);
Console.WriteLine("\n读取到的敌人列表:");
foreach (Slime s in loadedSlimes)
{
s.ShowInfo();
}
6. 实战:可存档的背包系统
让我运用本节课所学知识,来升级一下我们的背包系统
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace MyGame
{
class Inventory
{
private List<string> items;
private string savePath = "inventory.json";
public Inventory()
{
items = new List<string>();
}
public void AddItem(string itemName)
{
items.Add(itemName);
Console.WriteLine("获得物品:" + itemName);
}
public void RemoveItem(string itemName)
{
if (items.Contains(itemName))
{
items.Remove(itemName);
Console.WriteLine("失去了物品:" + itemName);
}
else
{
Console.WriteLine("背包里没有" + itemName + "!");
}
}
public void ShowInventory()
{
Console.WriteLine("\n=== 当前背包 ===");
if (items.Count == 0)
{
Console.WriteLine("(空)");
}
else
{
for (int i = 0; i < items.Count; i++)
{
Console.WriteLine(" [" + (i + 1) + "] " + items[i]);
}
}
Console.WriteLine("总物品数:" + items.Count);
}
// ★ 保存到文件
public void Save()
{
string json = JsonSerializer.Serialize(items);
File.WriteAllText(savePath, json);
Console.WriteLine("背包已保存!");
}
// ★ 从文件加载
public void Load()
{
if (File.Exists(savePath))
{
string json = File.ReadAllText(savePath);
items = JsonSerializer.Deserialize<List<string>>(json);
Console.WriteLine("背包已加载!");
}
else
{
Console.WriteLine("没有找到存档,使用空背包。");
}
}
}
}

7. 保存整个游戏状态
真实游戏中,你需要保存的不只是背包,而是一个完整的游戏存档。我们来创建一个 GameSaveData 类:
using System.Collections.Generic;
namespace MyGame
{
// 这个类专门用来保存游戏状态
class GameSaveData
{
public string PlayerName { get; set; }
public int PlayerHp { get; set; }
public int PlayerLevel { get; set; }
public List<string> InventoryItems { get; set; }
public int SlimeKillCount { get; set; }
}
}
在 Program.cs 中使用:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace MyGame
{
class Program
{
static string savePath = "gamesave.json";
static void Main(string[] args)
{
Console.WriteLine("1. 新游戏");
Console.WriteLine("2. 继续游戏");
Console.Write("请选择:");
string choice = Console.ReadLine();
GameSaveData data;
if (choice == "2" && File.Exists(savePath))
{
// 加载存档
string json = File.ReadAllText(savePath);
data = JsonSerializer.Deserialize<GameSaveData>(json);
Console.WriteLine("\n存档已加载!欢迎回来," + data.PlayerName + "!\n");
}
else
{
// 新建存档
data = new GameSaveData
{
PlayerName = "勇者",
PlayerHp = 100,
PlayerLevel = 1,
InventoryItems = new List<string> { "木剑", "生命药水" },
SlimeKillCount = 0
};
Console.WriteLine("\n新冒险开始!\n");
}
// 显示状态
ShowStatus(data);
// 模拟一些游戏过程
Console.WriteLine("\n--- 你打了一只史莱姆 ---");
data.SlimeKillCount++;
data.InventoryItems.Add("史莱姆粘液");
ShowStatus(data);
// 保存
string saveJson = JsonSerializer.Serialize(data);
File.WriteAllText(savePath, saveJson);
Console.WriteLine("\n游戏已保存!");
Console.ReadKey();
}
static void ShowStatus(GameSaveData data)
{
Console.WriteLine("=== 角色状态 ===");
Console.WriteLine("姓名:" + data.PlayerName);
Console.WriteLine("血量:" + data.PlayerHp);
Console.WriteLine("等级:" + data.PlayerLevel);
Console.WriteLine("击杀数:" + data.SlimeKillCount);
Console.Write("背包:");
foreach (string item in data.InventoryItems)
{
Console.Write(item + " ");
}
Console.WriteLine();
}
}
}
好了,这节课我们学习的知识点较多,我们来总结一下
| 对象→JSON字符串 | JsonSerializer.Serialize(obj) |
| JSON字符串→对象 | JsonSerializer.Deserialize<类型>(json) |
| 写入文件 | File.WriteAllText(路径, 内容) |
| 读取文件 | File.ReadAllText(路径) |
| 检查文件是否存在 |
|
今天的学习就到这里,关注我,下期更精彩。
更多推荐
所有评论(0)