最近在学习unity的对话系统,其中我打算用XML来存储人物对话,考虑到对话中可能会需要实时呈现出说话人的样子,即在对话框上加上角色的立绘。我的解决方法是在获取对话的同时还要获取人物角色唯一标识ID,通过人物ID来确定其立绘。这其中会涉及到XML文件的读取。因此在编写XML文件时要在里面先把人物id及其相应的对话先写好。
例如我的一个dialogueTest.xml文件是这样写的:
<objects>
<Scenes SceneID="classroom">
<people id="student_1">
学生1:起立
people>
<people id="student_2">
学生2:老师好!
people>
<people id="student_3">
学生3:老师好!!
people>
<people id="teacher_1">
老师:同学们好!
people>
Scenes>
objects>
在读取时,我的脚本代码如下:
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
public class XMLDialogueTest : MonoBehaviour
{
public string _sceneID; //当前场景ID
// Use this for initialization
void Start () {
//传递Xml文件的路径,注意要在自己输的路径前加"/"号
InitXML(Application.dataPath+ "/XMLData/dialogueTest.xml");
}
//初始化xml,读取对话,将对话数据及其id传入数组
void InitXML(string path)
{
//新建一个XmlDocument对象
XmlDocument xml=new XmlDocument();
//判断xml文件是否存在
if (File.Exists(path))
{
print("读取到了");
//通过路径path加载xml
xml.Load(path);
//获取objects节点下的子节点
XmlNodeList xmlNodeList = xml.SelectSingleNode("objects").ChildNodes;
//遍历objects节点下的子节点
foreach (XmlElement xl1 in xmlNodeList)
{
//确认对话的场景ID
if(xl1.GetAttribute("SceneID")==_sceneID)
{
print("当前场景ID为"+xl1.GetAttribute("SceneID"));
//新建对话数组,用于存放对话
ArrayList dialogueList = new ArrayList(xl1.ChildNodes.Count);
//新建人物数组,用于存放对应的人物id
ArrayList NPCIDList = new ArrayList(xl1.ChildNodes.Count);
//遍历人物对话,将对话放入数组中
foreach (XmlElement xl2 in xl1.ChildNodes)
{
//InnerText能取得相应节点的内容
dialogueList.Add(xl2.InnerText);
//取得节点的属性id的值,即人物id
NPCIDList.Add(xl2.GetAttribute("id"));
}
//传递对话数组
DialogueListToText(dialogueList,NPCIDList);
}
}
}
}
//将对话输出到控制台
void DialogueListToText(ArrayList dialogueList,ArrayList NPCIDList)
{
for (int i = 0; i < dialogueList.Count; i++)
{
Debug.Log("ID为" + NPCIDList[i] +"的对话是:"+dialogueList[i]);
}
}
}
将该脚本放到场景后,需要将上面dialogueTest.xml文件放在正确的路径下:
运行场景,控制台输出结果如下:
注:该脚本目前只是实现了读取xml文件,取得其中的人物id及其相应的对话,并将其输出到控制台而已。里面我有个我认为有待改进的地方,其中在存放人物id及其对话时,我本来是想将其人物id及其对话结合起来存放在一个对象上,期间我想到使用字典(Dictionary)来存数据,将人物id作为字典对象的key,将对话内容作为value,但是考虑到一个人物是有多句对话的,这样就相当于一个key对应了多个value,且与他人的对话之间会有个先后顺序,这个放到字典里的话就体现不出来顺序关系了。故而目前只能通过同时新建两个数组,一个用于存放人物id,另一个用于存放对话,由于是同步存储节点的id及对话,便能保证其对话的顺序及对话人物id相对应,但毕竟是用两个数组分别存数据,因此对于这两个数组的操作要同时进行,同时如果其中一个数组的数据出现问题,势必会影响最后读取数据的结果,其中的风险可想而知,因此如果有其他更好的替代方法我会在后面的笔记中给出。至于如何将取到的人物id及其对话结合到游戏中的对话框,实现人物对话还有待我接下来的继续学习。
另注:如果要获取到节点的属性名(注意,是属性名,不是属性值,例如id=”student_1”其中id为属性名,student_1为属性id的值)时,因为在XmlElement类下有一个属性是Attributes,返回值为XmlAttributeCollection,而节点element的属性名则存储在XmlAttributeCollection下。所以可以在上面脚本中已获取到了xl2节点的情况下,可以通过以下代码取得其属性名:
XmlAttributeCollection xac = xl2.Attributes;
//遍历节点的属性,将属性传给数组
foreach (XmlAttribute xat in xac)
{
string str = xat.Name;
//输出节点的属性名
print(str);
}
参考资料:
C#获取属性名称
Unity中的XML文件创建,读取,修改,添加
[Unity3D]Unity3D游戏开发之Xml解析实现NPC对话系统