Gigi Labs

Please follow Gigi Labs for the latest articles.
Showing posts with label time. Show all posts
Showing posts with label time. Show all posts

Sunday, August 4, 2013

Unity3D: Changing game speed and pausing

Hi!

Today's article is a little break from the OOP tutorials. Instead, we revisit the Unity3D game development engine (at the time of writing, version 4.2 was recently released) and learn about controlling time. This allows us to easily pause the game, slow it down, or speed it up.

Create a new project and add a sphere to your scene via GameObject menu -> Create Other -> Sphere. Next, create a new C# script by right clicking in the Project panel, and selecting Create -> C# Script. Name it Ball, and drag it onto your Sphere in the Hierarchy panel. Double-click the script to open it in MonoDevelop.

We're going to make a very basic bouncing ball just to be able to see the effects of our change in speed. Start off with the following code for the Ball script:

public class Ball : MonoBehaviour
{
    private Vector3 velocity;
   
    // Use this for initialization
    void Start ()
    {
        this.velocity = new Vector3(1.0f, 1.0f, 0.0f);
    }
   
    // Update is called once per frame
    void Update ()
    {
        this.transform.position += this.velocity * Time.deltaTime;
       
        if (this.transform.position.x > 5.0f)
            velocity.x = -velocity.x;
        else if (this.transform.position.x < -5.0f)
            velocity.x = -velocity.x;
        else if (this.transform.position.y > 6.0f)
            velocity.y = -velocity.y;
        else if (this.transform.position.y < -5.0f)
            velocity.y = -velocity.y;
    }
}

This will make the ball bounce when it reaches the sides of the screen. This may vary depending on your monitor so use whichever values work best.

We've used Time.deltaTime before. Games look interactive because they generate a certain number of images (frames) per second, usually something between 30 and 60. Time.deltaTime is the time between one frame and the next; multiplying this by the velocity makes the ball move pretty uniformly.

Another important property of the Time class is Time.timeScale. This is a measure of how quickly scripts and animations run, and is set to 1.0f by default. We can change this to make the game run at different speeds. To try it out, add the following code to the Ball script's Update() method:

        if (Input.GetKeyDown(KeyCode.P))
            Time.timeScale = 0.0f;
        else if (Input.GetKeyDown(KeyCode.N))
            Time.timeScale = 1.0f;
        else if (Input.GetKeyDown(KeyCode.F))
            Time.timeScale = 2.0f;
        else if (Input.GetKeyDown(KeyCode.S))
            Time.timeScale = 0.5f;

What we're doing here is:

  • If the player presses 'P' (pause), we set the time scale to zero, effectively stopping any movement in the game.
  • If the player presses 'N' (normal speed), we set the time scale to the default of 1.0f.
  • If the player presses 'F' (fast), we set the time scale to double the normal speed.
  • If the player presses 'S' (slow), we set the time scale to half the normal speed.
This simple property allows you to not only pause the game, but also to play the game at different speeds. Several games including Starcraft and Warcraft 2 have settings that allow you to tweak the game speed in order to make it more challenging or less frenetic.


This article showed how a single line of code in Unity3D is enough to change the speed of a game or pause it. Although this was a very easy tutorial, I hope you will also find it very useful in any games you make!

Wednesday, May 29, 2013

Unity3D: Space Invaders (Part 2 - Linear Interpolation)

Hi all! :)

In the previous article ("Unity3D: Space Invaders (Part 1 - Navigation and Materials)"), we began working on a Space Invaders clone called Ranch Invaders. Today we're going to continue where we left off, and we're going to animate the alien moving around. If you didn't follow the previous article, don't worry! :) All you need to do is start a new Unity project and drag a cube onto the scene.

If you've read "Unity3D: Moving an Object with Keyboard Input", you might remember that in order to make an object behave in some way, we need to attach a script to it. So, right-click in the Assets panel, and in the context menu, select Create -> C# Script. You can call it Alien (or whatever you like). Then, drag the script onto the Alien object (cube). You'll know you've done it right when you select the Alien object and the Alien script appears in the Inspector:


Double-click the Alien script to open it in MonoDevelop. You are presented with a default (empty) behaviour script:


You will notice that these scripts all inherit from a MonoBehaviour class and have at least Start() and Update() methods. The Start() method allows us to set certain variables when the object is initialised, while the Update() method is called continuously while the game is running. A game is interactive because it shows (renders) a certain number of images (frames) per second. The Update() method is called every frame. So that is where you put most of your logic. Note: there are other, similar methods if you need more control, but we don't need to get into those right now.

In "Unity3D: Moving an Object with Keyboard Input", we saw that we could set an object's position by assigning a new Vector3 to its transform.position:

        this.transform.position = new Vector3(5, 5, 5);

However, what we'd like to do is have the Alien move gradually from one point to another. You can think of it like this:


So we want the Alien's x-position to start at -5, and move gradually to the right until it reaches x=5. With each frame, x is set to a different intermediate value t.

First, we need a variable to store the time when the animation began. Add this variable in the Alien class:

private float startTime;

The float data type is something we haven't covered in the C# articles so far, but it's simply a number that may have a decimal value (e.g. 5.48). When assigning float values, we need to add an 'f' suffix to the value (e.g. 5.48f).

Next, we set this startTime to the current time in the Start() method:

    void Start ()
    {
        this.startTime = Time.time;
    }

Unlike float, which is a standard data type, Unity uses its own classes to represent time. Instead of the DateTime type we're used to from C#, Unity has its own Time class. The equivalent of DateTime.Now is Time.time, and it gives us a float representing the current time.

We can now change the Update() method as follows to carry out the animation:

    void Update ()
    {
        float t = Time.time - startTime;
        float x = Mathf.Lerp(-5.0f, 5.0f, t);
        this.transform.position = new Vector3(x, 5, 5);
    }

Remember that Update() is called every frame. Thus, based on the current time, we calculate how far along the animation we have come, and store it in t. We can then use Lerp() to set x to the correct intermediate value between -5.0f and 5.0f.

Before I mess up your mind with an explanation on Lerp, press F8 to make sure the code compiles, and then press Play from within Unity. Watch the Alien (cube) move gradually from left to right. This will help you understand better what is happening.

Lerp is short for linear interpolation, which might sound like some scary monster. But to understand it, refer again to this diagram:


Let's say t starts at 0, and goes up to 100 as time goes by. It's not the same as the value of x; think of it as a percentage.

Now, let's say that at a particular point in time, t is 0.6 (60%). In order to find the corresponding value of x, we need the value that marks 60% of the way between -5 and 5. That's

t starts at zAs time goes by, t increases. To keep it simple, let's say it increases in whole numbers. So from -5, it becomes -4, -3, and so on until it finally reaches 5. The x value can be calculated from t as follows:


In Unity, you don't really need to worry about the mathematics. Just keep track of the time, and store the elapsed time in a variable (such as t). To use the Lerp() method, just pass the minimum, maximum, and t values as parameters, in that order. The result is the intermediate, or interpolated value you want.

When you press Play in Unity, you'll notice that the Alien (cube) moves across rather quickly. You can regulate this by multiplying a speed value:

        float t = (Time.time - startTime) * 0.4f;

The value (in this case 0.4f) is up to you to choose. Values less than 1 will make the cube move more slowly, and values greater than 1 will make it move faster.

Wonderful! :) In this article, we learned how to use linear interpolation (lerp) to animate the movement of a cube. As a matter of fact, interpolation is used in all sorts of animation, from video game credits scrolling vertically, to an object gradually changing colour when it is hit by a bullet. A lot of this functionality can be used easily using libraries such as iTween, but learning how it actually works gives you much more control.

Come back for the next article in the Ranch Invaders series, in which we will learn about prefabs and use them to shoot bullets! In the meantime, as an exercise, implement the code that allows the alien to move from left to right, down, right to left, down, etc (see this video to get an idea). :)