zoukankan      html  css  js  c++  java
  • 处理顶点——从XML文件加载数据

    问题

    你想从一个XML文件中加载数据到XNA项目。你可以使用默认的.NET文件IO功能在XNA项目启动时读取文件做到这点,但这在Xbox360平台上无法工作。

    你想使用内容管道将一个XML文件串行化为一个二进制文件,这样就可以在XNA项目中读取包含在这些文件中的内容了。

    解决方案

    在XML文件中,只需简单地将你想要加载的对象插入到<XNAContent>和<Asset>标签之间,下面的XML示例文件是一个自定义的MapData类对象:

    <?xml version="1.0" encoding="utf-8"?>
    <XnaContent?>
        <Asset Type="XMLDataPLine.MapData"?>
        <mapName>Battle In The Middle</mapName>
        <numberOfCastles>8</numberOfCastles>
        <allies>
            <Item>Humans</Item> 
            <Item>Elves</Item>
            <Item>Dwarves</Item>
        </allies>
        </Asset>
    </XnaContent>

    技巧:如果你不知道如何从一个对象自动创建一个XML文件,你可以在本教程的最后学到方法。

    XNA框架自带有内容导入器可以将XML文件转换为定义在XML文件中的对象。

    这里因为对象已近建立了,所以你无需使用处理器,对象可以立即串行化为一个二进制文件。这里对象是自定义的MapData类,所以你需要定义一个自定义的TypeWriter和TypeReader。

    注意:如果内容管道知道如何串行化/反串行化XML文件描述的对象,你就没必要编写一个新的TypeWriter或TypeReader。

    图5-25显示了简图。

    image

    图5-25 当从XML文件导入对象时无需处理器。

    工作原理

    将一个. Xml文件导入到XNA项目中。在解决方案浏览器中,选择一个文件,它的属性显示在屏幕右下角。表面你想使用默认的XML内容导入器,选择No Processing Required表示导入器的输出不使用处理器就被串行化为一个文件。图5-26显示了最终的属性窗口。

    image

    图5-26 一个导入的XML文件的属性

    如果XML文件包含一个内容管道知道如何串行化/反串行化的类对象,你可以将这个对象在LoadContent方法中加载到一个变量。但是本教程中是一个自定义类,所以你需要定义一个TypeWriter。

    按照教程4-15中解释的步骤在解决方案中添加一个内容管道。这次,你无需定义处理器,只需定义MapData类 及对应的TypeWriter和TypeReader。

    注意:确保添加内容管道项目的引用,解释请见教程4-15。这是必需的,这样你的主程序才可以访问到MapData类的定义,这个类定义是存储在内容管道项目中的。

    定义自定义的MapData类

    本例中的MapData类包含一个string,一个int和一个string的集合,将这个定义添加到内容管道项目中:

    public class MapData 
    {
        public string mapName; 
        public int numberOfCastles; 
        public List<string> 
        allies = new List<string>(); 
    }

    技巧:验证一下包含在前面的XML文件中的数据提供了这三个变量的数据。

    定义一个可以串行化MapData类对象的TypeWriter

    如教程4-15所述,TypeWriter需要从对象串行化足够的数据,这样以后对象才能被TypeReader重建。和以往一样,仍需要提供 TypeReader的位置:

    [ContentTypeWriter] public class MapDataTypeWriter : ContentTypeWriter<MapData>
    {
        protected override void Write(ContentWriter output, MapData value) 
        {
            output.WriteObject<string>(value.mapName); 
            output.WriteObject<int>(value.numberOfCastles); 
            output.WriteObject<List<string>>(value.allies); 
        }
        
        public override string GetRuntimeReader(TargetPlatform targetPlatform) 
        {
            return typeof(MapDataReader).AssemblyQualifiedName; 
        }

    你表明了这个TypeWriter可以串行化MapData类对象。默认内容管道知道如何串行化一个string,一个int和一个List,所以你只需简单地将它们串行化为一个二进制文件。你传递了一个MapDataReader TypeReader的链接,下面就会定义这个链接。

    定义一个可以串行化MapData类对象的TypeReader

    TypeReader只是简单地创建了一个新MapData对象,读取string,int和List (按正确地顺序!),并将它们存储在MapData对象中。这个对象被返回并发送到XNA游戏项目。

    class MapDataReader : ContentTypeReader<MapData>
    {
        protected override MapData Read(ContentReader input, MapData existingInstance) 
        {
            MapData map = new MapData(); 
            map.mapName = input.ReadObject<string>(); 
            map.numberOfCastles = input.ReadObject<int>(); 
            map.allies = input.ReadObject<List<string>>(); 
            
            return map; 
        }
    }
    使用方法

    LoadContent方法的第一行代码就可以实时从MapData对象中读取数据,第二行代码只是在代码中添加一个断点,这样让你可以检查数据是否正确:

    protected override void LoadContent() 
    {
        MapData loadedMap = Content.Load<MapData>("data"); 
        System.Diagnostics.Debugger.Break(); 
    }

    注意:只要编译项目,XML文件就会被转换为一个二进制文件。当项目开始时,只调用了TypeReader从二进制文件构建了MapData对象。这意味着如果你改变了XML的内容,你必须重新编译。

    代码

    自定义内容管道只包含类定义,TypeWriter和TypeReader,这在教程前面已经写过了。

    扩展阅读
    从一个已存在的对象创建一个XNA可用的XML文件

    本节解释了如何以一个XML文件存储任意类对象,然后你就可以使用默认XML导入器加载它了。首先需要添加下面的命名空间:

    using System.Xml; 
    using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;

    你还需添加System. XML和Microsoft. XNA. Framework. Content. Pipeline的引用;你可以通过从Project菜单中选择Add Reference添加这些引用。

    然后,要么链接到自定义内容管道,要么通过将下列代码放在项目命名空间的外面手动重定义MapData类。

    namespace XMLDataPLine 
    {
        public class MapData
        {
            public string mapName; 
            public int numberOfCastles; 
            public List<string> allies = new List<string>(); 
        }
    }

    如果你手动重定义类,请确保将它放在与自定义内容管道相同的命名空间中(我教程中叫做XMLDataPLine),所有的变量也是相同的。

    接下来,回到XNA项目的命名空间,确保已近有了一个MapData类对象:

    XMLDataPLine.MapData myMap = new XMLDataPLine.MapData(); 
    myMap.mapName = "Battle In The Middle"; 
    myMap.numberOfCastles = 8; 
    myMap.allies.Add("Humans"); 
    myMap.allies.Add("Elves"); 
    myMap.allies.Add("Dwarves");

    然后使用这个代码存储到一个XNA可用的XML文件中,叫做data . xml:

    string fileName = "data.xml"; 
    XmlWriter writer = XmlWriter.Create(fileName); 
    IntermediateSerializer.Serialize<XMLDataPLine.MapData>(writer, myMap, fileName); 
    writer.Close();

    当你运行程序时,data . xml文件会被创建到与. exe相同的位置中。

    注意:在示例中你也能找到这个代码。

  • 相关阅读:
    VIM文本替换命令
    VIM格式化代码(How to format code with VIM)
    字符串匹配的Boyer-Moore算法
    Java中数组的遍历
    UVa10723
    uva242,Stamps and Envelope Size
    UVa1630,Folding
    uva1629,Cake Slicing,记忆化搜索
    uva 10118,记忆化搜索
    uva10003
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120110.html
Copyright © 2011-2022 走看看