To create something that can save files, we'll need to cover new territory. We've already discussed working with PlayerPrefs
back in Chapter 5, Shooting Gallery – Working with Animations and Tweens, but there can be a time when you want to save things other than just string
, int
, or float
variables. To deal with complex data types, there are more things that we can do. Perform the following steps:
Gameplay
) from the link described in the project setup.Scripts
folder and create a new C# script named LevelEditor
. With this finished, open your IDE.GameController.cs
file and highlight the level
variable. Cut it (Ctrl + X) and paste it (Ctrl + V) as a declaration in the LevelEditor
class.BuildLevel
function from the file and stop it from being called in our GameController
script's Start
function. Instead of calling it here, we will be writing a new version for our new LevelEditor
script.Next, we want access to our goalPS
variable inside the LevelEditor
class so that we have a reference to the particle system to turn to when we collect all the orbs, but right now, it's private. Now, I could set this variable as being public
and be done with it, but instead, we're going to use another aspect of programming in C# named properties.
goalPS
variable declaration:public ParticleSystem GoalPS { get { return goalPS; } set { goalPS = value; } }
This will allow us to access this newly created GoalPS
variable to modify goalPS
(our original one). The value that you see in the set
function is a keyword that will be assigned.
Now, you may be asking why you should do this instead of making it public
. There are two main reasons. First, we are allowed to use get
and set
just like a normal function. This will allow us to check the value of the variable before we actually assign something, which can be really useful if you want to make sure that a variable is within a certain range. Take a look at the following code:
private int health; public int Health { get { return health; } set { // Value can only be up to 100 health = value % 100; if(health <= 0) print ("I'm dead"); } }
Also, by omitting either set
or get
, we can say that the variable cannot be changed outside of the class or accessed outside of the class.
For more information on properties, check out http://unity3d.com/learn/tutorials/modules/intermediate/scripting/properties.
We will also no longer need the variables for our object references, so go ahead and remove the following lines in our GameController script:
[Header("Object References")] public Transform wall; public Transform player; public Transform orb; public Transform goal;
Now that our level is no longer being created in the GameController
, let's add the functionality back to our LevelEditor
. Perform the following steps:
void BuildLevel() { //Go through each element inside our level variable for (int yPos = 0; yPos < level.Length; yPos++) { for (int xPos = 0; xPos < (level[yPos]).Length; xPos++) { CreateBlock(level[yPos][xPos], xPos, level.Length - yPos); } } }
CreateBlock
function, so right now, it'll show up as being red, but before we add it in, we need to create some variables:int xMin = 0; int xMax = 0; int yMin = 0; int yMax = 0; public List<Transform> tiles; GameObject dynamicParent;
List
type will show up in red. This is because it doesn't know what we're talking about. Add the following line to our using
statements up at the top of the file:using System.Collections.Generic; // Lists
We used arrays previously in this book, which are containers for multiple copies of an object. One of the problems with arrays is the fact that you have to know the size (or how many elements) of the array in advance, and you cannot add or subtract elements from the array.
The list type is basically a dynamically sized array, which is to say that we can add and remove elements from it at any point that we want. It also gives us access to some nice helper functions such as IndexOf
(which will return to us the index of an element in a list, something that can be really useful when using the index operator []
).
For more information on lists, check out http://unity3d.com/learn/tutorials/modules/intermediate/scripting/lists-and-dictionaries.
CreateBlock
function, as follows:public void CreateBlock(int value, int xPos, int yPos) { Transform toCreate = null; // We need to know the size of our level to save later if(xPos < xMin) { xMin = xPos; } if(xPos > xMax) { xMax = xPos; } if(yPos < yMin) { yMin = yPos; } if(yPos > yMax) { yMax = yPos; } //If value is set to 0, we don't want to spawn anything if(value != 0) { toCreate = tiles[value-1]; } if(toCreate != null) { //Create the object we want to create Transform newObject = Instantiate(toCreate, new Vector3(xPos, yPos, 0), Quaternion.identity) as Transform; //Give the new object the same name as ours newObject.name = toCreate.name; if(toCreate.name == "Goal") { // We want to have a reference to the particle system // for later GameController._instance.GoalPS = newObject.gameObject.GetComponent<ParticleSystem>(); // Move the particle system so it'll face up newObject.transform.Rotate(-90,0,0); } // Set the object's parent to the DynamicObjects // variable so it doesn't clutter our Hierarchy newObject.parent = dynamicParent.transform; } }
Start
function, as follows:public void Start() { // Get the DynamicObjects object so we can make it our // newly created objects' parent dynamicParent = GameObject.Find("Dynamic Objects"); BuildLevel(); enabled = false; }
As we used previously, the GameObject.Find
function looks within our scene to find an object with the name Dynamic Objects. If it does not find the object, it will return null
. It's always a good idea to make sure that the value is not null
, or you may be wondering why something in your code doesn't work when it's a spelling error or something of that sort. It's important to note that case is important and that DynamicObjects and dynamicObjects are different! If anything is different, it will not work:
if(dynamicParent == null) { print("Object not found! Check spelling!"); }
This function should be used only on seldom occasions, as it can be quite slow. For more information on GameObject.Find
, check out http://docs.unity3d.com/ScriptReference/GameObject.Find.html.
Next, go back to Inspector and attach the LevelEditor
script to the GameController object by dragging the script file on top of it. Afterward, open up the Tiles variable and change Size to 4
. Then, go to the Prefabs
folder and drag Wall
, Player
, Collectible
, and Goal
to the Element 0, Element 1, Element 2, and Element 3 variables, respectively.
You'll note that now, the class creates our level and then turns itself off—a great start for our level editor!