Monday, August 15, 2016

Creating Dynamic 2D Water Effects in Unity_part 2 (end)

Creating Our Collisions

Now we want our collider too:
  1. colliders[i] = new GameObject();
  2. colliders[i].name = "Trigger";
  3. colliders[i].AddComponent<BoxCollider2D>();
  4. colliders[i].transform.parent = transform;
  5. colliders[i].transform.position = new Vector3(Left + Width * (i + 0.5f) / edgecount, Top - 0.5f, 0);
  6. colliders[i].transform.localScale = new Vector3(Width / edgecount, 1, 1);
  7. colliders[i].GetComponent<BoxCollider2D>().isTrigger = true;
  8. colliders[i].AddComponent<WaterDetector>();
Here, we're making box colliders, giving them a name so they're a bit tidier in the scene, and making them each children of the water manager again. We set their position to be halfway between the nodes, set their size, and add a WaterDetector class to them.

Now that we have our mesh, we need a function to update it as the water moves:
  1. void UpdateMeshes()
  2.     {
  3.         for (int i = 0; i < meshes.Length; i++)
  4.         {
  5.  
  6.             Vector3[] Vertices = new Vector3[4];
  7.             Vertices[0] = new Vector3(xpositions[i], ypositions[i], z);
  8.             Vertices[1] = new Vector3(xpositions[i+1], ypositions[i+1], z);
  9.             Vertices[2] = new Vector3(xpositions[i], bottom, z);
  10.             Vertices[3] = new Vector3(xpositions[i+1], bottom, z);
  11.  
  12.             meshes[i].vertices = Vertices;
  13.         }
  14.     }
You might notice that this function just uses the code we wrote before. The only difference is that this time we don't have to set the tris and UVs, because these stay the same.

Our next task is to make the water itself work. We'll use FixedUpdate() to modify them all incrementally.
  1. void FixedUpdate()
  2. {
Implementing the Physics

First, we're going to combine Hooke's Law with the Euler method to find the new positions, accelerations and velocities.

So, Hooke's Law is \(F = kx\), where \(F\) is the force produced by a spring (remember, we're modelling the surface of the water as a row of springs), \(k\) is the spring constant, and \(x\) is the displacement. Our displacement is simply going to be the y-position of each node minus the base height of the nodes.

Next, we add a damping factor proportional to the velocity of the force to dampen the force.
  1. for (int i = 0; i < xpositions.Length ; i++)
  2.         {
  3.             float force = springconstant * (ypositions[i] - baseheight) + velocities[i]*damping ;
  4.             accelerations[i] = -force;
  5.             ypositions[i] += velocities[i];
  6.             velocities[i] += accelerations[i];
  7.             Body.SetPosition(i, new Vector3(xpositions[i], ypositions[i], z));
  8.         }
The Euler method is simple; we just add the acceleration to the velocity and the velocity to the position, every frame.

Note: I just assumed the mass of each node was 1 here, but you'll want to use:
  1. accelerations[i] = -force/mass;
if you want a different mass for your nodes.

Tip: For precise physics, we would use Verlet integration, but because we're adding damping, we can only use the Euler method, which is a lot quicker to calculate. Generally, though, the Euler method will exponentially introduce kinetic energy from nowhere into your physics system, so don't use it for anything precise.

Now we're going to create wave propagation. The following code is adapted from Michael Hoffman's tutorial.
  1. float[] leftDeltas = new float[xpositions.Length];
  2. float[] rightDeltas = new float[xpositions.Length];
Here, we create two arrays. For each node, we're going to check the height of the previous node against the height of the current node and put the difference into leftDeltas.

Then, we'll check the height of the subsequent node against the height of the node we're checking, and put that difference into rightDeltas. (We'll also multiply all values by a spread constant).
  1. for (int j = 0; j < 8; j++)
  2. {
  3.     for (int i = 0; i < xpositions.Length; i++)
  4.     {
  5.         if (i > 0)
  6.         {
  7.             leftDeltas[i] = spread * (ypositions[i] - ypositions[i-1]);
  8.             velocities[i - 1] += leftDeltas[i];
  9.         }
  10.         if (i < xpositions.Length - 1)
  11.         {
  12.             rightDeltas[i] = spread * (ypositions[i] - ypositions[i + 1]);
  13.             velocities[i + 1] += rightDeltas[i];
  14.         }
  15.     }
  16. }
We can change the velocities based on the height difference immediately, but we should only store the differences in positions at this point. If we changed the position of the first node straight off the bat, by the time we looked at the second node, the first node will have already moved, so that'll ruin all our calculations.
  1. for (int i = 0; i < xpositions.Length; i++)
  2. {
  3.     if (i > 0) 
  4.     {
  5.         ypositions[i-1] += leftDeltas[i];
  6.     }
  7.     if (i < xpositions.Length - 1) 
  8.     {
  9.         ypositions[i + 1] += rightDeltas[i];
  10.     }
  11. }
So once we've collected all our height data, we can apply it at the end. We can't look to the right of the node at the far right, or to the left of the node at the far left, hence the conditions i > 0 and i <  xpositions.Length - 1.

Also, note that we contained this whole code in a loop, and ran it eight times. This is because we want to run this process in small doses multiple times, rather than one large calculation, which would be a lot less fluid.

Adding Splashes

Now we have water that flows, and it shows. Next, we need to be able to disturb the water!

For this, let's add a function called Splash(), which will check the x-position of the splash, and the velocity of whatever is hitting it. It should be public so that we can call it from our colliders later.
  1. public void Splash(float xpos, float velocity)
  2. {
First, we need to make sure that the specified position is actually within the bounds of our water:
  1. if (xpos >= xpositions[0] && xpos <= xpositions[xpositions.Length-1])
  2. {
And then we'll change xpos so it gives us the position relative to the start of the body of water:
  1. xpos -= xpositions[0];
Next, we're going to find out which node it's touching. We can calculate that like this:
  1. int index = Mathf.RoundToInt((xpositions.Length-1)*(xpos / (xpositions[xpositions.Length-1] - xpositions[0])));
So, here's what going on here:
  1. We take the position of the splash relative to the position of the left edge of the water (xpos).
  2. We divide this by the position of the right edge relative to the position of the left edge of the water.
  3. This gives us a fraction that tells us where the splash is. For instance, a splash three-quarters of the way along the body of water would give a value of 0.75.
  4. We multiply this by the number of edges and round this number, which gives us the node our splash was closest to.
  1. velocities[index] = velocity;
Now we set the velocity of the object that hit our water to that node's velocity, so that it gets dragged down by the object.

Note: You could change this line to whatever suits you. For instance, you could add the velocity to its current velocity, or you could use momentum instead of velocity and divide by your node's mass.


Now we want to make a particle system that'll produce the splash. We defined that earlier; it's called "splash" (creatively enough). Be sure not to confuse it with Splash(). The one I'll be using is included in the source files.

First, we want to set the parameters of the splash to change with the velocity of the object.
  1. float lifetime = 0.93f + Mathf.Abs(velocity)*0.07f;
  2. splash.GetComponent<ParticleSystem>().startSpeed = 8+2*Mathf.Pow(Mathf.Abs(velocity),0.5f);
  3. splash.GetComponent<ParticleSystem>().startSpeed = 9 + 2 * Mathf.Pow(Mathf.Abs(velocity), 0.5f);
  4. splash.GetComponent<ParticleSystem>().startLifetime = lifetime;
Here, we've taken our particles, set their lifetime so they won't die shortly after they hit the surface of the water, and set their speed to be based on the square of their velocity (plus a constant, for small splashes).

You may be looking at that code and thinking, "Why has he set the startSpeed twice?", and you'd be right to wonder that. The problem is, we're using a particle system (Shuriken, provided with the project) that has its start speed set to "random between two constants". Unfortunately, we don't have much access over Shuriken by scripts, so to get that behaviour to work we have to set the value twice.

Now I'm going to add a line that you may or may not want to omit from your script:
  1. Vector3 position = new Vector3(xpositions[index],ypositions[index]-0.35f,5);
  2. Quaternion rotation = Quaternion.LookRotation(new Vector3(xpositions[Mathf.FloorToInt(xpositions.Length / 2)], baseheight + 8, 5) - position);
Shuriken particles won't be destroyed when they hit your objects, so if you want to make sure they aren't going to land in front of your objects, you can take two measures:
  1. Stick them in the background. (You can tell this by the z-position being 5).
  2. Tilt the particle system to always point towards the center of your body of water—this way, the particles won't splash onto the land.
The second line of code takes the midpoint of the positions, moves upwards a bit, and points the particle emitter towards it. I've included this behaviour in the demo. If you're using a really wide body of water, you probably don't want this behaviour. If your water is in a small pool inside a room, you may well want to use it. So, feel free to scrap that line about rotation.
  1.         GameObject splish = Instantiate(splash,position,rotation) as GameObject;
  2.         Destroy(splish, lifetime+0.3f);
  3.     }
  4. }
Now, we make our splash, and tell it to die a little after the particles are due to die. Why a little afterwards? Because our particle system sends out a few sequential bursts of particles, so even though the first batch only last till Time.time + lifetime, our final bursts will still be around a little after that.

Yes! We're finally done, right?

Collision Detection

Wrong! We need to detect our objects, or this was all for nothing!

Remember we added that script to all our colliders before? The one called WaterDetector?

Well we're going to make it now! We only want one function in it:
  1. void OnTriggerEnter2D(Collider2D Hit)
  2. {
Using OnTriggerEnter2D(), we can specify what happens whenever a 2D Rigid Body enters our body of water. If we pass a parameter of Collider2D we can find more information about that object.
  1. if (Hit.rigidbody2D != null)
  2. {
We only want objects that contain a rigidbody2D.
  1.       transform.parent.GetComponent<Water>().Splash(transform.position.x, Hit.rigidbody2D.velocity.y*Hit.rigidbody2D.mass / 40f);
  2.     }
  3. }
Now, all of our colliders are children of the water manager. So we just grab the Water component from their parent and call Splash(), from the position of the collider.

Remember again, I said you could either pass velocity or momentum, if you wanted it to be more physically accurate? Well here's where you have to pass the right one. If you multiply the object's y-velocity by its mass, you'll have its momentum. If you just want to use its velocity, get rid of the mass from that line.

Finally, you'll want to call SpawnWater() from somewhere. Let's do it at launch:
  1. void Start()
  2. {
  3.     SpawnWater(-10,20,0,-10);
  4. }
And now we're done! Now any rigidbody2D with a collider that hits the water will create a splash, and the waves will move correctly.


Bonus Exercise

As an extra bonus, I've added a few lines of code to the top of SpawnWater().
  1. gameObject.AddComponent<BoxCollider2D>();
  2. gameObject.GetComponent<BoxCollider2D>().center = new Vector2(Left + Width / 2, (Top + Bottom) / 2);
  3. gameObject.GetComponent<BoxCollider2D>().size = new Vector2(Width, Top - Bottom);
  4. gameObject.GetComponent<BoxCollider2D>().isTrigger = true;
These lines of code will add a box collider to the water itself. You can use this to make things float in your water, using what you've learnt.

You'll want to make a function called OnTriggerStay2D() which takes a parameter of Collider2D Hit. Then, you can use a modified version of the spring formula we used before that checks the mass of the object, and add a force or velocity to your rigidbody2D to make it float in the water.

Make a Splash

In this tutorial, we implemented a simple water simulation for use in 2D games with simple physics code and a line renderer, mesh renderers, triggers and particles. Perhaps you will add wavy bodies of fluid water as an obstacle to your next platformer, ready for your characters to dive into or carefully cross with floating stepping stones, or maybe you could use this in a sailing or windsurfing game, or even a game where you simply skip rocks across the water from a sunny beach. Good luck!
Written by Alex Rose

If you found this post interesting, follow and support us.
Suggest for you:

Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus

Learn to Code by Making Games - The Complete Unity Developer

Make a Multiplayer Shooter in Unity

Unity 5 Host Your Game Server Online like a PRO

Start Learning Unity3d by Making 5 Games from Scratch

Saturday, August 13, 2016

Creating Dynamic 2D Water Effects in Unity_part1

In this tutorial, we're going to simulate a dynamic 2D body of water using simple physics. We will use a mixture of a line renderer, mesh renderers, triggers and particles to create our effect. The final result comes complete with waves and splashes, ready to add to your next game. A Unity (Unity3D) demo source is included, but you should be able to implement something similar using the same principles in any game engine.

End Result

Here's what we're going to end up with. You'll need the Unity browser plugin to try it out.


Setting Up Our Water Manager

In his tutorial, Michael Hoffman demonstrated how we can model the surface of water with a row of springs.

We're going to render the top of our water using one of Unity's line renderers, and use so many nodes that it appears as a continuous wave.



We'll have to keep track of the positions, velocities and accelerations of every node, though. To do that, we're going to use arrays. So at the top of our class we'll add these variables:
  1. float[] xpositions;
  2. float[] ypositions;
  3. float[] velocities;
  4. float[] accelerations;
  5. LineRenderer Body;
The LineRenderer will store all our nodes and outline our body of water. We still need the water itself, though; we'll create this with Meshes. We're going to need objects to hold these meshes too.
  1. GameObject[] meshobjects;
  2. Mesh[] meshes;
We're also going to need colliders so that things can interact with our water:
  1. GameObject[] colliders;
And we'll store all our constants as well:
  1. const float springconstant = 0.02f;
  2. const float damping = 0.04f;
  3. const float spread = 0.05f;
  4. const float z = -1f;
These constants are the same kind as Michael discussed, with the exception of z—this is our z-offset for our water. We're going to use -1 for this so that it gets displayed in front of our objects. (You might want to change this depending on what you want to appear in front and behind of it; you're going to have to use the z-coordinate to determine where sprites sit relative to it.)

Next, we're going to hold onto some values:
  1. float baseheight;
  2. float left;
  3. float bottom;
These are just the dimensions of the water.

We're going to need some public variables we can set in the editor, too. First, the particle system we're going to use for our splashes:
  1. public GameObject splash:
Next, the material we'll use for our line renderer (in case you want to reuse the script for acid, lava, chemicals, or anything else):
  1. public Material mat:
Plus, the kind of mesh we're going to use for the main body of water:
  1. public GameObject watermesh:
These are all going to be based on prefabs, which are all included in the source files.

We want a game object that can hold all of this data, act as a manager, and spawn our body of water ingame to specification. To do that, we'll write a function called SpawnWater().

This function will take inputs of the left side, the width, the top, and the bottom of the body of water.
  1. public void SpawnWater(float Left, float Width, float Top, float Bottom)
  2. {
(Though this seems inconsistent, it acts in the interest of quick level design when building from left to right).

Creating the Nodes

Now we're going to find out how many nodes we need:
  1. int edgecount = Mathf.RoundToInt(Width) * 5;
  2. int nodecount = edgecount + 1;
We're going to use five per unit width, to give us smooth motion that isn't too demanding. (You can vary this to balance efficiency against smoothness.) This gives us all our lines, then we need the + 1 for the extra node on the end.

The first thing we're going to do is render our body of water with the LineRenderer component:
  1. Body = gameObject.AddComponent<LineRenderer>();
  2. Body.material = mat;
  3. Body.material.renderQueue = 1000;
  4. Body.SetVertexCount(nodecount);
  5. Body.SetWidth(0.1f, 0.1f);
What we've also done here is select our material, and set it to render above the water by choosing its position in the render queue. We've set the correct number of nodes, and set the width of the line to 0.1.

You can vary this depending on how thick you want your line. You may have noticed that SetWidth() takes two parameters; these are the width at the start and the end of the line. We want that width to be constant.

Now that we've made our nodes, we'll initialise all our top variables:
  1. xpositions = new float[nodecount];
  2. ypositions = new float[nodecount];
  3. velocities = new float[nodecount];
  4. accelerations = new float[nodecount];
  5.  
  6. meshobjects = new GameObject[edgecount];
  7. meshes = new Mesh[edgecount];
  8. colliders = new GameObject[edgecount];
  9.  
  10. baseheight = Top;
  11. bottom = Bottom;
  12. left = Left;
So now we have all our arrays, and we're holding on to our data.

Now to actually set the values of our arrays. We'll start with the nodes:
  1. for (int i = 0; i < nodecount; i++)
  2. {
  3.     ypositions[i] = Top;
  4.     xpositions[i] = Left + Width * i / edgecount;
  5.     accelerations[i] = 0;
  6.     velocities[i] = 0;
  7.     Body.SetPosition(i, new Vector3(xpositions[i], ypositions[i], z));
  8. }
Here, we set all the y-positions to be at the top of the water, and then incrementally add all the nodes side by side. Our velocities and accelerations are zero initially, as the water is still.

We finish the loop by setting each node in our LineRenderer (Body) to their correct position.

Creating the Meshes

Here's where it gets tricky.

We have our line, but we don't have the water itself. And the way we can make this is using Meshes. We'll start off by creating these:
  1. for (int i = 0; i < edgecount; i++)
  2. {
  3.     meshes[i] = new Mesh();
Now, Meshes store a bunch of variables. The first variable is pretty simple: it contains all the vertices (or corners).

The diagram shows what we want our mesh segments to look like. For the first segment, the vertices are highlighted. We want four in total.
  1. Vector3[] Vertices = new Vector3[4];
  2. Vertices[0] = new Vector3(xpositions[i], ypositions[i], z);
  3. Vertices[1] = new Vector3(xpositions[i + 1], ypositions[i + 1], z);
  4. Vertices[2] = new Vector3(xpositions[i], bottom, z);
  5. Vertices[3] = new Vector3(xpositions[i+1], bottom, z);
Now, as you can see here, vertex 0 is the top-left, 1 is the top-right,2 is the bottom-left, and is the top-right. We'll need to remember that for later.

The second property that meshes need is UVs. Meshes have textures, and the UVs choose which part of the textures we want to grab. In this case, we just want the top-left, top-right, bottom-left, and bottom-right corners of our texture.
  1. Vector2[] UVs = new Vector2[4];
  2. UVs[0] = new Vector2(0, 1);
  3. UVs[1] = new Vector2(1, 1);
  4. UVs[2] = new Vector2(0, 0);
  5. UVs[3] = new Vector2(1, 0);
Now we need those numbers from before again. Meshes are made up of triangles, and we know that any quadrilateral can be made of two triangles, so now we need to tell the mesh how it should draw those triangles.


Look at the corners with the node order labelled. Triangle A connects nodes 01 and 3; Triangle B connects nodes 32 and 0. Therefore, we want to make an array that contains six integers, reflecting exactly that:
  1. int[] tris = new int[6] { 0, 1, 3, 3, 2, 0 };
This creates our quadrilateral. Now we set the mesh values.
  1. meshes[i].vertices = Vertices;
  2. meshes[i].uv = UVs;
  3. meshes[i].triangles = tris;
Now, we have our meshes, but we don't have Game Objects to render them in the scene. So we're going to create them from our watermesh prefab which contains a Mesh Renderer and Mesh Filter.
  1. meshobjects[i] = Instantiate(watermesh,Vector3.zero,Quaternion.identity) as GameObject;
  2. meshobjects[i].GetComponent<MeshFilter>().mesh = meshes[i];
  3. meshobjects[i].transform.parent = transform;
We set the mesh, and we set it to be the child of the water manager, to tidy things up.
Written by Alex Rose

If you found this post interesting, follow and support us.
Suggest for you:

Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus

Learn to Code by Making Games - The Complete Unity Developer

Make a Multiplayer Shooter in Unity

Unity 5 Host Your Game Server Online like a PRO

Start Learning Unity3d by Making 5 Games from Scratch

Tuesday, August 9, 2016

How to Build a Prince-Of-Persia-Style Time-Rewind System, Part 2 (end)

How to Build It

In order to test this system, we need a simple game where we can test it. Let's create one!

The Player
Create a cube in your scene, this will be our player-character. Then create a new C#-script calls Player.cs and adapt the Update()-function to look like this:
  1. void Update()
  2. {
  3.     transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertical"));
  4.     transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal"));
  5. }
This will handle simple movement via the arrow keys. Attach this script to the player cube. When you now hit play you should already be able to move around.

Then angle the camera so that it views the cube from above, with room on its side where we can move it. Lastly, create a plane to act as floor and assign some different materials to each object, so that we're not moving it inside of a void. It should look like this:


Try it out, and you should be able to move your cube using the WSAD and arrow-keys.

The TimeController
Now create a new C#-script called TimeController.cs and add it to a new empty GameObject. This will handle the actual recording and subsequent rewinding of the game.

In order to make this work, we will record the movement of the player character. When we then press the rewind button we will adapt the player coordinates. To do so start by creating a variable to hold the player, like this:
  1. public GameObject player;
And assign the player-object to the resulting slot on the TimeController, so that it can access the player and its data.

Then we need to create an array to hold the player data:
  1. public ArrayList playerPositions;
  2. void Start()
  3. {
  4.     playerPositions = new ArrayList();
  5. }
What we will do next is continuously record the position of the player. We will have the position stored of where the player was in the last frame, the position where the player was 6 frames ago, and the position where the player was 8 seconds ago (or however long you will set it to record). When we later hit a button we'll go backward through our array of positions and assign it frame by frame, resulting in a time-rewinding feature.

First, let's save the data:
  1. void FixedUpdate()
  2. {
  3.     playerPositions.Add (player.transform.position);
  4. }
In the FixedUpdate()-function we record the data. FixedUpdate() is used as it runs at a constant 50 cycles per second (or whatever you set it to), which allows for a fixed interval to record and set the data. The Update()-function meanwhile runs depending on how many frames the CPU manages, which would make things more difficult.

This code will store the player-position of each frame in the array. Now we need to apply it!

We'll add a check to see if the rewind button was pressed. For this, we need a boolean variable:
  1. public bool isReversing = false;
And a check in the Update()-function to set it according to whether we want to rewind the gameplay:
  1. void Update()
  2. {
  3.     if(Input.GetKey(KeyCode.Space))
  4.     {
  5.         isReversing = true;
  6.     }
  7.     else
  8.     {
  9.         isReversing = false;
  10.     }
  11. }
To make the game run backward, we will apply the data instead of recording. The new code for recording and applying of the player position should look like this:
  1. void FixedUpdate()
  2. {
  3.     if(!isReversing)
  4.     {
  5.         playerPositions.Add (player.transform.position);
  6.     }
  7.     else
  8.     {
  9.         player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1];
  10.         playerPositions.RemoveAt(playerPositions.Count - 1);
  11.     }
  12. }
And the entire TimeController-script like this:
  1. using UnityEngine;
  2. using System.Collections; 
  3. public class TimeController: MonoBehaviour
  4. {
  5.     public GameObject player;
  6.     public ArrayList playerPositions;
  7.     public bool isReversing = false; 
  8.     void Start()
  9.     {
  10.         playerPositions = new ArrayList();
  11.     } 
  12.     void Update()
  13.     {
  14.         if(Input.GetKey(KeyCode.Space))
  15.         {
  16.             isReversing = true;
  17.         }
  18.         else
  19.         {
  20.             isReversing = false;
  21.         }
  22.     }   
  23.     void FixedUpdate()
  24.     {
  25.         if(!isReversing)
  26.         {
  27.             playerPositions.Add (player.transform.position);
  28.         }
  29.         else
  30.         {
  31.             player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1];
  32.             playerPositions.RemoveAt(playerPositions.Count - 1);
  33.         }
  34.     }
  35. }
Also, don't forget to add a check to the player-class to see if the TimeController is currently rewinding or not, and only move when it is not reversing. Otherwise, it might create buggy behavior:
  1. using UnityEngine;
  2. using System.Collections; 
  3. public class Player: MonoBehaviour
  4. {
  5.     private TimeController timeController; 
  6.     void Start()
  7.     {
  8.         timeController = FindObjectOfType(typeof(TimeController)) as TimeController;
  9.     }     
  10.     void Update()
  11.     {
  12.         if(!timeController.isReversing)
  13.         {
  14.             transform.Translate (Vector3.forward * 3.0f * Time.deltaTime * Input.GetAxis ("Vertical"));
  15.             transform.Rotate (Vector3.up * 200.0f * Time.deltaTime * Input.GetAxis ("Horizontal"));
  16.         }
  17.     }
  18. }
These new lines will automatically find the TimeController-object in the scene on startup and check it during runtime to see if we are currently playing the game or rewinding it. We can only control the character when we are currently not reversing time.

Now you should be able to move around the world, and rewind your movement by pressing space. If you download the build package attached to this article and open TimeRewindingFunctionality01 you can try it out!

But wait, why does our simple player-cube keep looking in the last direction we left them in? Because we didn't get around to also record its rotation!

For that you need another array to keep its rotation-values, to instantiate it at the beginning, and to save and apply the data the same way we handled position-data
  1. using UnityEngine;
  2. using System.Collections; 
  3. public class TimeController: MonoBehaviour
  4. {
  5.     public GameObject player;
  6.     public ArrayList playerPositions;
  7.     public ArrayList playerRotations;
  8.     public bool isReversing = false;    
  9.     void Start()
  10.     {
  11.         playerPositions = new ArrayList();
  12.         playerRotations = new ArrayList();
  13.     }     
  14.     void Update()
  15.     {
  16.         if(Input.GetKey(KeyCode.Space))
  17.         {
  18.             isReversing = true;
  19.         }
  20.         else
  21.         {
  22.             isReversing = false;
  23.         }
  24.     }     
  25.     void FixedUpdate()
  26.     {
  27.         if(!isReversing)
  28.         {
  29.             playerPositions.Add (player.transform.position);
  30.             playerRotations.Add (player.transform.localEulerAngles);
  31.         }
  32.         else
  33.         {
  34.             player.transform.position = (Vector3) playerPositions[playerPositions.Count - 1];
  35.             playerPositions.RemoveAt(playerPositions.Count - 1);   
  36.             player.transform.localEulerAngles = (Vector3) playerRotations[playerRotations.Count - 1];
  37.             playerRotations.RemoveAt(playerRotations.Count - 1);
  38.         }
  39.     }
  40. }
Try it out! TimeRewindingFunctionality02 is the improved version. Now our player-cube can move backward in time, and will look the same way it did when it was at that moment.

Conclusion

We have built a simple prototype game with an already usable time-rewinding system, but it is far from done yet. In the next part of this series we'll make it much more stable and versatile, and add some neat effects.

Here is what we still need to do:

Only record every ~12th frame and interpolate between the recorded ones to save on the huge data load
Only record the last ~75 player positions and rotations to make sure the array doesn't become too unwieldy and the game doesn't crash
We'll also take a look at how to extend this system past just the player-character:

Record more than just the player
Add an effect to signify rewinding is happening (like VHS-blurring)
Use a custom class to hold player position and rotation instead of arrays
Written by Matthias Zarzecki

If you found this post interesting, follow and support us.
Suggest for you:

Unity 5 Professional Guide - Develop a 2D Arkanoid Game!

Unity 5 Professional Guide - Mastering C# Programming!

Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus

Learn to Code by Making Games - The Complete Unity Developer

Start Learning Unity3d by Making 5 Games from Scratch

Monday, August 8, 2016

How to Build a Prince-Of-Persia-Style Time-Rewind System, Part 1

What You'll Be Creating
In this tutorial, we'll build a simple game where the player can rewind progress in Unity (it can also be adapted to work in other systems). This first part will go into the basics of the system, and the next part will flesh it out and make it much more versatile.

First, though we'll take a look at what games use this. Then we'll look at the other uses for this technical setup, before ultimately creating a small game that we can rewind, which should give you a basis for your own.
A demonstation of the basic functionality
You will need the newest version of Unity for this, and should have some experience with it. The source code is also available for download if you want to check your own progress against it.

Ready? Let's go!

How Has This Been Used Before?

Prince of Persia: The Sands of Time is one of the first games to truly integrate a time-rewinding mechanic into its gameplay. When you die you do not just have to reload, but can rather rewind the game for a few seconds to where you were alive again, and immediately try again.

Prince of Persia: The Forgotten Sands. The Sands Of Time Trilogy integrates time-rewinding beautifully into its gameplay and avoids immersion-breaking quick-reloading.
This mechanic is not only integrated into the gameplay, but the narrative and universe as well, and is mentioned throughout the story.

Other games that employ these systems are Braid, for example, which is also centered around the winding of time. The hero Tracer in Overwatch has a power that resets her to a position a few seconds ago, essentially rewinding her time, even in a multiplayer game. The GRID-series of racing games also has a snapshot-mechanic, where you have a small pool of rewinds during a race, which you can access when you have a critical crash. This prevents frustration caused by crashes near the end of race, which can be especially infuriating.

When you have a fatal crash in GRID you get the chance to rewind the game to a point before the crash.
Other Uses

But this system can not only be used to replace quick-saving. Another way this is employed is ghosting in racing games and asynchronous multiplayer.

Replays
Replays are another fun way to employ this feature. This can be seen in games like SUPERHOT, the Worms series, and pretty much the majority of sports games.

Sports-replays work the same way they are presented on TV, where an action is showed again, possibly from a different angle. For this not a video is recorded but rather the actions of the user, allowing the replay to employ different camera angles and shots. The Worms games use this in a humorous way, where very comical or effective kills are shown in an Instant Replay.

SUPERHOT also records your movement. When you are done playing around your entire progress is then replayed, showing the few seconds of actual movement that happened.

Super Meat Boy uses this in a fun way. When you finish a level you see a replay of all your previous attempts laid on top of each other, culminating with your finishing run being the last left standing.

The end-of-level replay in Super Meat Boy. Every one of your previous attempts is recorded and then played back at the same time.
Time-Trial Ghosts
Race-Ghosting is a technique where you race for the best time on an empty track. But at the same time, you race against a ghost, which is a ghostly, transparent car, which drives the exact way you raced before on your best attempt. You cannot collide with it, which means you can still concentrate on getting the best time.

Instead of driving alone you get to compete against yourself, which makes time-trials much more fun. This feature shows up in the majority of racing games, from the Need for Speed series to Diddy Kong Racing.

Racing a ghost in Trackmania Nations. This one has the silver difficulty, meaning I will get the silver medal if I beat them. Note the overlap in car-models, showing the ghost isn't corporeal and can be driven through.
Multiplayer-Ghosts
Asynchronous Multiplayer-Ghosting is another way to use this setup. In this rarely-used feature, multiplayer matches are accomplished by recording the data of one player, who then sends their run to another player, who can subsequently battle against the first player. The data is applied the same way a time-trial-ghost would be, only that you are racing against another player.

A form of this shows up in the Trackmania-games, where it is possible to race against certain difficulties. These recorded racers will give you an opponent to beat for a certain reward.

Movie-Editing
Few games offer this from the get-go but used right it can be a fun tool.Team Fortress 2 offers a built-in replay-editor, with which you can create your own clips.

The replay editor from Team Fortress 2. Once recorded a match can be seen from any perspective, not just the player's.
Once the feature has been activated you can record and watch previous matches. The vital element is that everything is recorded, not only your view. This means you can move around the recorded game-world, see where everyone is, and have control over time.
Written by Matthias Zarzecki (continue)

If you found this post interesting, follow and support us.
Suggest for you:

Unity 5 Professional Guide - Develop a 2D Arkanoid Game!

Unity 5 Professional Guide - Mastering C# Programming!

Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus

Learn to Code by Making Games - The Complete Unity Developer

Start Learning Unity3d by Making 5 Games from Scratch


Friday, August 5, 2016

Creating a 3D City in Unity 5_part2 (end)


Camera Position

When you choose an object in the Hierarchy, the objects detail will show in the Inspector window (on the right). This is where you can make changes to the object, add textures, add colliders and add code.

Let's get the camera in the correct position. Choose the Main Camera in the Hierarchy tab. Now look at the Inspector tab and on the right, under Transform, you will see Position. Type 265, 20, 20. Your camera should now be in the position where we want it.

Follow the Grey Brick Road

Now let's add a texture to the terrain. Choose Terrain from the Hierarchy tab and click the paint brush in the Inspector window. Under Textures you will see Edit Textures. Left-click and choose Add a Texture, and a small window will pop up asking you to choose a texture. Once you click that box, the textures you imported from the Asset Store will show. Double-click and add one you like. I chose Dark Concrete.

Look Into the Sky

Unity comes with a default skybox which works great if you like it. I think it's a little boring, so I'm going to add the skybox we downloaded earlier. Let's click Main Camera and in the Inspector window click Add Componentat the bottom. Type Skybox and click the circle on the right. A box will open where you can choose a skybox of your choice by double-clicking it. Now if you look in your Game Scene you will see the new skybox. Looking good so far!

If You Build It

Now that our environment is coming along, let's add some buildings. Go to Game Object > 3D Object > Cube. At first, you won't see the cube because it's at a far distance. Let's get it to where we can see it. Click on Cube from the Hierarchy. Let's position the cube by typing 300, 25, 100. Let's also scale it to 20, 50, 20. You can use the scale tool or just type the size into the boxes. Once you've added the first Cube, right-click it in the Hierarchy tab to rename it. Name it Building 1.



Awesome. Let's add some more buildings. Repeat the steps above. You will see the additional cube in your Hierarchy as Cube (1), so let's rename it Building 2 by right-clicking your mouse and typing it in. Now scale to 20, 70, 20 and position to 275, 25, 100.

As you add buildings, change the scale and position for each one. Make sure you keep the middle positions at 25 to keep them lined up. You can also use the toggle bar to scale and move the buildings. Continue the steps until you have five buildings, and name them consecutively, for example Building 2, Building 3, and so on. I have my buildings positioned by skipping 25 numbers like so: 250, 0, 100, 225, 0, 100 etc. Don't forget to save your scene!

Tip: You can also right-click a building in the Hierarchy tab, copy and paste it. 

Adding Building Textures

Now we get to turn our cubes until buildings. Click on your Artwork folder in the Project tab (this is where you added your building textures). Choose a texture and drag it to a box on your Scene tab. You will immediately see the texture change in your Scene and Game views. Feel free to adjust, move and rotate your buildings until you're satisfied.

Tip: At times the texture can be backward. An easy fix is to rotate your box by changing the Z rotation to 180.

The Road Ahead

It's time to add the road. Go to Game Object > 3D Object > Plane. Position it at 250, 0.2, 80. Add a Y rotation of 90 and scale it to 1, 1, 15.  Now choose your road texture and add it to the plane. Rename the plane Road.

A Place for Everything

Final Unity projects can have thousands of objects, scripts, and prefabs. It is important to keep your items organized, and now is a good time to organize your Hierarchy.

Any city is made up of numerous buildings, so let's keep ours itemized by the block. Go to Game Object > Create Empty, and you will now see a new item in your Hierarchy named GameObject. Rename it Block1(L). Click building 1, hold down Shift and highlight all of your other buildings. You can now move them all under Block1(L) which becomes the buildings' parent.


Copy Cat

We will now create the other side of the street. Right-click Block1(L) and copy and paste. Name it Block1(R). Position Block1(R) to 235, -90, 300.

You can now change the textures around or download new ones if you wish. When changing a texture, you must click the individual box, otherwise you will change all the textures for the block. Let's reposition the Camera to 340, 10, 80 and rotate to -80.

Tip: If you don't like the way an item is positioned, you can move it with your toggle menu. Click save.

Adding City Props

From here on out we will need to use the toggle bar. Practice using the right and left mouse buttons to move around your world. It takes a little practice.

Click the down arrow on the City Props Pack folder in the Project tab. Scroll down to the Prefabs folder and click the down arrow until you see the list of objects. Choose the Stop sign. When you choose it you will see it displayed in the Inspector window on the right.

Let's move to the front of the first building. Choose the Stop sign and drag it to the Scene window; depending on your scene, you may need to scale it down. Scale to 0.2, 0.2, 0.2. Great!

Let's get creative and add more props. Feel free to choose the ones you like and place them anywhere you like on the sidewalk. Remember you can copy and paste any object in your Hierarchy. In the spirit of keeping things organized, create an Empty parent under Game Object and call it City Props. Move items accordingly. Save your scene.

Tip: Remember, if your objects glow white, you will need to change the shader to Legacy Shaders/Bumped Diffuse.

Adding Trees

Now it's time to add some trees to our city. Unity comes with standard trees that work great. You can always download different types of trees from the asset store if you are going for a different look.

Let's click Terrain in the Hierarchy tab. In the Inspector window, you will see a picture of what looks like a tree under Terrain—click it. Under the settings, change the Brush Size to 1. Now click Edit Trees > Add Tree. In the Tree Prefab box, click the circle at the end.

Choose a tree (I chose Broadleaf). Double-click and add. You will now see the tree you chose under the Trees box in the Inspector tab. When you move your mouse on the Scene, a blue circle will follow. Since we have the Brush size on 1, you will place one tree at a time. If you add a tree and it's too large, you can resize under settings by changing the Tree Height. If you make a mistake, click Edit Trees and remove the tree. You can then start over.


Adding a Third-Person Character

OK, so we finally have our environment where we want it, and now it's time for our friend Ethan to walk around in our world. Click the down arrow under Standard Assets from the Project tab, then Characters > ThirdPersonCharacter. Go into Prefabs and drag the ThirdPersonController into your Scene. Position the controller at 315, 0.1, 78 and resize to 3, 3, 3.

You can also rotate him so he is facing the direction you want. Click Play, and you should be able to control Ethan. Click the arrow buttons on your keyboards and run around.

At some point, you will notice he moves off the screen, so we need the camera to follow him. Under Hierarchy, highlight the Main Camera and drag under ThirdPersonController. Your MainCamera should now be a child of the ThirdPersonController. Now when you hit play, the camera will follow Ethan.

Adding a First-Person Controller

We can also view our world in the first-person view. Go into your Project tab. Choose Standard Assets, Prefab, FPS Controller. Drag it to your scene, rotate and scale. Before you hit play, it is important to note that the FPS comes with its own camera, so you will need to delete the MainCamera.

Tip: If your character falls through the ground, you probably have them positioned too low. Double-click your character on the Hierarchy tab and you will see a close-up on the Scene tab. Move the controller up with the arrow bar or position the Y at 1.

Congratulations! You have built your first 3D City in Unity 5! As you can see, it's easy and lots of fun. You can get as creative as you like and add houses, cars, stores, etc.
Written by Sandra Gerber

If you found this post interesting, follow and support us.
Suggest for you:

Unity 5 Professional Guide - Develop a 2D Arkanoid Game!

Unity 5 Professional Guide - Mastering C# Programming!

Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus

Learn to Code by Making Games - The Complete Unity Developer

Start Learning Unity3d by Making 5 Games from Scratch

Thursday, August 4, 2016

How to Save and Load Your Players' Progress in Unity

https://school.codequs.com/p/HJkEBKvu
What You'll Be Creating
In this tutorial, you'll learn how to implement a simple system to create and manage savegames for your Unity games. We will build the framework for a Final Fantasy-like main menu that enables players to create new, unique save files, and to load existing ones. The principles demonstrated will allow you to extend them to whatever needs your game has.

By the end of the tutorial, you will have learned how to:
  • save and load game data within Unity3D using serialization
  • use static variables to persist data across scene changes
Note: This approach to saving and loading game data works on all platforms except for the Web Player. For information on saving game data in the Web Player, take a look at the official docs on Unity Web Player and browser communication.

Let's Get Serial

The first thing we're going to do is to create some code that allows us to serialize our game data—that is, convert it to a format that can be saved and later restored. For this, let's create a C# script and call it SaveLoad. This script will handle all the saving and loading functionality.

We will reference this script from other scripts, so let's make it a static class by adding the word static  between public and class. Let's also remove the : MonoBehaviour part, because we don't need to attach it to a GameObject. And since it no longer inherits from MonoBehaviour, let's delete the Start  and Update functions.

The resulting code should look like this:
  • using UnityEngine;
  • using System.Collections;
  • public static class SaveLoad {
  • }
Now, we're going to want to add some new functionality to this script, so immediately under where it says using System.Collections;, add the following:
  1. using System.Collections.Generic; 
  2. using System.Runtime.Serialization.Formatters.Binary; 
  3. using System.IO;
The first line allows us to use dynamic lists in C#, but this is not necessary for serialization. The second line is what enables us to use the operating system's serialization capabilities within the script. In the third line, IO stands for Input/Output, and is what allows us to write to and read from our computer or mobile device. In other words, this line allows us to create unique files and then read from those files later.

We're now ready to serialize some data!

Making Serializable Classes

Now that our script has the ability to serialize, we are going to have to set up some classes to be serialized. If you think about a basic RPG, like Final Fantasy, it offers players the ability to create and load different saved games. So, create a new C# script called Game and give it some variables to hold three objects: a knight, a rogue, and a wizard. Change the code of this script to look like this:
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. [System.Serializable]
  5. public class Game { 
  6.  
  7.     public static Game current;
  8.     public Character knight;
  9.     public Character rogue;
  10.     public Character wizard;
  11.  
  12.     public Game () {
  13.         knight = new Character();
  14.         rogue = new Character();
  15.         wizard = new Character();
  16.     }
  17.          
  18. }
The [System.Serializable] line tells Unity that this script can be serialized—in other words, that we can save all the variables in this script. Cool! According to the official docs, Unity can serialize the following types:
  • All basic data types (like intstringfloat, and bool).
  • Some built-in types (including Vector2Vector3Vector4QuaternionMatrix4x4ColorRect, and LayerMask).
  • All classes inheriting from UnityEngine.Object (including GameObjectComponentMonoBehavior,Texture2D, and AnimationClip).
  • Enums.
  • Arrays and lists of a serializable type.
The first variable, current, is a static reference to a Game instance. When we create or load a game, we're going to set this static variable to that particular game instance so that we can reference the "current game" from anywhere in the project. By using static variables and functions, we don't have to use a gameObject's GetComponent() function. Handy!

Notice that it's referencing something called a Character? We don't have that yet, so let's create a new script to house this class, and call it Character:
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. [System.Serializable] 
  5. public class Character {
  6.  
  7.     public string name;
  8.  
  9.     public Character () {
  10.         this.name = "";
  11.     }
  12. }
You may be wondering why we needed a whole new class if we're just storing a string variable. Indeed, we could just replace Character in the Game script to use string instead. But I want to show you how deep this rabbit hole can go: you can save and load classes that reference other classes, and so on, as long as each class is serializable.

Now that our classes are set up to be saved and loaded, let's hop back over to our SaveLoad script and add the ability to save games.

Saving a Game's State

A "Load Game" menu  usually shows a list of saved games, so let's create a List of type Game and call it savedGames. Make it a static List, so that there's only one list of saved games in our project. The code should look like this:
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Runtime.Serialization.Formatters.Binary;
  5. using System.IO;
  6. public static class SaveLoad {
  7.     public static List<Game> savedGames = new List<Game>(); 
  8. }
Next, let's create a new static function to save a game:
  1. public static void Save() {
  2.     savedGames.Add(Game.current);
  3.     BinaryFormatter bf = new BinaryFormatter();
  4.     FileStream file = File.Create (Application.persistentDataPath + "/savedGames.gd");
  5.     bf.Serialize(file, SaveLoad.savedGames);
  6.     file.Close();
  7. }
Line 2 adds our current game to our list of saved games. That list is what we're going to serialize. To do so, we first need to create a new BinaryFormatter, which will handle the serialization work. This is what Line 3 does.

In Line 4, we're creating a FileStream, which is essentially a pathway to a new file that we can send data too, like fish swimming downstream in a river. We use File.Create() to create a new file at the location we pass in as its parameter. Conveniently, Unity has a built-in location to store our game files (which updates automatically based on what platform your game is built to) that we can reference using Application.persistentDataPath.

Since we're creating a new file, however, we can't just say where the file is, we also have to cap off this pathway with the name of the actual file itself. There are two parts to this file:
  1. the file name
  2. the file type
We'll use savedGames for the file name, and we'll use a custom data type gd (for "game data") for the file type. Our result is a game file called savedGames.gd at the location set by Application.persistentDataPath. (In the future, you could save other types of things to this data type; for example, you could save the users' options settings as options.gd.)

Note: You can make the file type anything you want. For example, the Elder Scrolls series uses .esmas its file type. You could have as easily said savedGames.baconAndGravy.

In Line 5, we're calling the Serialize functionality of the BinaryFormatter to save our savedGames list to our new file. After that, we have the close the file that we created, in Line 6.

Badda bing, badda boom. Our games are saved.

Loading a Game's State

In the Save function, we serialized our list of saved games at a specific location. Conversely, the code to load our games should look like this:
  1. public static void Load() {
  2.     if(File.Exists(Application.persistentDataPath + "/savedGames.gd")) {
  3.         BinaryFormatter bf = new BinaryFormatter();
  4.         FileStream file = File.Open(Application.persistentDataPath + "/savedGames.gd", FileMode.Open);
  5.         SaveLoad.savedGames = (List<Game>)bf.Deserialize(file);
  6.         file.Close();
  7.     }
  8. }
In Line 2, we check whether a saved game file exists. (If it doesn't, there will be nothing to load, obviously.) In Line 3, we create a BinaryFormatter the same way we did in the Save function. In Line 4, we create a FileStream—but this time, our fish are swimming upstream from the file. Thus, we use File.Open, and point to where our savedGames.gd exists using the same Application.persistentDataPath string.

Line 5 is a bit dense, so let's unpack it:
  • The bf.Deserialize(file) call finds the file at the location we specified above and deserializes it. 
  • We can't just spit binary at Unity and expect it to work, however, so we convert (or cast) our deserialized file to the data type we want it to be, which in this case is a List of type Game. 
  • We then set that list as our list of saved games. 
Lastly, in Line 6, we close that file the same way we did in the Save function.

Note: The data type to which you cast the deserialized data can change depending on what you need it to be. For example, Player.lives = (int)bf.Deserialize(file);;.

Conclusion

Our SaveLoad script is now complete, and should look like this:
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Runtime.Serialization.Formatters.Binary;
  5. using System.IO;
  6. public static class SaveLoad {
  7.     public static List<Game> savedGames = new List<Game>();          
  8.     //it's static so we can call it from anywhere
  9.     public static void Save() {
  10.         SaveLoad.savedGames.Add(Game.current);
  11.         BinaryFormatter bf = new BinaryFormatter();
  12.         //Application.persistentDataPath is a string, so if you wanted you can put that into debug.log if you want to know where save games are located
  13.         FileStream file = File.Create (Application.persistentDataPath + "/savedGames.gd"); //you can call it anything you want
  14.         bf.Serialize(file, SaveLoad.savedGames);
  15.         file.Close();
  16.     }   
  17.          public static void Load() {
  18.         if(File.Exists(Application.persistentDataPath + "/savedGames.gd")) {
  19.             BinaryFormatter bf = new BinaryFormatter();
  20.             FileStream file = File.Open(Application.persistentDataPath + "/savedGames.gd", FileMode.Open);
  21.             SaveLoad.savedGames = (List<Game>)bf.Deserialize(file);
  22.             file.Close();
  23.         }
  24.     }
  25. }
Those are the basics of saving and loading in Unity. In the attached project file, you'll find some other scripts which show how I handle calling these functions and how I display the data using Unity's GUI.

If you need a head-start with your game development, try the Unity3D templates available on Envato Market.
Written by Eric Daily
If you found this post interesting, please  follow and support us.
Suggest for you:

Unity 5 Professional Guide - Develop a 2D Arkanoid Game!

Unity 5 Professional Guide - Mastering C# Programming!

Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus

Learn to Code by Making Games - The Complete Unity Developer

Start Learning Unity3d by Making 5 Games from Scratch