XNA-讀取和存放資料在Windows

XNA-讀取和存放資料在Windows

    這裡要介紹XNA在Windows的存檔和讀取檔案的方法,XNA Framework的Microsoft.Xna.Framework.Storage,就提供了對裝置作存取和讀取檔案的動作,它會將檔案存成.sav的檔案,裡面是以XML的格式所撰寫的,它會存在系統預設的路徑:C:\Documents and Settings\使用者帳號\My Documents底下的SavedGames資料夾裡,也必須使用到System.IO、System.Xml.Serialization這兩個類別的東西,System.IO是做寫入或是讀檔的動作,System.Xml.Serialization是設定XML格式的資料。

    建立檔案需要注意到的事情,建立檔案的同時就必須將你遊戲要儲存的資訊先用一些預設值(EX:數值的資料0)進去,不過這裡建議的是檔案裡面最好都用字串做存檔,因為我在讀取檔案裡面是數值的時候會發生取出來的值會怪怪的,以致不正確的數字發生,所以建議使用字串來存檔。

    讀取檔案和存取檔案所需要注意到的事情,在程式中最常犯的小錯誤就是忘記使用完檔案後必須要做關閉檔案的動作,因為同一個檔案只能同時被開啟一次,如果再做一次的話就會發生錯誤,因此使用完檔案後都必須要加上Close的動作。

    這裡也建議大家將此三種功能都分開撰寫成不同的函式,雖然他們的程式碼上都大同小異,但畢竟作的事情是不一樣的,這樣才能夠區分到底有何不同之處。

    此範例在做的就是如何建立檔案、讀取檔案、儲存檔案,模擬一個遊戲中的分數在還未被儲存前檔案所記錄的狀態,透過按鍵S就能夠將遊戲的分數存到檔案中,為了方便可以直接將變數topscore指派的值做變化,當然必須要大於檔案裡存放的值來的大才會儲存進去檔案中,因此record score也就隨之更新了,按鍵L則是做讀取檔案的動作。

程式範例:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
//存檔讀檔必須使用到這兩個namespace
using System.IO;
using System.Xml.Serialization;


namespace Data
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        IAsyncResult result;
        SpriteFont a;
        int topscore=9100;     //假設是遊戲的分數
        string score="0";      //在檔案建立時將預設值先存入檔案中
        //存檔的結構也是XML的格式
        public struct SaveGameData
        {
            public string Score;
        }
        //先宣告專門用來存放讀取檔案的物件
        SaveGameData data;

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

        protected override void Initialize()
        {
            CreateData();  //先檢查是否檔案有存在
            LoadData();    //先讀取檔案的資料
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            a = Content.Load<SpriteFont>("SpriteFont1");  //讀取字型檔
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            KeyboardState keyboard = Keyboard.GetState();
            if (keyboard.IsKeyDown(Keys.S))
            {
                SaveData(topscore);
            }
            if (keyboard.IsKeyDown(Keys.L))
            {
                LoadData();            
            }
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            String current = "current score";
            String record  = "record score";
            String gamescore;
            gamescore = Convert.ToString(topscore);
            spriteBatch.Begin();
            spriteBatch.DrawString(a, current, new Vector2(0, 0), Color.Blue);
            spriteBatch.DrawString(a, gamescore, new Vector2(0, 50), Color.Blue);
            spriteBatch.DrawString(a, record, new Vector2(0, 100), Color.Yellow);
            spriteBatch.DrawString(a, score, new Vector2(0, 150), Color.Yellow);
            spriteBatch.End();
            base.Draw(gameTime);
        }

        public void CreateData()
        {
            //先取得使用者使用的裝置資訊
            result = Guide.BeginShowStorageDeviceSelector(PlayerIndex.One, null, null);
            StorageDevice device = Guide.EndShowStorageDeviceSelector(result);
            //指定該用戶使用的資料夾
            StorageContainer container = device.OpenContainer("StorageDemo");
            //存放檔名
            string filename = Path.Combine(container.Path, "demobinary.sav");
            //檢查檔案是否已經被創出來了
            if (!File.Exists(filename))
            {
                //建立檔案並先將預設值0存入檔案中,以防null發生
                data.Score = score;
                FileStream file = File.Create(filename);
                XmlSerializer serializer = new XmlSerializer(typeof(SaveGameData));
                //將XML的格式的資料寫入檔案中
                serializer.Serialize(file, data);
                //關閉檔案
                file.Close();
            }
        }

        public void LoadData()
        {
            //先取得使用者使用的裝置資訊
            result = Guide.BeginShowStorageDeviceSelector(PlayerIndex.One, null, null);
            StorageDevice device = Guide.EndShowStorageDeviceSelector(result);
            //指定該用戶使用的資料夾
            StorageContainer container = device.OpenContainer("StorageDemo");
            //存放檔名
            string filename = Path.Combine(container.Path, "demobinary.sav");
            //設定檔案存取的模式和存放檔案的內容
            FileStream stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            //宣告一個存放XML格式的變數,格式則是剛剛宣告的SaveGameData這個結構
            XmlSerializer serializer = new XmlSerializer(typeof(SaveGameData));
            //將sav檔案XML格式的檔案裡的紀錄存放在新宣告的結構data裡
            data = (SaveGameData)serializer.Deserialize(stream);
            score = data.Score;
            //檔案開啟完畢之後必須做關閉的動作
            stream.Close();
        }

        public void SaveData(int topscore)
        {
            //先取得使用者使用的裝置資訊
            result = Guide.BeginShowStorageDeviceSelector(PlayerIndex.One, null, null);
            StorageDevice device = Guide.EndShowStorageDeviceSelector(result);
            //指定該用戶使用的資料夾
            StorageContainer container = device.OpenContainer("StorageDemo");
            //存放檔名
            string filename = Path.Combine(container.Path, "demobinary.sav");
            //先將字串轉換成數值為了和遊戲分數做比較
            int v ;
            //取出目前檔案的紀錄是多少將他轉換成數值存放起來
            v= Convert.ToInt16(data.Score);
            //如果遊戲分數大於檔案紀錄的分數的話就執行
            if (topscore > v)
            {
                v = topscore;
                data.Score = Convert.ToString(v);
                score = data.Score;
                //開啟檔案
                FileStream stream = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write);
                XmlSerializer serializer = new XmlSerializer(typeof(SaveGameData));
                //將XML格式的資料存進檔案中
                serializer.Serialize(stream, data);
                //關閉檔案
                stream.Close();
            }
        }
    }
}

存檔前

1

按下S鍵存檔後

2

    不過此方法在Xbox360上測試是失敗的,目前還不知道原因在哪,如果大家試出來的話,PO出來讓大家可以交流一下,更能夠了解到Windows開發和Xbox360開發上是有些許差異的。

最後附上專案程式Data.rar