zoukankan      html  css  js  c++  java
  • XNA 3.0——将数据保存到文件,从文件读取数据

    1.9 将数据保存到文件,从文件读取数据

    问题

    你需要在游戏中实现保存功能。解决方案虽然保存功能通常是创建游戏的最后一步,但你肯定需要在游戏中实现这个功能。首先,XNA使用默认的.NET文件I/O 功能,这意味着创建/打开/删除文件是很容易的。接着,使用XmlSerializer类能非常容易地将数据保存到文件并在以后加载数据。

    唯一的问题是找到在PC平台和Xbox360平台都能保存的位置,要解决这个问题,你可以使用StorageDevice,它必须首先被建立。

    注意创建一个StorageDevice的原理可能很复杂,但别被吓倒,因为本教程的其余部分(从“将数据保存到磁盘”) 非常简单和有效,而且这个方法并不局限与在XNA上使用,因为它使用的是默认的.NET功能。

    工作原理

    在将数据保存到磁盘之前,你需要一个可用的位置进行写入。这可以通过创建一个StorageDevice实现,StorageDevice会询问Xbox360平台上的用户将数据保存到哪儿。

    异步创建一个StorageDevice

    在这个过程中会打开Xbox Guide并终止程序直到用户关闭Guide。要解决这个问题,可以让这个过程异步处理,原理在教程8-5中解释。

    Guide需要将GamerServicesComponent添加到游戏中 (见教程8-1),所以要将下列代码添加到Game1构造函数中:

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

    下一步,当调用Update方法时,你会检查用户是否想保存数据,如果是,则调用Guide. BeginShowStorageDeviceSelector,它会打开一个对话框让用户选择在哪里保存数据。程序并不会在此终止,但会暂停程序直到用户关闭对话框。Guide. BeginShowStorageDeviceSelector方法要求你指定另一个FindStorageDevice方法作为第一个参数,一旦用户关闭对话框这个方法就会被调用:

    KeyboardState keyState = Keyboard.GetState(); 
    if (!Guide.IsVisible)
        if (keyState.IsKeyDown(Keys.S)) 
            Guide.BeginShowStorageDeviceSelector(FindStorageDevice, null); 

    如果用户按下S键就会打开对话框,但代码并不会终止直到用户关闭对话框。

    当对话框显示在屏幕上时你的程序仍在运行,一旦用户做出选择并关闭对话框,作为第一个参数的FindStorageDevice方法就会被调用,这意味着你应事先定义这个方法,否则编译器会报错:

    private void FindStorageDevice(IAsyncResult result)
    {
        StorageDevice storageDevice = Guide.EndShowStorageDeviceSelector(result); 
            if (storageDevice != null) 
                SaveGame(storageDevice); 
    } 

    BeginShowStorageDeviceSelector的输出结果作为这个方法的参数,如果你将结果传递到Guide. EndShowStorageDeviceSelector方法,就可以获取data storage。但是如果用户取消操作,结果将会是null,所以你应该事先检查。如果StorageDevice可用,你将它传递到SaveGame方法,这个方法一会儿后就会定义。

    但如果当用户指定数据位置时允许用户进行第二种操作,例如加载数据,那么就需要定义第二个方法,比方说FindStorageDeviceForLoading。但清晰的方法是指定一个identifier,在FindStorageDevice方法中可以检查这个identifier。你的Update方法应该包含下列代码块:

    KeyboardState keyState = Keyboard.GetState(); 
    if (!Guide.IsVisible)
    {
        if (keyState.IsKeyDown(Keys.S)) 
            Guide.BeginShowStorageDeviceSelector(FindStorageDevice, "saveRequest"); 
        if (keyState.IsKeyDown(Keys.L)) 
            Guide.BeginShowStorageDeviceSelector(FindStorageDevice, "loadRequest"); 
    } 

    如你所见,在这两种情况下对话框都会显示,当对话框关闭后就会调用FindStorageDevice方法。但这次的区别是你指定了一个identifier并在FindStorageDevice方法中检查这个identifier:

    private void FindStorageDevice(IAsyncResult result)
    {
        StorageDevice storageDevice = Guide.EndShowStorageDeviceSelector(result); 
        if (storageDevice != null)
        {
            if (result.AsyncState == "saveRequest") 
                SaveGame(storageDevice); 
            else if (result.AsyncState == "loadRequest") 
                LoadGame(storageDevice); 
        }
    } 

    根据指定的identity,你将调用SaveGame或LoadGame方法。

    将数据保存到磁盘

    一旦有了一个正确的StorageDevice,你就可以很容易地为写入数据的文件指定一个名称:

    private void SaveGame(StorageDevice storageDevice)
    {
        StorageContainer container = storageDevice.OpenContainer("BookCodeWin"); 
        string fileName = Path.Combine(container.Path, "save0001.sav"); 
        FileStream saveFile = File.Open(fileName, FileMode.Create); 
    } 

    这将创建一个叫做save0001. Sav的文件,如果这个文件已经存在将会被覆盖。

    注意在PC上这个文件将会创建在My Documents\SavedGames文件夹中。

    一旦你有了正确的文件名并已经打开了这个文件,你就可以使用默认的.NET 方法保存文件,假设你将存储的数据结构如下:

    public struct GameData
    {
        public int ActivePlayers; 
        public float Time; 
    } 

    你需要创建一个XmlSerializer,它能够将你的数据转换为XML并保存到磁盘:

    XmlSerializer xmlSerializer = new XmlSerializer(typeof(GameData));
    xmlSerializer.Serialize(saveFile, gameData); 
    saveFile.Close(); 

    XmlSerializer能够串行化GameData对象,之后使用一个命令就可以将GameData对象的数据流写到文件中。别忘了关闭文件流,否则程序会锁定文件流。

    你需要添加System. IO和System.Xml. Serialization命名空间,只需在代码顶部添加下面的代码:

    using System.IO; 
    using System.Xml.Serialization; 

    最后一行代码需要你添加对System. Xml的引用,要添加这个引用,可以打开Project菜单并选择Add Reference,选择System.Xml,如图1-5所示,然后点击OK。

    2

    图1-5 添加对System. Xml的引用

    从磁盘加载数据

    加载数据的方法与保存数据的方法相同,顺序正好相反。你检查文件是否存在,如果存在就打开它。你仍要创建一个XmlSerializer,但这次你使用XmlSerializer从文件流中反串行化GameData对象,下面的代码加载从文件加载所有数据并把数据转换为GameData对象:

    private void LoadGame(StorageDevice storageDevice) 
    {
        StorageContainer container = storageDevice.OpenContainer("BookCodeWin"); 
        string fileName = Path.Combine(container.Path, "save0001.sav"); 
        if (File.Exists(fileName)) 
        {
            FileStream saveFile = File.Open(fileName, FileMode.Open); 
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(GameData)); 
            gameData = (GameData)xmlSerializer.Deserialize(saveFile); 
            saveFile.Close(); 
        }
    } 
    代码

    Update方法检查用户是想保存还是加载文件并打开对话框:

    protected override void Update(GameTime gameTime)
    {
        GamePadState gamePadState = GamePad.GetState(PlayerIndex.One); 
        if (gamePadState.Buttons.Back == ButtonState.Pressed) 
            this.Exit(); 
        KeyboardState keyState = Keyboard.GetState(); 
        if (!Guide.IsVisible)
        {
            if (keyState.IsKeyDown(Keys.S)) 
                Guide.BeginShowStorageDeviceSelector(FindStorageDevice, "saveRequest"); 
            if (keyState.IsKeyDown(Keys.L)) 
                Guide.BeginShowStorageDeviceSelector(FindStorageDevice, "loadRequest"); 
        }
        gameData.Time += (float)gameTime.ElapsedGameTime.TotalSeconds; 
        base.Update(gameTime); 
    } 

    当用户关闭Guide时就会调用FindStorageDevice方法,这个方法根据异步调用的identity调用SaveData或LoadData方法。你可以在前面的代码中看到整个FindStorageDevice方法,只漏了SaveGame 方法:

    private void SaveGame(StorageDevice storageDevice) 
    {
        StorageContainer container = storageDevice.OpenContainer("BookCodeWin"); 
        string fileName = Path.Combine(container.Path, "save0001.sav"); 
        FileStream saveFile = File.Open(fileName, FileMode.Create); 
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(GameData)); 
        XmlSerializer.Serialize(saveFile, gameData); 
        saveFile.Close(); 
        log.Add("Game data saved!"); 
    } 
    3
  • 相关阅读:
    Oracle数据库的经典问题 snapshot too old是什么原因引起的
    在服务器上排除问题的头五分钟
    MySQL的redo log结构和SQL Server的log结构对比
    MySQL优化---DBA对MySQL优化的一些总结
    事务分类
    扩展HT for Web之HTML5表格组件的Renderer和Editor
    iOS平台快速发布HT for Web拓扑图应用
    HT for Web的HTML5树组件延迟加载技术实现
    Zip 压缩、解压技术在 HTML5 浏览器中的应用
    百度地图、ECharts整合HT for Web网络拓扑图应用
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120177.html
Copyright © 2011-2022 走看看