目录
前言
读者在阅读《游戏设计、原型与开发》中第四个实例原型《Prospector》的过程中,看到源代码使用的是自己创建的PT_XMLReader脚本,名字应该表示“Prototool_XML Reader”的意思。在使用该脚本读取XML文件时,稍有繁琐,需要考虑XML文件某个节点的属性是否存在等问题。我在跟着教程写代码时,写了使用C#里的API读取XML文件的版本。在此先给出这一部分代码以供参考。
#region 从XML文件中获取Sprite的位置信息——C#
/* ---读取XML文件--- */
// Resources文件夹比较特殊,不能使用相对路径访问
// 注意,无需为文件添加后缀
TextAsset xmlAsset = Resources.Load("XML Versions of Deck & Layout/XML_Deck");
// 检查是否获取到文件
if (xmlAsset == null)
{
Debug.Log("XML_Deck文件获取失败!");
return;
}
else
{
Debug.Log("XML_Deck文件获取成功!");
}
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlAsset.text);
/* 读---取XML文件中的 decorator节点--- */
// 在 decorator前添加 // 表示是在文件全局中寻找
XmlNodeList nodesDeco = doc.SelectNodes("//decorator");
Debug.Log($"nodesDeco.Count:{nodesDeco.Count}");
decorators = new List();
Decorator deco;
if (nodesDeco.Count > 0)
{
// 读取并设置decorator
foreach (XmlNode n in nodesDeco)
{
deco = new Decorator();
// 添加?作为可空类型,可以避免XML中没写这个属性,但是却使用了其Value,导致空引用报错
deco.type = n.Attributes["type"]?.Value;
deco.loc.x = Convert.ToSingle(n.Attributes["x"]?.Value);
deco.loc.y = Convert.ToSingle(n.Attributes["y"]?.Value);
deco.loc.z = Convert.ToSingle(n.Attributes["z"]?.Value);
deco.flip = n.Attributes["flip"]?.Value == "1";
deco.scale = Convert.ToSingle(n.Attributes["scale"]?.Value);
decorators.Add(deco);
}
}
/* ---读取XML文件中的 card 节点--- */
XmlNodeList nodesCard = doc.SelectNodes("//card");
cardDefs = new List();
CardDefinition cDef;
if (nodesCard.Count > 0)
{
foreach (XmlNode n in nodesCard)
{
cDef = new CardDefinition();
cDef.rank = int.Parse(n.Attributes["rank"]?.Value);
XmlNodeList childNodesCard = n.ChildNodes;
foreach (XmlNode childN in childNodesCard)
{
deco = new Decorator();
deco.type = "pip";
deco.flip = childN.Attributes["flip"]?.Value == "1";
deco.loc.x = Convert.ToSingle(childN.Attributes["x"]?.Value);
deco.loc.y = Convert.ToSingle(childN.Attributes["y"]?.Value);
deco.loc.z = Convert.ToSingle(childN.Attributes["z"]?.Value);
deco.scale = Convert.ToSingle(childN.Attributes["scale"]?.Value);
cDef.pips.Add(deco);
}
// J、Q、K卡面是人脸
cDef.face = n.Attributes["face"]?.Value;
cardDefs.Add(cDef);
}
}
#endregion
以下是我上面代码读取的Xml文件
<xml>
<decorator type="letter" x="-1.05" y="1.42" z="0" flip="0" scale="1.25"/>
<decorator type="suit" x="-1.05" y="1.03" z="0" flip="0" scale="0.4" />
<decorator type="suit" x="1.05" y="-1.03" z="0" flip="1" scale="0.4" />
<decorator type="letter" x="1.05" y="-1.42" z="0" flip="1" scale="1.25"/>
<card rank="1">
<pip x="0" y="0" z="0" flip="0" scale="2"/>
</card>
<card rank="2">
<pip x="0" y="1.1" z="0" flip="0"/>
<pip x="0" y="-1.1" z="0" flip="1"/>
</card>
<card rank="3">
<pip x="0" y="1.1" z="0" flip="0"/>
<pip x="0" y="0" z="0" flip="0"/>
<pip x="0" y="-1.1" z="0" flip="1"/>
</card>
<card rank="4">
<pip x="-.55" y="1.1" z="0" flip="0"/>
<pip x=".55" y="1.1" z="0" flip="0"/>
<pip x="-.55" y="-1.1" z="0" flip="1"/>
<pip x=".55" y="-1.1" z="0" flip="1"/>
</card>
<card rank="5">
<pip x="-.55" y="1.1" z="0" flip="0"/>
<pip x=".55" y="1.1" z="0" flip="0"/>
<pip x="0" y="0" z="0" flip="0"/>
<pip x="-.55" y="-1.1" z="0" flip="1"/>
<pip x=".55" y="-1.1" z="0" flip="1"/>
</card>
<card rank="6">
<pip x="-.55" y="1.1" z="0" flip="0"/>
<pip x=".55" y="1.1" z="0" flip="0"/>
<pip x="-.55" y="0" z="0" flip="0"/>
<pip x=".55" y="0" z="0" flip="0"/>
<pip x="-.55" y="-1.1" z="0" flip="1"/>
<pip x=".55" y="-1.1" z="0" flip="1"/>
</card>
<card rank="7">
<pip x="-.55" y="1.1" z="0" flip="0"/>
<pip x=".55" y="1.1" z="0" flip="0"/>
<pip x="0" y=".55" z="0" flip="0"/>
<pip x="-.55" y="0" z="0" flip="0"/>
<pip x=".55" y="0" z="0" flip="0"/>
<pip x="-.55" y="-1.1" z="0" flip="1"/>
<pip x=".55" y="-1.1" z="0" flip="1"/>
</card>
<card rank="8">
<pip x="-.55" y="1.1" z="0" flip="0"/>
<pip x=".55" y="1.1" z="0" flip="0"/>
<pip x="0" y=".55" z="0" flip="0"/>
<pip x="-.55" y="0" z="0" flip="0"/>
<pip x=".55" y="0" z="0" flip="0"/>
<pip x="0" y="-.55" z="0" flip="1"/>
<pip x="-.55" y="-1.1" z="0" flip="1"/>
<pip x=".55" y="-1.1" z="0" flip="1"/>
</card>
<card rank="9">
<pip x="-.58" y="1.1" z="0" flip="0"/>
<pip x=".58" y="1.1" z="0" flip="0"/>
<pip x="-.58" y=".37" z="0" flip="0"/>
<pip x=".58" y=".37" z="0" flip="0"/>
<pip x="0" y="0" z="0" flip="0"/>
<pip x="-.58" y="-.37" z="0" flip="1"/>
<pip x=".58" y="-.37" z="0" flip="1"/>
<pip x="-.58" y="-1.1" z="0" flip="1"/>
<pip x=".58" y="-1.1" z="0" flip="1"/>
</card>
<card rank="10">
<pip x="-.58" y="1.1" z="0" flip="0"/>
<pip x=".58" y="1.1" z="0" flip="0"/>
<pip x="0" y=".73" z="0" flip="0"/>
<pip x="-.58" y=".37" z="0" flip="0"/>
<pip x=".58" y=".37" z="0" flip="0"/>
<pip x="-.58" y="-.37" z="0" flip="1"/>
<pip x=".58" y="-.37" z="0" flip="1"/>
<pip x="0" y="-.73" z="0" flip="1"/>
<pip x="-.58" y="-1.1" z="0" flip="1"/>
<pip x=".58" y="-1.1" z="0" flip="1"/>
</card>
<card rank="11" face="FaceCard_11"/>
<card rank="12" face="FaceCard_12"/>
<card rank="13" face="FaceCard_13"/>
</xml>
一、相关API概述
开门见山!
using System.IO; // 引用该命名空间,以使用读写操作的API,在本文章中暂不说明,读者可以在互联网或者结合AI了解如何使用
using System.Xml; // 引用该命名空间,以使用操作Xml文件的API
XmlDocument是一个类,表示一个Xml文件
XmlNodeList是一个类,表示存储Xml文件中的节点的列表
XmlNode是一个类,表示一个节点
void XmlDocument.LoadXml(string xml)是一个成员方法,根据xml文件的名称加载Xml文件
XmlNodeList XmlNode.SelectNodes(string xpath)是一个成员方法,根据节点名称获取所有符合条件的节点
SelectNode(string xpath)根据节点名称找到一个符合条件的节点
再继续下去就有点像XML API介绍了,其实这些内容可以从微软官方文档中找到XmlDocument类定义-Microsoft
接下来我将介绍如何使用。
二、如何读取XML文件
步骤说明:
- 创建一个
XDocument实例,并调用其LoadXml()方法获取Xml文件 - 如果需要获取某个节点,使用SelectNode(string xpath)方法;如果需要获取相同名称的所有节点,使用SelectNodes(string xpath)方法
- 需要获取节点的属性,使用节点的attribute["属性名"]获取。
以上面的示例代码为例,
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlAsset.text);
这一步获取Xml文件。
/* ---读取XML文件中的 decorator节点--- */
// 在 decorator前添加 // 表示是在文件全局中寻找
XmlNodeList nodesDeco = doc.SelectNodes("//decorator");
Debug.Log($"nodesDeco.Count:{nodesDeco.Count}");
这一步在整个Xml文件中寻找名为"decorator"的节点
注意:这里的节点名称前添加了“//”,表示会在整个Xml文件中寻找。你也可以先获取Xml中的某个根节点,然后在根节点的子节点里寻找。
if (nodesDeco.Count > 0)
{
// 读取并设置decorator
foreach (XmlNode n in nodesDeco)
{
deco = new Decorator();
// 添加?作为可空类型,可以避免XML中没写这个属性,但是却使用了其Value,导致空引用报错
deco.type = n.Attributes["type"]?.Value;
deco.loc.x = Convert.ToSingle(n.Attributes["x"]?.Value);
deco.loc.y = Convert.ToSingle(n.Attributes["y"]?.Value);
deco.loc.z = Convert.ToSingle(n.Attributes["z"]?.Value);
deco.flip = n.Attributes["flip"]?.Value == "1";
deco.scale = Convert.ToSingle(n.Attributes["scale"]?.Value);
decorators.Add(deco);
}
}
这一步遍历获取到的节点,并读取节点中属性的值。你可以看到在Attributes["x"]?后跟了个"?",表示这是个可空类型,如果它为null,就不会自动使用其Value属性;如果不为null,才使用。这个问号可以避免报错。
在这一步,我将读取到的值一个一个赋予我创建的类对象。
总结
读取XML文件的步骤:
- 获取XML文件
- 读取XML文件的节点
- 操作XML文件节点的值