在关卡选择屏幕、XML、XNA 上保存和加载数据

Posted

技术标签:

【中文标题】在关卡选择屏幕、XML、XNA 上保存和加载数据【英文标题】:Saving & loading data on level selection screen, XML, XNA 【发布时间】:2014-06-24 16:34:23 【问题描述】:

我正在制作一个基本的平台游戏,这是我的第一款游戏。我遇到了一些问题。到目前为止,游戏只有一个关卡,它是从 .txt 文件加载的。不过我想要一个 Angry Birdish 的世界/关卡选择屏幕。

计划是为每个级别显示一个图标,但仅到目前为止已完成的级别和下一个可访问。此外,对于已完成的关卡,分数(星星等)将显示在图标下方。

我不想从 XML 加载关卡,至少现在还不想。只有需要读取和写入的持久世界数据。我认为最简单的方法是从 XML 加载关卡选择屏幕的格式,而不是使用我目前使用的方法(文本文件)。

我想我可以用文本文件做到这一点,但我真的不喜欢在文件中编写和排序的想法。然后我发现 XML 文件在这方面的问题应该少一些。然而,另一个问题来自我以前从未使用过 XML 文件这一事实。

有人可以为我指明此类事情的教程方向,或者您可能遇到的一些示例,至少可以实现相对相似的结果。我不希望任何人为我编写代码,但如果您有指示或有时间和耐心提供示例,我将不胜感激。

在对旧 XNA 版本的教程进行了一些进一步的挖掘和摸索之后,我设法生成了以下保存/加载类:

namespace SaveLoadXML

    class SaveLoad
    
        public LevelInfo Load (int id)
        
            LevelInfo level;

            // Get the path of the save game
            string fullpath = "World.xml";

            // Open the file
            FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate,
            FileAccess.Read);
            try
            

                // Read the data from the file
                XmlSerializer serializer = new XmlSerializer(typeof(LevelInfo));
                level = (LevelInfo)serializer.Deserialize(stream);
            
            finally
            
                // Close the file
                stream.Close();
            

            return (level);
        

        public void Save (LevelInfo level, int id)
        
            // Get the path of the save game
            string fullpath = "World.xml";

            // Open the file, creating it if necessary
            FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate);
            try
            
                // Convert the object to XML data and put it in the stream
                XmlSerializer serializer = new XmlSerializer(typeof(LevelInfo));
                serializer.Serialize(stream, level);
            
            finally
            
                // Close the file
                stream.Close();
            
        
    

现在我开始思考,有没有办法针对 XML 文件的特定部分,或者写作总是从头开始?几乎我看到的所有例子一开始都有一个条件:如果文件存在,删除它然后写入。

我假设我可以(甚至应该?)制作一个 LevelInfo 对象列表并一次加载它们,因为无论如何都没有真正需要加载单个 LevelInfo。但是,在保存时,我是否需要加载以前的状态(旧列表),然后处理涉及某些索引的列表,然后删除 te 文件,并再次保存。

这可能会为系统故障打开一个简单的方法,例如,如果保存出现问题或电源故障。整个文件将丢失或损坏。我想这可以通过使用备份文件然后检查主文件的完整性来解决,但现在对于像我这样的初学者来说,它开始感觉像是一座需要爬的山。

在 GameDev 上尝试过这个问题后,我将在这里澄清主要问题:

1) 我可以在包含所有级别信息的 XML 文件中只保存一个或两个级别的信息吗? IE。我可以使用一些索引来将写入操作指向一个特定的部分,然后该部分将被覆盖/替换。

2)如果没有,有什么方法可以安全地从文件中加载所有信息,删除文件,在需要的地方修改后保存所有信息。


在研究了这个 Json 的东西之后,我成功地序列化了测试级别的信息。但是,反序列化失败,因为我有一个矩形作为对象的一部分。错误如下:

将值“X:1 Y:1 Width:1 Height:1”转换为类型“Microsoft.Xna.Framework.Rectangle”时出错。路径“[0].Rectangle”,第 6 行,位置 46。

class LevelInfo

    public int ID  get; set; 
    public Vector2 Dimensions  get; set; 
    public Vector2 Position  get; set; 
    public Rectangle Rectangle  get; set; 
    public int Stars  get; set; 
    public string Text  get; set; 



class SaveLoadJSON

    public static List<LevelInfo> Load()
    
        List<LevelInfo> levels = new List<LevelInfo>();

        using (StreamReader file = File.OpenText("World.json"))
        
            JsonSerializer serializer = new JsonSerializer();
            levels = (List<LevelInfo>)serializer.Deserialize(file, typeof(List<LevelInfo>));
          

        return levels;
    

    public static void Save(List<LevelInfo> levels)
     
        if (File.Exists("World.json"))
        
            File.Delete("World.json");
        

        using (FileStream fs = File.Open("World.json", FileMode.CreateNew))
        using (StreamWriter sw = new StreamWriter(fs))
        using (JsonWriter jw = new JsonTextWriter(sw))
        
            jw.Formatting = Formatting.Indented;

            JsonSerializer serializer = new JsonSerializer();
            serializer.Serialize(jw, levels);
        
    

有没有办法解决这个问题?对于像我这样简单的初学者来说,最好是一种相对简单的方法。

或者,有没有办法在开始时省略矩形信息,然后再添加?如果我没有向矩形输入任何内容,它仍然会以 0 值添加到 Json 文件中。我确实需要绘图的矩形信息。

【问题讨论】:

【参考方案1】:

因此,承诺的答案来了。

我个人更喜欢使用 JSon 来存储数据,因为它比 XML 更容易使用,并且占用的存储空间更少。您要做的是为您的玩家、敌人、物品、场景对象等创建数据模型。

然后,您需要 JsonConvert.SerializeObject() 一个父数据模型,它将包含所有这些内容。

将此保存在任何文件中,并在加载时再次反序列化,并从头开始重建所有对象。

或者,只需将您正在使用的类中的所有属性公开即可。这样,JsonConvert 将能够实际序列化整个模型。请记住,如果您执行此运行时,它将更多地生成关卡当前状态的完整快照。阿卡。敌人所在的位置、剩余的生命值以及您可能拥有的任何其他值。

我希望这能回答你的问题。

【讨论】:

Json 似乎是一个有趣的选择,尤其是由于文件较小。但是,似乎我需要添加一些库/引用才能真正获得对 Json 的访问权限。有一个例子是添加 using 语句来获得 Json 功能,但似乎情况发生了变化,这样的语句不再起作用。 问题是,选择哪一个:james.newtonking.com/json 或 codeproject.com/Articles/159450/fastJSON 我的目标是最终拥有可以在 WP、androidios 上运行的东西,那么这个 Json 业务是否会造成潜在的危害?至少 Newtonsoft Json 声称兼容性很高,所以我认为可能涉及一些问题。 据我所知,Json 可以在任何存在的平台上运行(嗯,你知道,任何著名的平台)。是的,要么使用james.newtonking.com/json 要么去VS包管理器并写“安装包Newtonsoft.Json”

以上是关于在关卡选择屏幕、XML、XNA 上保存和加载数据的主要内容,如果未能解决你的问题,请参考以下文章

未在加载函数之外保存的数组 - ActionScript 3 和 XML

XNA 地图编辑器(上)

XNA的开始和结束屏幕[关闭]

如何获取 XNA 游戏屏幕上的窗口位置?

使用 XNA 裁剪音频

UE4 关卡加载与关卡流加载