Saving data with XML

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.

Adding the required variables

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.

Saving the player data

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.

Saving the enemy data

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.129.253