前言
- 本内容为本人原创提供
- 本内特为学习者提供原创完整的工程源码下载,可参考学习或其他用途。
- 本内容从角色相关属性出发,对数据存取操作,一步一步推进,能直观感受。
- 如果后续有其他的存取游戏数据的方式,将继续提供给大家借鉴参考,希望能协助大家完成自己项目。
目录
写着写着就这么多了,可能不是特别全,不介意费时就看看吧。有时间还会接着更新。
一、什么是xml
XML是扩展标记语言,也是一种与HTML非常相似的标记语言,被设计用于存储和传输数据,XML 1.0正式版于1998年发布。
XML使用一个简单而又灵活的标准格式,为基于Web的应用提供了一个描述数据和交换数据的有效手段,当然也能作为本地数据交换的一种方法。用于软件/框架的配置文件,保存和传输数据。
二、xml全认识
1、xml第一行都是固定的文档声明,1.0版本是W3C组织于2000年发布的xml10规范。
2、encoding是整个文档的编码方式,这里我们不用去动它。
例如:
<?xml version="1.0" encoding="utf-8"?>
3、xml 只能有一个根标签,文章或英或中都可以,跟标签有开头也必须有结束,处于闭合状态。
例如:
<root>
<player> </player>
<玩家> </玩家>
</root>
注意:<root>为根标签,</root>是闭合状态。
4、标签内部和下一级中可以插入内容。
比如:第一种
<game>
<player id="10005">
<类型>战士</类型>
<HP>200</HP>
</player>
</game>
第二种,也可以这样写:
<game>
<player 类型="战士" HP="00">10005</player>
</game>
元素的值必须用 “ ” 框住。
两种方式根据自己喜好或者对解析方式的熟练程度。本文采用第一种方式。
4、xml标签命名有约束:
- 不能有空格。
- 不能有冒号。
- 不能以数字和下划线开头(特别注意这一点)。
- 若是英文,开头和结束大小写必须一致。
5、xml可以使用一些特殊符号
例如:
< <
> >
& &
" "
' '
如果xml元素中只有字符 < 或者 & ,这是非法的。< 会被认为是标签头,& 会被误认为是实体。
简而言之,标签外谨慎使用。
6、DTD约束
主要规范xml文档,DTD顺序排序安装约束我们编写xml,这里了解一下即可。
<game>
<player id="10005">
<类型>战士</类型>
<HP>200</HP>
</player>
</game>
<!Element 类型 (#PCDATA)>
<!Element HP (#PCDATA)>
最后注意文档不要弄错格式哟,xml保存的文件后缀以 xxx.xml 结尾。当然,也只能读取xml后缀文件。
三、unity实战
本次实战采用玩家属性单元展开,对玩家的属性进行存档和读档操作。
1、c#对xml操作的起始工作
1.1、玩家属性:
首先,把玩家内容属性规范好,可以创建玩家结构体,或者类。如果数据多,并且比较复杂,可以选择类,我这里选择创建一个玩家类:
public class Player
{
public int role_id { get; set; }
public string role_name { get; set; }
public int role_hp { get; set; }
public int role_mp { get; set; }
public int role_atc { get; set; }
public int role_def { get; set; }
public Dictionary<string,int> role_bag { get; set; }
}
1.2、C#引用:
c#解析xml需要引用:
using System.Xml;
unity对File文件进行操作,需要引用:
using UnityEngine.Windows;
1.3、文件路径
文件路径设置
private string xmlPath = Application.dataPath + "/Save/gamexml.xml";
2、创建xml文件
创建一个xml文件,如果你喜欢手写xml可以选择手写xml,这里用c#方法创建xml文件:
2.1、检测文件
public bool IsHaveXmlDoc()
{
//检测文件是否存在在xmlpath路径中
return File.Exists(xmlPath);
}
2.2、创建一个xml文件
XmlDocument myxmlDoc = new XmlDocument();
// 创建Xml declaration
XmlDeclaration xmlDeclaration =
myxmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null);
myxmlDoc.AppendChild(xmlDeclaration);
2.3、创建根元素
xml文件中创建一个根元素
// 根元素
XmlElement rootElement = myxmlDoc.CreateElement("Roles");
myxmlDoc.AppendChild(rootElement);
根元素下创建玩家属性元素
// Player元素
XmlElement playerElement = myxmlDoc.CreateElement("Player");
将元素添加到刚才创建的player元素中
// 添加子元素到Player元素 Name Hp MP .....
XmlElement childElement = myxmlDoc.CreateElement("Name");
childElement.InnerText = "主角";
playerElement.AppendChild(childElement);
childElement = myxmlDoc.CreateElement("Hp");
childElement.InnerText = "1000";
playerElement.AppendChild(childElement);
childElement = myxmlDoc.CreateElement("MP");
childElement.InnerText = "20";
playerElement.AppendChild(childElement);
childElement = myxmlDoc.CreateElement("atc");
childElement.InnerText = "5";
playerElement.AppendChild(childElement);
childElement = myxmlDoc.CreateElement("def");
childElement.InnerText = "3";
playerElement.AppendChild(childElement);
childElement = myxmlDoc.CreateElement("bag");
// (num,num)(id和数量)
childElement.InnerText = "(00003,2)|((00007,8)|((00017,99)|((00011,2)|((00006,18)";
playerElement.AppendChild(childElement);
rootElement.AppendChild(playerElement);
注意:如果CreateElement是根开头,在xml中可以表示为:<root>。
那么 AppendChild方法是根结束,可以表示为</root>。
最后是保存xml文件
myxmlDoc.Save(xmlPath);
2.4、保存的xml数据
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Player>
<Name>主角</Name>
<Hp>40</Hp>
<MP>65</MP>
<atc>12</atc>
<def>76</def>
<bag>(00003,2)|(00007,8)|(00017,99)|(00011,2)|(00006,18)</bag>
</Player>
<Enemy01>
<Name>豆豆怪</Name>
<Hp>100</Hp>
<MP>0</MP>
<atc>2</atc>
<def>1</def>
</Enemy01>
</Roles>
3、保存文件
保存文件与创建文件有极大相似,所以尽量简短内容
3.1、路径读取和获取节点
读取路径中的xml文件
XmlDocument myxml = new XmlDocument();
myxml.Load(xmlPath);
获取“Roles”根节点中的元素
XmlNodeList list = myxml.GetElementsByTagName("Roles");
3.2、声明游戏管理类
实现一个游戏属性管理类,并单例它,同时声明 myPlayer 方便管理我们的玩家属性
public class Gamemanager : MonoBehaviour
{
public Player myPlayer;
private static Gamemanager _instance;
public static Gamemanager Instance
{
get
{
if (_instance == null)
{
_instance = new Gamemanager();
}
return _instance;
}
}
}
3.3、玩家属性保存
回到xml管理类,将玩家属性赋予节点元素的InnerText
XmlNode nd = node.ChildNodes[0];
// 角色赋值给InnerText存数据
nd.ChildNodes[0].InnerText = Gamemanager.Instance.myPlayer.role_name;
nd.ChildNodes[1].InnerText = Gamemanager.Instance.myPlayer.role_hp.ToString();
nd.ChildNodes[2].InnerText = Gamemanager.Instance.myPlayer.role_mp.ToString();
nd.ChildNodes[3].InnerText = Gamemanager.Instance.myPlayer.role_atc.ToString();
nd.ChildNodes[4].InnerText = Gamemanager.Instance.myPlayer.role_def.ToString();
int i = 0;
//将玩家的字典属性赋值给InnerText
nd.ChildNodes[5].InnerText = string.Empty;// 初始化
foreach (var item in Gamemanager.Instance.myPlayer.role_bag)
{
string str = i == (Gamemanager.Instance.myPlayer.role_bag.Count - 1) ? string.Empty : "|";
nd.ChildNodes[5].InnerText += "(" + item.Key + "," + item.Value + ")" + str;
i++;
}
记得保存文件
myxml.Save(xmlPath);
4、读取文件
3.1、按路径获取文件
// 按路径读取的xml文档
XmlDocument myxml = new XmlDocument();
myxml.Load(xmlPath);
3.2、读取根元素并赋值
读取指定的节点,获得元素节点集合
XmlNodeList list = myxml.GetElementsByTagName("Roles");
赋值给玩家
//获取节点
XmlNode node = list[0];
if (node.ChildNodes[0].Name == "Player")
{
XmlNode nd = node.ChildNodes[0];
//将节点内的集合值,InnerText 给角色赋值
Gamemanager.Instance.myPlayer = new Player()
{
role_id = 0,
role_name = nd.ChildNodes[0].InnerText.ToString(),
role_hp = int.Parse(nd.ChildNodes[1].InnerText.ToString()),
role_mp = int.Parse(nd.ChildNodes[2].InnerText.ToString()),
role_atc = int.Parse(nd.ChildNodes[3].InnerText.ToString()),
role_def = int.Parse(nd.ChildNodes[4].InnerText.ToString()),
role_bag = ReadBag(nd.ChildNodes[5].InnerText.ToString()),
};
}
3.3、读取背包
背包是Dictionary<string,int>类型,存有编号和物品的 int 数量,用 () 归组,以 | 线分开。
读取它们时候,我们要解析上面符号,如下:
private Dictionary<string,int> ReadBag(string str)
{
Dictionary<string, int> dic = new Dictionary<string, int>();
string[] tarry = str.Split('|');
string s = string.Empty;
for (int i = 0; i < tarry.Length; i++)
{
s = tarry[i].Replace("(", "").Replace(")","");
string[] t = s.Split(",");
dic.Add(t[0], int.Parse(t[1]));
}
return dic;
}
结果返回 Dictionary 中
5、删除文件
按路径删除xml文件
public void DeleteXmlDoc()
{
if (IsHaveXmlDoc())
File.Delete(xmlPath);
}
四、其他xml数据处理方式
//读取节点集合
public XmlNodeList ReadXmlNodeList(XmlDocument myxml, string str)
{
return myxml.GetElementsByTagName(str);
}
//获取XmlNode
public XmlNode ReadXmlNode(XmlNodeList nodelist, int index, string name)
{
return nodelist[index].Name.Equals(name) ? null : nodelist[0];
}
//读取某个元素的InnerText值
public string ReadSingleInnerText(XmlNode node, int index)
{
return node.ChildNodes[index].InnerText;
}
五、运行图示
六、总结
- 不要创建过多的子节点,避免出现大量多层嵌套,让xml数据看上去非常复杂。
- 可以创建分别玩家.xml,技能.xml,将他们分开;也可以将各种系统属性统一到一个xml中。
- 数据可以直接从xml中全部读取,也可以根据条件读取某条数据,根据实际情况使用。
- 玩家属性数据需创建一个独立类,作为游戏实体与数据之间的中介,保证数据的独立性。