用xml加NGUI实现角色信息存储或者存档,好了废话不多说先入正题,咱们开始做准备工作,这个教程使用的是NGUI3.0.6。
第一步:先导入NGUI、然后新建3个文件夹Scene、Script、Prefabs分别用来存放场景、脚本、预设,然后使用NGUI创建一个2DUI如图:
复制代码
复制代码
好了到现在为止咱们已经把核心代码搞定了,那么接下来咱们插播一点界面元素:
先将UICamera下的Anchor复制一个,分别命名为:Info(UIAnchor的side属性设为TopLeft)和Buttons(UIAnchor的side属性设为BottomRight),然后在Buttons的panel下创建一个按钮,给按钮添加一个label,复制这个按钮,修改名称分别为:Create、Load,并修改它们的label值为:创建角色,返回登录,结构如下:
然后设计信息面板,在Info的panel下创建一个空物体命名为Item(这里记得修改它的层为2DUI,并且reset它的transform)然后给Item添加一个Label和一个Input控件,然后将Item复制3个,并且将Label的内容修改成,姓名、职业、等级、经验(这些其实是从游戏里面读取的,这里就直接输入好了,其实在游戏存储的时候这些值都是知道的),然后给Info的panel添加一个ngui的UITable脚本设置Columns = 1 ,最终效果如下图:
复制代码
然后我们再去编写脚本,新建一个C#脚本,并命名为RoleListItem,这个脚本很简单,只是声明一个xmldatastructure变量与这个item绑定,代码如下:
复制代码
怎么样这代码很简单吧,后面会用到这个roleData,然后我们再新建一个脚本命名为RoleList,这个脚本用来读取xml文件的角色信息,并制作一个列表显示,其中又用到了委托,给按钮添加事件,代码如下:
复制代码
然后我们将RoleListItem脚本与RoleListItem这个物体绑定,新建一个预设,将RoleListItem这个Toggle拖进去,形成一个预设,删掉Info的子panel下的RoleListItem,然后将RoleList脚本拖给Info下的panel,并将上面的按钮变量正确的拖进去,其中的itemPrefab就是刚才新建的RolelistItem预设,效果如图:
然后我们将工程built设置一下,要按图中的顺序啊,如图:
然后将CreateRole脚本里面的Application.LoadLevel(1);(有2个地方有,共有2句,很好找)的注释去掉,现在我们跳转到第一个Scene,然后运行可以看到结果,当跳转到第2个场景的时候就有了刚才创建的角色信息了:第二个场景效果如图
好了到现在为止咱们做了角色信息的列表,如果是存档的话其中的输入就变成了玩家进入存档点时记录的信息了,原理是一样的,小弟将在以后的帖子中实现存档的制作。
第一步:先导入NGUI、然后新建3个文件夹Scene、Script、Prefabs分别用来存放场景、脚本、预设,然后使用NGUI创建一个2DUI如图:
第二步:咱们开始写第一个脚本,作为xml文件存储的数据结构,新建个C#脚本,命名为XmlDataStructure,这里就简单的定义一下角色信息(实际中肯定很复杂的,比如玩家的位置啊,当前血量,技能等级等等,这些大家可以自己建立,这里主要提供一个思路),我这里只定义了6个属性变量代码如下:
- using System;
- /// <summary>
- /// Xml data structure.定义一个xml存储的数据结构,数据以后可以扩展
- /// </summary>
- public class XmlDataStructure {
- /// <summary>
- /// The identifier.id索引、名称、职业、等级、剩余经验、创建时间
- /// </summary>
- public int id ;
- public string name ;
- public string occupation ;
- public int level ;
- public int freeExp ;
- public string createtime ;
- /// <summary>
- /// Initializes a new instance of the <see cref="XmlDataStructure"/> class.构造函数
- /// </summary>
- /// <param name="_id">_id.</param>
- /// <param name="_name">_name.</param>
- /// <param name="_occupation">_occupation.</param>
- /// <param name="_level">_level.</param>
- /// <param name="_freeexp">_freeexp.</param>
- /// <param name="_createtime">_createtime.</param>
- public XmlDataStructure(string _name ,string _occupation , int _level , int _freeexp , string _createtime){
- name = _name ;
- occupation = _occupation ;
- level = _level ;
- freeExp = _freeexp ;
- createtime = _createtime ;
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="XmlDataStructure"/> class.空构造函数
- /// </summary>
- public XmlDataStructure(){
-
- }
- }
这段代码很简单就定义了一个简单的类,来存放角色的信息,大家可以自己扩充。
然后创建第二个脚本,命名为XmlManager,这个是操作xml文件的核心类,所有xml的操作都在这个类里面,这个类有几个重要的函数:
AddRole-->这个函数负责将玩家数据写入xml文件
ClearXmlFile-->这个函数负责清空xml文件内容,也就是清除所有的角色信息(慎用)
ReFreshXmlId-->这个函数负责对xml文件里面的角色id重新排序,主要在xml里面有角色被删除的时候使用
GetDataFromXml-->这个函数是从xml文件中读取角色或者存档信息,结果保存在一个线性表里面
RemoveItemById-->这个函数是从xml文件中删除指定id的角色信息
代码如下:
然后创建第二个脚本,命名为XmlManager,这个是操作xml文件的核心类,所有xml的操作都在这个类里面,这个类有几个重要的函数:
AddRole-->这个函数负责将玩家数据写入xml文件
ClearXmlFile-->这个函数负责清空xml文件内容,也就是清除所有的角色信息(慎用)
ReFreshXmlId-->这个函数负责对xml文件里面的角色id重新排序,主要在xml里面有角色被删除的时候使用
GetDataFromXml-->这个函数是从xml文件中读取角色或者存档信息,结果保存在一个线性表里面
RemoveItemById-->这个函数是从xml文件中删除指定id的角色信息
代码如下:
- using System.IO;
- using System.Xml;
- using UnityEngine;
- using System;
- using System.Collections.Generic;
-
- public class XmlManager {
- public enum XmlRandS{
- xml_role ,
- xml_save
- };
- private static string XmlDir_Path = Application.dataPath + "/XmlDir" ;
- private XmlDocument _xmlDoc = new XmlDocument();
- public List<XmlDataStructure> dataSetList ;
-
- #region XmlRole_Path
- private string XmlRole_Path = XmlDir_Path + "/Roles.xml" ;
- private string XmlRole_root = "Roles" ;
- #endregion
-
- #region XmlSave_Path
- private string XmlSave_Path = XmlDir_Path + "/Saves.xml" ;
- private string XmlSave_root = "Saves" ;
- #endregion
-
- public XmlManager(){
- Init();
- }
- /// <summary>
- /// Init this instance.检测文件是否存在
- /// </summary>
- void Init(){
- if(!Directory.Exists(XmlDir_Path)){
- Directory.CreateDirectory(XmlDir_Path);
- }
- CheckAndCreateXml(XmlRole_Path,XmlRole_root);
- CheckAndCreateXml(XmlSave_Path,XmlSave_root);
- }
- /// <summary>
- /// Checks the and create xml.判断xml是否存在,不存在就创建一个,并同时创建根节点
- /// </summary>
- /// <param name="_name">_name.</param>
- /// <param name="_root">_root.</param>
- void CheckAndCreateXml(string _name , string _root){
- if(!File.Exists(_name)){
- //File.Create(_name);
- XmlDocument tempDoc = new XmlDocument();
- //tempDoc.Load(_name);
- XmlElement rootNode = tempDoc.CreateElement(_root);
- tempDoc.AppendChild(rootNode);
- tempDoc.Save(_name);
- }
- }
-
- /// <summary>
- /// Adds the role.向xml文件中添加一个角色或者添加一个存档
- /// </summary>
- /// <param name="_roleData">_role data.</param>
- /// <param name="r_and_s">R_and_s.</param>
- public void AddRole(XmlDataStructure _roleData,XmlRandS r_and_s){
- string _xmlpath = "";
- string newNodeName = "";
- switch(r_and_s){
- case XmlRandS.xml_role:
- _xmlpath = XmlRole_Path;
- newNodeName = "Role" ;
- break ;
- case XmlRandS.xml_save:
- _xmlpath = XmlSave_Path;
- newNodeName = "Save" ;
- break ;
- }
- _xmlDoc.Load(_xmlpath);
- if(!_xmlDoc.DocumentElement.HasChildNodes){
- _roleData.id = 0 ;
- }else{
- _roleData.id = Convert.ToInt32(_xmlDoc.DocumentElement.LastChild.Attributes[0].InnerText) + 1 ;
- }
-
- XmlElement newNode = _xmlDoc.CreateElement(newNodeName);
- newNode.SetAttribute("id",_roleData.id.ToString());
- newNode.SetAttribute("time",_roleData.createtime);
- _xmlDoc.DocumentElement.AppendChild(newNode);
-
- XmlElement nameNode = _xmlDoc.CreateElement("name");
- nameNode.InnerText = _roleData.name ;
- XmlElement occuNode = _xmlDoc.CreateElement("occu");
- occuNode.InnerText = _roleData.occupation ;
- XmlElement levelNode = _xmlDoc.CreateElement("level");
- levelNode.InnerText = _roleData.level.ToString() ;
- XmlElement expNode = _xmlDoc.CreateElement("exp");
- expNode.InnerText = _roleData.freeExp.ToString() ;
-
- newNode.AppendChild(expNode);
- newNode.AppendChild(levelNode);
- newNode.AppendChild(occuNode);
- newNode.AppendChild(nameNode);
-
- _xmlDoc.Save(_xmlpath);
- }
-
- /// <summary>
- /// Clears the xml file.清空整个xml文件
- /// </summary>
- /// <param name="r_and_s">R_and_s.</param>
- public void ClearXmlFile(XmlRandS r_and_s){
- string _xmlpath = "";
- switch(r_and_s){
- case XmlRandS.xml_role:
- _xmlpath = XmlRole_Path;
- break ;
- case XmlRandS.xml_save:
- _xmlpath = XmlSave_Path;
- break ;
- }
- _xmlDoc.Load(_xmlpath);
- _xmlDoc.DocumentElement.RemoveAll();
- _xmlDoc.Save(_xmlpath);
- }
- /// <summary>
- /// Res the fresh xml identifier.当xml中有节点被删除的时候从新排下节点的id。
- /// </summary>
- /// <param name="r_and_s">R_and_s.</param>
- public void ReFreshXmlId(XmlRandS r_and_s){
- string _xmlpath = "";
- switch(r_and_s){
- case XmlRandS.xml_role:
- _xmlpath = XmlRole_Path;
- break ;
- case XmlRandS.xml_save:
- _xmlpath = XmlSave_Path;
- break ;
- }
- _xmlDoc.Load(_xmlpath);
- if(_xmlDoc.DocumentElement.HasChildNodes){
- XmlNodeList _chilidlist = _xmlDoc.DocumentElement.ChildNodes ;
- int i = 0 ;
- foreach(XmlNode xn in _chilidlist){
- XmlElement xe = (XmlElement)xn ;
- xe.Attributes[0].InnerText = (i++).ToString();
- }
- }
- _xmlDoc.Save(_xmlpath);
- }
- /// <summary>
- /// Gets the data from xml.先打开xml然后读取xml里面的内容
- /// </summary>
- /// <returns>The data from xml.</returns>
- /// <param name="r_and_s">R_and_s.</param>
- public List<XmlDataStructure> GetDataFromXml(XmlRandS r_and_s){
- string _xmlpath = "";
- switch(r_and_s){
- case XmlRandS.xml_role:
- _xmlpath = XmlRole_Path;
- break ;
- case XmlRandS.xml_save:
- _xmlpath = XmlSave_Path;
- break ;
- }
- _xmlDoc.Load(_xmlpath);
- dataSetList = new List<XmlDataStructure>();
- if(_xmlDoc.DocumentElement.HasChildNodes){
- dataSetList.Clear();
- XmlNodeList _chilidlist = _xmlDoc.DocumentElement.ChildNodes ;
- foreach(XmlNode xn in _chilidlist){
- XmlElement xe = (XmlElement)xn ;
- XmlDataStructure xds = new XmlDataStructure(xe.ChildNodes[3].InnerText,
- xe.ChildNodes[2].InnerText,
- Convert.ToInt32(xe.ChildNodes[0].InnerText),
- Convert.ToInt32(xe.ChildNodes[1].InnerText),
- xe.Attributes[1].InnerText) ;
- xds.id = Convert.ToInt32(xe.Attributes[0].InnerText);
- dataSetList.Add(xds);
- }
- }
- _xmlDoc.Save(_xmlpath);
- return dataSetList ;
- }
- /// <summary>
- /// Removes the item by identifier.通过id属性找到节点,然后删除
- /// </summary>
- /// <param name="id">Identifier.</param>
- /// <param name="r_and_s">R_and_s.</param>
- public void RemoveItemById(int id , XmlRandS r_and_s){
- string _xmlpath = "";
- switch(r_and_s){
- case XmlRandS.xml_role:
- _xmlpath = XmlRole_Path;
- break ;
- case XmlRandS.xml_save:
- _xmlpath = XmlSave_Path;
- break ;
- }
- _xmlDoc.Load(_xmlpath);
- if(_xmlDoc.DocumentElement.HasChildNodes){
- XmlNodeList _chilidlist = _xmlDoc.DocumentElement.ChildNodes ;
- for(int i = 0 ; i < _chilidlist.Count ; ++i){
- if(_chilidlist[i].Attributes[0].InnerText == id.ToString()){
- _xmlDoc.DocumentElement.RemoveChild(_chilidlist[i]);
- break;
- }
- }
- }
- _xmlDoc.Save(_xmlpath);
- //ReFreshXmlId(r_and_s);
- }
- }
先将UICamera下的Anchor复制一个,分别命名为:Info(UIAnchor的side属性设为TopLeft)和Buttons(UIAnchor的side属性设为BottomRight),然后在Buttons的panel下创建一个按钮,给按钮添加一个label,复制这个按钮,修改名称分别为:Create、Load,并修改它们的label值为:创建角色,返回登录,结构如下:
然后设计信息面板,在Info的panel下创建一个空物体命名为Item(这里记得修改它的层为2DUI,并且reset它的transform)然后给Item添加一个Label和一个Input控件,然后将Item复制3个,并且将Label的内容修改成,姓名、职业、等级、经验(这些其实是从游戏里面读取的,这里就直接输入好了,其实在游戏存储的时候这些值都是知道的),然后给Info的panel添加一个ngui的UITable脚本设置Columns = 1 ,最终效果如下图:
2013-12-30 09:33 上传
下载附件 (83.75 KB)
嗯现在大家可以看到已经可以输入了,现在咱们再回到脚本上来,新建一个C#脚本,命名为CreateRole,脚本如下:
- using UnityEngine;
- using System.Collections;
- using System;
- public class CreateRole : MonoBehaviour {
- private XmlDataStructure role ;
- private XmlManager xmlMan ;
- /// <summary>
- /// The name input.获取几个input,得到他们的内容
- /// </summary>
- public UIInput nameInput ;
- public UIInput occuInput ;
- public UIInput levelInput ;
- public UIInput expInput ;
-
- public UIButton _backlaod ;
- void Start(){
- xmlMan = new XmlManager();
-
- EventDelegate.Add(_backlaod.onClick,delegate() {
- //Application.LoadLevel(1);
- });
- }
- /// <summary>
- /// Raises the click event.点击创建按钮新建一个角色,然后添加到xml文件里面去
- /// </summary>
- void OnClick(){
- try{
- if(xmlMan.GetDataFromXml(XmlManager.XmlRandS.xml_role).Count >=5){
- print("你已经拥有5个角色,如果需要继续创建,请先删除");
- }else{
- role = new XmlDataStructure(nameInput.value,
- occuInput.value,
- Convert.ToInt32(levelInput.value),
- Convert.ToInt32(expInput.value),
- DateTime.Now.ToShortDateString());
- xmlMan.AddRole(role,XmlManager.XmlRandS.xml_role);
- //Application.LoadLevel(1);
- }
- }
- catch{
- print("请输入正确的格式like,int 、 int 、 string 、 string");
- }
- }
- }
这个脚本的目的是读取
input
里面的内容,然后写入到
xml
文件里面去,然后通过给按返回登录钮添加委托,实现界面的跳转(当然啦这里大家可以不用委托,在写个脚本给返回登录按钮,在
OnClick
里面调用
loadlevel
也行,不过我觉得这样脚本多了不好控制);
把这个脚本绑给Create按钮,并且把上面的那几个input分别拖进去对应起来,将Load按钮托给_load变量,那么输入后,点击Create后,我们退出后可以看到项目下面多出了一个xmlDir的文件夹,里面有Role和Save这2个xml文件,并且Role里面的内容就是刚才输入的信息,效果如下:
把这个脚本绑给Create按钮,并且把上面的那几个input分别拖进去对应起来,将Load按钮托给_load变量,那么输入后,点击Create后,我们退出后可以看到项目下面多出了一个xmlDir的文件夹,里面有Role和Save这2个xml文件,并且Role里面的内容就是刚才输入的信息,效果如下:
好了接下来我们开始做角色列表,在Prefabs下创建一个叫UIPrefab的Prefab,然后将UIRoot拖给这个Prefab形成一个预设,再将这个scene保存,然后新建一个scene,将UIPrefab拖进去,然后删掉delete按钮,把Create身上的CreateRole脚本删掉并将Create按钮复制2个,并改名Delete和Load,然后将他们的label分别改为:返回创建、删除角色、进入游戏,继续将Info的panel的所有子项清空,结果如下:
然后在panel下创建一个Toggle并命名为RoleListItem,修改它的Label位置最终效果如下:
然后我们再去编写脚本,新建一个C#脚本,并命名为RoleListItem,这个脚本很简单,只是声明一个xmldatastructure变量与这个item绑定,代码如下:
- using UnityEngine;
- using System.Collections;
-
- public class RoleListItem : MonoBehaviour {
- public XmlDataStructure roleData ;
- // Use this for initialization
- void Awake(){
- roleData = new XmlDataStructure();
- EventDelegate.Add(GetComponent<UIButton>().onClick,delegate() {
- //print(roleData.id);
- });
- }
-
-
- // Update is called once per frame
- void Update () {
-
- }
- }
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
-
- public class Rolelist : MonoBehaviour {
- /// <summary>
- /// The _create.声明3个按钮变量
- /// </summary>
- public UIButton _create ;
- public UIButton _delete ;
- public UIButton _load ;
-
- private XmlManager xmlMan ;
- /// <summary>
- /// The roles list.声明一个存放角色的线性表
- /// </summary>
- private List<XmlDataStructure> rolesList ;
- /// <summary>
- /// The item prefab.这个是item预设
- /// </summary>
- public GameObject itemPrefab ;
- // Use this for initialization
- void Start () {
- xmlMan = new XmlManager();
- LoadRoles();
- /// <summary>
- /// EventDelegate.给3个按钮添加事件
- /// </summary>
- EventDelegate.Add(_create.onClick,delegate() {
- Application.LoadLevel(0);
- });
- EventDelegate.Add(_delete.onClick,delegate() {
- try{
- xmlMan.RemoveItemById(UIToggle.GetActiveToggle(1).gameObject.GetComponent<RoleListItem>().roleData.id,
- XmlManager.XmlRandS.xml_role);
- Destroy(UIToggle.GetActiveToggle(1).gameObject);
- gameObject.GetComponent<UITable>().Reposition();
- }catch{
- print("您还没有角色,请先创建角色");
- }
- });
- EventDelegate.Add(_load.onClick,delegate() {
- try{
- print("你选择登录的角色信息为:"+UIToggle.GetActiveToggle(1).gameObject.GetComponent<RoleListItem>().roleData.id+
- "姓名:"+UIToggle.GetActiveToggle(1).gameObject.GetComponent<RoleListItem>().roleData.name+
- "门派:"+UIToggle.GetActiveToggle(1).gameObject.GetComponent<RoleListItem>().roleData.occupation);
- }catch{
- print("请选择要登录的角色");
- }
- });
- }
- /// <summary>
- /// Loads the roles.从xml文件读取信息,并创建item然后将信息与item绑定
- /// </summary>
- void LoadRoles(){
- rolesList = new List<XmlDataStructure>();
- rolesList = xmlMan.GetDataFromXml(XmlManager.XmlRandS.xml_role);
- foreach(XmlDataStructure role in rolesList){
- GameObject itemClone = (GameObject)Instantiate(itemPrefab,transform.position,Quaternion.identity);
- itemClone.transform.parent = this.transform;
- itemClone.transform.localScale = new Vector3(1,1,1);
- RoleListItem itemScript = itemClone.GetComponent<RoleListItem>();
- itemScript.roleData.id = role.id ;
- itemScript.roleData.occupation = role.occupation;
- itemScript.roleData.name = role.name;
- itemScript.roleData.level = role.level;
- itemScript.roleData.freeExp = role.freeExp;
- itemScript.roleData.createtime = role.createtime;
- itemClone.GetComponentInChildren<UILabel>().text = "名称:"+itemScript.roleData.name+
- "\n门派:"+itemScript.roleData.occupation+
- "\n等级:"+itemScript.roleData.level+
- "\n时间:"+itemScript.roleData.createtime;
- }
- //gameObject.GetComponent<UITable>().Reposition
- }
- // Update is called once per frame
- /// <summary>
- /// Update this instance.如果当前没有选择角色或者没有角色,删除和进入游戏按钮不可用
- /// </summary>
- void Update () {
- if(rolesList.Count <= 0 || UIToggle.GetActiveToggle(1) == null){
- _load.enabled = false ;
- _delete.enabled = false ;
- }else{
- _load.enabled = true ;
- _delete.enabled = true ;
- }
- }
- }
然后我们将工程built设置一下,要按图中的顺序啊,如图:
然后将CreateRole脚本里面的Application.LoadLevel(1);(有2个地方有,共有2句,很好找)的注释去掉,现在我们跳转到第一个Scene,然后运行可以看到结果,当跳转到第2个场景的时候就有了刚才创建的角色信息了:第二个场景效果如图
好了到现在为止咱们做了角色信息的列表,如果是存档的话其中的输入就变成了玩家进入存档点时记录的信息了,原理是一样的,小弟将在以后的帖子中实现存档的制作。