在XNA 4.0中保存游戏数据的一个好例子是什么?

7
我正在尝试通过XNA MSDN文档来保存和读取游戏数据,但是效果不佳。
本质上,我有一个管理器类,它跟踪多个基类的实例。
我希望能够保存管理器跟踪的整个对象列表的状态,并在下次游戏加载时将它们加载。 基本上是保存世界的状态。
1个回答

17

如果您像XNA 4.0帮助文档中所示使用XmlSerializer,则需要为每个可以序列化为具体类型的基类指定[XmlInclude(Type)]属性。

以下是在XNA 4.0中保存游戏数据的示例。运行游戏后按F1保存,数据将保存到类似于C:\ Users \ {username} \ Documents \ SavedGames \ WindowsGame \ Game1StorageContainer \ Player1的位置。

加载数据的过程非常相似。

要在XBox上使其工作,请添加对Microsoft.Xna.Framework.GamerServices和System.Xml.Serialization的引用。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;

namespace WindowsGame
{
    [XmlInclude(typeof(Soldier)), XmlInclude(typeof(Grenade))]
    public class BaseGameObject
    {
        public Vector3 Position { get; set; }
    }

    public class Soldier : BaseGameObject
    {
        public float Health { get; set; }
    }

    public class Grenade : BaseGameObject
    {
        public float TimeToDetonate { get; set; }
    }

    public struct SaveGameData
    {
        public string PlayerName;
        public Vector2 AvatarPosition;
        public int Level;
        public int Score;
        public List<BaseGameObject> GameObjects;
    }

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        enum SavingState
        {
            NotSaving,
            ReadyToSelectStorageDevice,
            SelectingStorageDevice,

            ReadyToOpenStorageContainer,    // once we have a storage device start here
            OpeningStorageContainer,
            ReadyToSave
        }

        GraphicsDeviceManager graphics;
        KeyboardState oldKeyboardState;
        KeyboardState currentKeyboardState;
        StorageDevice storageDevice;
        SavingState savingState = SavingState.NotSaving;
        IAsyncResult asyncResult;
        PlayerIndex playerIndex = PlayerIndex.One;
        StorageContainer storageContainer;
        string filename = "savegame.sav";

        SaveGameData saveGameData = new SaveGameData()
        {
            PlayerName = "Grunt",
            AvatarPosition = new Vector2(10, 15),
            Level = 3,
            Score = 99424,
            GameObjects = new List<BaseGameObject>() 
            { 
                new Soldier { Health = 10.0f, Position = new Vector3(0.0f, 10.0f, 0.0f) },
                new Grenade { TimeToDetonate = 3.0f, Position = new Vector3(4.0f, 3.0f, 0.0f) }
            }
        };

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

#if XBOX
            Components.Add(new GamerServicesComponent(this));
#endif

            currentKeyboardState = Keyboard.GetState();
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            oldKeyboardState = currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();

            UpdateSaveKey(Keys.F1);
            UpdateSaving();

            base.Update(gameTime);
        }

        private void UpdateSaveKey(Keys saveKey)
        {
            if (!oldKeyboardState.IsKeyDown(saveKey) && currentKeyboardState.IsKeyDown(saveKey))
            {
                if (savingState == SavingState.NotSaving)
                {
                    savingState = SavingState.ReadyToOpenStorageContainer;
                }
            }
        }

        private void UpdateSaving()
        {
            switch (savingState)
            {
                case SavingState.ReadyToSelectStorageDevice:
#if XBOX
                    if (!Guide.IsVisible)
#endif
                    {
                        asyncResult = StorageDevice.BeginShowSelector(playerIndex, null, null);
                        savingState = SavingState.SelectingStorageDevice;
                    }
                    break;

                case SavingState.SelectingStorageDevice:
                    if (asyncResult.IsCompleted)
                    {
                        storageDevice = StorageDevice.EndShowSelector(asyncResult);
                        savingState = SavingState.ReadyToOpenStorageContainer;
                    }
                    break;

                case SavingState.ReadyToOpenStorageContainer:
                    if (storageDevice == null || !storageDevice.IsConnected)
                    {
                        savingState = SavingState.ReadyToSelectStorageDevice;
                    }
                    else
                    {
                        asyncResult = storageDevice.BeginOpenContainer("Game1StorageContainer", null, null);
                        savingState = SavingState.OpeningStorageContainer;
                    }
                    break;

                case SavingState.OpeningStorageContainer:
                    if (asyncResult.IsCompleted)
                    {
                        storageContainer = storageDevice.EndOpenContainer(asyncResult);
                        savingState = SavingState.ReadyToSave;
                    }
                    break;

                case SavingState.ReadyToSave:
                    if (storageContainer == null)
                    {
                        savingState = SavingState.ReadyToOpenStorageContainer;
                    }
                    else
                    {
                        try
                        {
                            DeleteExisting();
                            Save();
                        }
                        catch (IOException e)
                        {
                            // Replace with in game dialog notifying user of error
                            Debug.WriteLine(e.Message);
                        }
                        finally
                        {
                            storageContainer.Dispose();
                            storageContainer = null;
                            savingState = SavingState.NotSaving;
                        }
                    }
                    break;
            }
        }

        private void DeleteExisting()
        {
            if (storageContainer.FileExists(filename))
            {
                storageContainer.DeleteFile(filename);
            }
        }

        private void Save()
        {
            using (Stream stream = storageContainer.CreateFile(filename))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(SaveGameData));
                serializer.Serialize(stream, saveGameData);
            }
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            base.Draw(gameTime);
        }
    }
}

1
保存后,流不应该关闭吗? - Jesse Demarco
3
该流被封装在一个using块中,在块的末尾将调用IDisposable.Dispose对该流进行处理。即使在块内抛出异常,这也会发生,因此比仅调用Close更安全。 - Empyrean
1+ 这对我也起作用了,非常好,正是我在寻找的。 :) - radbyx

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