Now, you will learn how to save to your XML files and use the nodes we created within the XML files that we just created.
Before we start adding variables, we need to make sure that we have all the using
statements required. Add these to your script if you don't have them already:
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Xml; using System.Xml.Serialization; using System.IO; using System.Text;
Next, we will add our variables to the script. For an XML-saving system, we will use more variables than we did while using a flat file. This is because, to test our XML system, we will save the player's transform data as well as the transform data for multiple enemies. Add these variables to your script:
XmlDocument xPlayer = new XmlDocument(); XmlDocument xEnemy = new XmlDocument(); public string pFileName = ""; public string eFileName = ""; public GameObject Player; public GameObject[] Enemies;
Our first two variables are XML documents; these variables hold the data from our XML files in our computer. The next two strings hold the directory and filename with the extension of the XML files that we are using. Finally, we have two GameObject
variables, with the first one being for our player and the other one being an array of GameObjects
to hold our enemies.
Now, we will add the function we will call to save our player data. Add this function to your script:
void SavePlayer() { if(Player != null) { XmlNode root = xPlayer.FirstChild; foreach(XmlNode node in root.ChildNodes) { switch(node.Name) { case "xPos": node.InnerText = Player.transform.position.x.ToString(); break; case "yPos": node.InnerText = Player.transform.position.y.ToString(); break; case "zPos": node.InnerText = Player.transform.position.z.ToString(); break; case "xRot": node.InnerText = Player.transform.rotation.x.ToString(); break; case "yRot": node.InnerText = Player.transform.rotation.y.ToString(); break; case "zRot": node.InnerText = Player.transform.rotation.z.ToString(); break; case "xScale": node.InnerText = Player.transform.localScale.x.ToString(); break; case "yScale": node.InnerText = Player.transform.localScale.y.ToString(); break; case "zScale": node.InnerText = Player.transform.localScale.z.ToString(); break; } } xPlayer.Save(pFileName); } }
When we call this function, we first check whether there is actually a GameObject in our Player
variable. If there isn't, then no saving will be done. Next, we declare an XmlNode
variable, which will be our root node from the XML document. After this, we run a foreach
loop that will find all of our child nodes within that root node.
To find specific nodes, we check the name property of that node, which actually is what we typed to create that node. In the switch statement, we look for each node that we want to save data to. For every node in XML, we set its InnerText
value to its associating value from our player's GameObject. The InnerText
property of a node is the data it holds and is what we will save to and load from.
Finally, we call the Save
function from our xPlayer XmlDocument
variable and pass it to the directory and filename we set in our pFileName
variable.
We will add the function to save our enemy data. This function will look similar to our function to save player data, except with a little more complication since we will be intending this function to save for multiple enemies. Add this function to your script now, just below the SavePlayer
function:
void SaveEnemies() { xEnemy.RemoveAll(); XmlNode eRoot = xEnemy.CreateNode(XmlNodeType.Element, "eData", ""); string[] nodes = {"name", "xPos", "yPos", "zPos", "xRot", "yRot", "zRot", "xScale", "yScale", "zScale"}; for(int e = 0; e < Enemies.Length; e++) { if(Enemies[e] != null) { XmlNode eBase = xEnemy.CreateNode(XmlNodeType.Element, "enemy", ""); for(int n = 0; n < nodes.Length; n++) { XmlNode newNode = xEnemy.CreateNode(XmlNodeType.Element, nodes[n], ""); eBase.AppendChild(newNode); } foreach(XmlNode node in eBase.ChildNodes) { switch(node.Name) { case "name": node.InnerText = Enemies[e].name; break; case "xPos": node.InnerText = Enemies[e].transform.position.x.ToString(); break; case "yPos": node.InnerText = Enemies[e].transform.position.y.ToString(); break; case "zPos": node.InnerText = Enemies[e].transform.position.z.ToString(); break; case "xRot": node.InnerText = Enemies[e].transform.rotation.x.ToString(); break; case "yRot": node.InnerText = Enemies[e].transform.rotation.y.ToString(); break; case "zRot": node.InnerText = Enemies[e].transform.rotation.z.ToString(); break; case "xScale": node.InnerText = Enemies[e].transform.localScale.x.ToString(); break; case "yScale": node.InnerText = Enemies[e].transform.localScale.y.ToString(); break; case "zScale": node.InnerText = Enemies[e].transform.localScale.z.ToString(); break; } eRoot.AppendChild(eBase); } xEnemy.AppendChild(eRoot); } } xEnemy.Save(eFileName); }
In the first line, we call the RemoveAll
function from the xEnemy XmlDocument
variable. This deletes all of the nodes from the XML document. We do this for simplicity's sake, this allows us to avoid the hassle of searching for specific enemy nodes to save data from a specific enemy. Next, we create a couple of variables. The first one will be our root node that holds all of our enemies. The next one is a string array, which will hold the names of nodes we will use later on.
The next step in this function is to use a for
loop to iterate through our enemies' GameObject
array; this is to check whether we actually have an enemy GameObject
in our array. If it runs into a null, it won't save any data for that spot.
Once we check to see that we don't have a null GameObject, we start creating our XML data. First, we create a new XmlNode
variable, which will be the root node for our enemy data. Next, we run a for
loop to create new nodes for each of the variables that we want to save. We do this by creating a new node and setting its name to one of the strings in our nodes string array. Finally, we append it as a child to our enemy root node.
Now that we have created the enemy node and added all of the child nodes that we want to save to, let's iterate through those nodes and start saving our data. To check each node, we create a foreach
loop like we did to save the player data and check the names for each of the eBase
child nodes.
After finding each of the specific nodes, we assign InnerText
with the value associating nodes with the current enemy GameObject. Once all the nodes have been assigned, we append the eBase
node to the root node. We do this process for each of the GameObjects within the enemies' GameObject
array, saving the data for each of them.
Finally, to end the function, we call the Save
function of our xEnemy
XML document and save the data to our EnemyData
XML document.
18.118.9.197