Nếu bạn sử dụng XmlSerializer như được trình bày trong trợ giúp XNA 4.0, các lớp cơ sở cần có thuộc tính [XmlInclude (Type)] được chỉ định cho từng loại cụ thể mà chúng có thể được nối tiếp vào.
Dưới đây là ví dụ về cách lưu dữ liệu trò chơi trong XNA 4.0. Nhấn F1 để lưu khi trò chơi đang chạy. Dữ liệu sẽ được lưu vào một vị trí tương tự như C: \ Users \ {username} \ Documents \ SavedGames \ WindowsGame \ Game1StorageContainer \ Player1.
Tải lại dữ liệu là một quá trình rất giống nhau.
Để làm việc này trên XBox, hãy thêm tham chiếu đến 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);
}
}
}
Hoàn hảo. Cảm ơn nhiều. Đây chính xác là những gì tôi cần để làm việc. –
Không nên đóng luồng sau khi lưu? –
Luồng được gói gọn trong một khối sử dụng sẽ gọi IDisposable.Dispose trên luồng ở cuối khối. Điều này sẽ xảy ra ngay cả khi một ngoại lệ được ném vào trong khối để an toàn hơn là chỉ gọi Close. – Empyrean