【问题标题】:What is a good example of saving game data in XNA 4.0?在 XNA 4.0 中保存游戏数据的好例子是什么?
【发布时间】:2010-09-16 02:23:03
【问题描述】:

我正在尝试阅读有关保存和读取游戏数据的 XNA MSDN 文档,但运气不佳。

本质上,我有一个管理器类,它跟踪基类的多个实例。

我希望能够保存经理正在跟踪的整个对象列表的状态,然后在下次加载游戏时加载它们。基本上拯救了世界的状态。

【问题讨论】:

    标签: savestate xna-4.0


    【解决方案1】:

    如果您使用 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);
            }
        }
    }
    

    【讨论】:

    • 完美。非常感谢。这正是我需要解决的问题。
    • 保存后不应该关闭流吗?
    • 流被封装在一个 using 块中,该块将在块末尾的流上调用 IDisposable.Dispose。即使在块内抛出异常也会发生这种情况,因此比仅调用 Close 更安全。
    • 1+ 它也对我有用,非常好,正是我想要的。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    相关资源
    最近更新 更多