如何在XML中保存对象实例的引用

3

编辑:已经得到了答案。我将玩家的清单Inv更改为整数列表,并在游戏初始加载时将物品导入字典中,如下所示:

public static class InitLoad
{
    static List<ItemEquipmentWeapon> weapons;

    public static Dictionary<int, Item> ItemIDList = new Dictionary<int, Item>();

    public static void PreLoading()
    {

        string path, filePath, 
            weaponFile = @"\WeaponsItem.aid";
        XmlSerializer SerializerObj;
        FileStream ReadFileStream;

        path = string.Format(@"{0}\AwesomeRPG\Data\Items",
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
        filePath = string.Format(@"{0}\{1}", path, weaponFile);
        SerializerObj = new XmlSerializer(typeof(ItemEquipmentWeapon));
        ReadFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        weapons = (List<ItemEquipmentWeapon>)SerializerObj.Deserialize(ReadFileStream);
        foreach (Item item in weapons)
        {
            ItemIDList.Add(item.ID, item);
        }
    }
}

意思是我可以使用我的player类来完成这个任务:
[Serializable()]
public class Player : Entity
{
    public string Name { get; set; }
    public int MaxHP { get; set; }
    public int Level { get; set; }
    public int XP { get; set; }
    public int Str { get; set; }
    public int End { get; set; }
    public int Dex { get; set; }
    public int Agi { get; set; }
    public int Wis { get; set; }
    public int Int { get; set; }
    //Create a list of Item Id's for inventory
    public List<int> Inv { get; set; }

    private int lHand;
    private int rHand;

    public int LHand
    {
        get 
        { return lHand; }
        set
        {
            if (!value.THand)
            {
                lHand = value;
            }
            else lHand = null;
        }
    }
    public int RHand
    {
        get 
        { return rHand; }
        set 
        { rHand = value; }
    }

    internal Player() { }
    public Player(string name, int maxhp, int hp, int lvl, int exp, int str, int end, int dex, int agi, int wis, int inte)
        : base(true, hp)
    {
        Name = name;
        MaxHP = maxhp;
        Level = lvl;
        XP = exp;
        Str = str;
        End = end;
        Dex = dex;
        Agi = agi;
        Wis = wis;
        Int = inte;

        Inv = new List<int>();
    }

    public List<string> GetInv()
    {
        List<string> val = new List<string>();
        Item item;
        foreach (int i in Inv)
        {
            InitLoad.ItemIDList.TryGetValue(i, out item);
            val.Add(item.Name);
        }

        return val;
    }

    public void AddItem(Item i, int amt)
    {
        for (int j = 0; j < amt; j++)
        {
            Inv.Add(i.ID);
        }
    }
    public void AddItem(Item i){
        AddItem(i, 1); }

    public void RemoveItem(Item i, int amt)
    {
        int count = 0;

        foreach (int item in Inv)
        {
            if (item == i.ID)
            {
                Inv.Remove(item);
                count++;
            }
            if (count == amt)
            {
                break;
            }
        }
    }
    public void RemoveItem(Item i){
        RemoveItem(i, 1); }

    public bool HasItem(Item i, int amt)
    {
        int count = 0;

        foreach (int item in Inv)
        {
            if (item == i.ID)
            {
                count++;
            }
        }

        return count >= amt;
    }
    public bool HasItem(Item i){
        return HasItem(i, 1); }
}

希望这可以帮助其他人!
原始问题:
所以,我正在制作一个愚蠢的小RPG游戏,使用窗体来测试我的技能,并且我正在解决保存问题。目前它保存到一个XML文件中,自定义扩展名为(.asd)。这是我的保存/加载代码:
public static class SaveGame
{
    public static void Save(Player player)
    {
        string myfile = string.Format(@"{1}\AwesomeRPG\Saves\{0}Save.asd", player.Name, Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
        //Delete file if it already exists
        if (File.Exists(myfile)) System.IO.File.Delete(myfile);
        //Create/Write to the file
        FileStream outFile = File.Create(myfile);            
        XmlSerializer Serializer = new XmlSerializer(typeof(Player));
        Serializer.Serialize(outFile, player);
        outFile.Close();
    }

    public static Player Load(string FileName)
    {
        string myfile = string.Format(@"{1}\AwesomeRPG\Saves\{0}Save.asd", FileName, Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

        if (!File.Exists(myfile)) return null;
        XmlSerializer Serializer = new XmlSerializer(typeof(Player));
        FileStream ReadFileStream = new FileStream(myfile, FileMode.Open, FileAccess.Read, FileShare.Read);
        return (Player)Serializer.Deserialize(ReadFileStream);
    }
}

正如您所想象的那样,这将保存Inv列表中任何项目的所有详细信息。 但是,我希望所有存在的项目在游戏启动时都能被加载(创建它们的实例),并且我需要一种方法让保存文件保留对这些实例的引用,而不是创建新实例。

游戏启动时加载的实例也包含在XML文件中,然后根据项目类型加载到单独的列表中,例如所有ItemEquipmentWeapon实例(继承ItemEquipment,后者继承Item)都在WeaponItem.aid文件中,该文件以XML格式存储,并加载到List中。

是否有任何方法可以通过引用将Inv内容保存并从玩家保存文件中加载,以便可以使用在初始加载期间设置的现有实例?

编辑: 突然想到,让一些人看看Player类的编码可能有所帮助,所以在此提供:

[Serializable()]
public class Player : Entity
{
    public string Name { get; set; }
    public int MaxHP { get; set; }
    public int Level { get; set; }
    public int XP { get; set; }
    public int Str { get; set; }
    public int End { get; set; }
    public int Dex { get; set; }
    public int Agi { get; set; }
    public int Wis { get; set; }
    public int Int { get; set; }

    public List<Item> Inv { get; set; }

    private ItemEquipmentWeapon lHand;
    private ItemEquipmentWeapon rHand;

    public ItemEquipmentWeapon LHand
    {
        get 
        { return lHand; }
        set
        {
            if (!value.THand)
            {
                lHand = value;
            }
            else lHand = null;
        }
    }
    public ItemEquipmentWeapon RHand
    {
        get 
        { return rHand; }
        set 
        { rHand = value; }
    }

    internal Player() { }
    public Player(string name, int maxhp, int hp, int lvl, int exp, int str, int end, int dex, int agi, int wis, int inte)
        : base(true, hp)
    {
        Name = name;
        MaxHP = maxhp;
        Level = lvl;
        XP = exp;
        Str = str;
        End = end;
        Dex = dex;
        Agi = agi;
        Wis = wis;
        Int = inte;

        Inv = new List<Item>();
    }

    public List<string> GetInv()
    {
        List<string> val = new List<string>();

        foreach (Item item in Inv)
        {
            val.Add(item.Name);
        }

        return val;
    }

    public void AddItem(Item i, int amt)
    {
        for (int j = 0; j < amt; j++)
        {
            Inv.Add(i);
        }
    }
    public void AddItem(Item i){
        AddItem(i, 1); }

    public void RemoveItem(Item i, int amt)
    {
        int count = 0;

        foreach (Item item in Inv)
        {
            if (item == i)
            {
                Inv.Remove(item);
                count++;
            }
            if (count == amt)
            {
                break;
            }
        }
    }
    public void RemoveItem(Item i){
        RemoveItem(i, 1); }

    public bool HasItem(Item i, int amt)
    {
        int count = 0;

        foreach (Item item in Inv)
        {
            if (item == i)
            {
                count++;
            }
        }

        return count >= amt;
    }
    public bool HasItem(Item i){
        return HasItem(i, 1); }
}

显然,从XML加载物品实例的代码在游戏加载时也非常有用,但我尚未编写该代码,我不确定如何去做。

到目前为止,我有这个:

public static class InitLoad
{
    static List<ItemEquipmentWeapon> weapons;

    public static void PreLoading()
    {
        string path, filePath, 
            weaponFile = @"\WeaponsItem.aid";
        XmlSerializer SerializerObj;
        FileStream ReadFileStream;

        path = string.Format(@"{0}\AwesomeRPG\Data\Items",
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

        filePath = string.Format(@"{0}\{1}", path, weaponFile);
        SerializerObj = new XmlSerializer(typeof(ItemEquipmentWeapon));
        ReadFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        weapons = (List<ItemEquipmentWeapon>)SerializerObj.Deserialize(ReadFileStream);
    }
}

非常感谢您的帮助!


请查看类似问题的这个答案,可能会对您有所帮助 https://dev59.com/FXI-5IYBdhLWcg3w6dC1#1617566 - Honza Brestan
1个回答

2
有没有办法通过引用将 Inv 内容保存和加载到玩家保存文件中,以便在初始加载期间使用现有实例设置? 解决此问题的一种方法如下:
1. 在你的 Item 类中添加 int 字段 Id 或类似的内容,并为每个唯一的项分配适当的唯一值。
2. 在初始加载期间创建全局缓存,其中包含游戏中所有唯一的项目。 为此,我建议使用 Dictionary,其中键是项目的 Id,值是项目本身。
3. 在你的 Player 类中,你应该只存储项目的 ID,因此在加载期间,你可以从前面提到的全局缓存中获取 Item 的实例。
此外,你可能想阅读关于 Flyweight 模式的文章,它与共享实例非常相关。

哦,对于玩家类中的GetInv方法,我该如何将字典从InitLoad传递给该类,以便它可以通过ID查找物品的名称? - Mayube
@user3033160,理想情况下,您不应该将该字典传递给您的Player.GetInv方法。'Global'意味着它应该从程序中的任何地方访问,因此您可能希望使用Singleton模式或将该字典声明为公共的public static Dictionary<int, Item> ItemsCache。之后,您可以按如下方式从Player.GetInv方法访问它:foreach(int id in Ids) { val.Add(InitLoad.ItemsCache[id].Name); } - Yurii
是的,我在InitLoad.cs的类范围内将其设置为公共静态。 因为该类位于Lib项目中,而其他两个项目都引用了Lib,现在它对我的所有代码都是可访问的,尽管在Lib之外不太需要。非常感谢您的帮助! - Mayube

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接