Unity for Windows VII–Creating a more advanced game, Part 2

image

In this tutorial, we will continue on what we created in the previous tutorial.

I. Making the camera follow the player

The first thing we want to do is to make the camera follow the player. Find the Standard Assets (Mobile) script folder:
image

Now, drag the script named SmoothFollow2d and set it on the Main Camera:

image

Put it on Main Camera:
image

You should now see it added as a component of the camera:
image

Now, we need to set the target to the player. Drag the Player GameObject from the hierarchy to the target property of the component:

a)
image

b)
image

c)
image

If you press play now, the camera will center on the player object.

II. Controlling the player

Create a new script in our Scripts folder and name it “PlayerHandler”.
image

Drag it on the Player GameObject in the hierarchy view and make sure it’s added:
image

Now, edit this script. Our goal is to move it up and down by input, and then we are walking forward automatically. How should we control the character? First of all, this is going to be an app for both tablets and phones, so touch/mouse is essential. At a later tutorial, we will add keybaord and Xbox360 controller support too (easy to do! Smilefjes).

This script is a start, covering the touch/mouse input:

using UnityEngine;
using System.Collections;

public class PlayerHandler : MonoBehaviour {
    float speed = 4.0f;
    public GameObject go;
    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
        Vector3 movePlayerVector = Vector3.right;

        if (Input.GetMouseButton(0))
        {
            Vector3 touchWorldPoint = Camera.main.ScreenToWorldPoint(
                new Vector3(Input.mousePosition.x,
                            Input.mousePosition.y,
                            10.0f));

            if (touchWorldPoint.y >= this.transform.position.y)
            {
                movePlayerVector.y = 1.0f;
            }
            else movePlayerVector.y = -1.0f;
        }

        this.transform.position += movePlayerVector * Time.deltaTime * speed;
    }
}

First of all we create a vector that’s pointing right. This vector is then added to the players position later. This means that we are always walking right. This vector is 1.0 on the X-axis and 0.0 on the Y-axis.

We need to modify this vector with the Y-axis to make our character move up and down.

We check for input from the left mouse button (the same as a touch point). If it is being pressed, take the mouse coordinate and convert it to world view (since when we click the mouse/touch the screen, the position of the location we touched is in screen-space (screen resolution). We need to convert it to world space (the same coordinate system that our player is in).

Now, it’s hard to see anything without a background. Let’s add this!

III. Adding the background

This section will cover how to add a background to our game.

a) First, add a new quad to our scene:
image

b) And name it “Background”:
image

c) Set the position to 0,0,0:
image

d) Create a new material and name it “BackgroundMaterial”:
image

e) Set the texture of the material to the “Background.png” texture in “Textures\Environment”:
image

f) Set the shader to Mobile/Background:
image
The reason for this is that we don’t want any lighting on our scene, since it’s 2D. This shader will just use the colors set when creating the image using your favorite drawing application.

g) Set the scale of the Background GameObject to the same aspect as the texture resolution, something that fit the scene. We also set the Positions Z azis to one, so it’s a bit behind our player:
image

The result should be something like this:
image

 

IV. Looping the background

Next we need to loop the background. We want an infinite world. We could duplicate the Background GameObject many times and line them up together, or we can make a prefab out of it, and then use a script to draw a lot of them!

Create a new folder in the Assets/Game folder and name it Prefabs:

image

Next, create a new C# script in the Scripts-folder named EnvironmentHandler:
image

Drag this script on the Main Camera GameObject.

Now, browse to the Prefabs-folder:
image

Then drag the Background GameObject from the scene hierarchy to the Prefabs-folder to create a prefab out of it:
image

Then delete the Background GameObject from the scene hierarchy:

imageimage

Now, open the EnvironmentHandler-script, and write the following code:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EnvironmentHandler : MonoBehaviour {
    public GameObject BackgroundPrefab;
    public GameObject Player;

    List<GameObject> spawnedBackgrounds = new List<GameObject>();

    int spawnIndex = 2;

    // Use this for initialization
    void Start () {
        for (int i = 0; i < spawnIndex; i++)
        {
            spawnedBackgrounds.Add(
                (GameObject)Instantiate(BackgroundPrefab,
                                        new Vector3(i * 51.2f + 25.6f, 0, 0.01f),
                                        Quaternion.identity)
                );
        }
    }

    // Update is called once per frame
    void Update()
    {
        bool addNewBackground = false;
        foreach (GameObject bgObject in spawnedBackgrounds)
        {
            if (bgObject != null)
            {
                if (bgObject.activeInHierarchy)
                {
                    float distanceFromPlayer =
                          Player.transform.position.x – bgObject.transform.position.x;

                    if (distanceFromPlayer > 51.2f)
                    {
                        Destroy(bgObject);
                        bgObject.SetActive(false);
                        addNewBackground = true;
                    }
                }
            }
        }

        if (addNewBackground)
        {
            spawnedBackgrounds.Add(
                (GameObject)Instantiate(BackgroundPrefab,
                                        new Vector3(spawnIndex * 51.2f + 25.6f, 0, 0.01f),
                                        Quaternion.identity));
            spawnIndex++;
        }
    }
}

Oh, another script that looks complex! Again, I wrote this to have a simple code so it would be easy to understand the goal and logic of it, not efficient so if you need a place to optimize, this is a place to test out (but it should be good enought Smilefjes som blunker).

So… what is this script doing?
It’s simple – what we want is to render two backgrounds on our scene. If one background is behind us, remove it and spawn a new infront of us.

image

When we start the level, two Background GameObjects are spawned. These are positioned at the scenes origin (where the player starts) – 25.6f. This number is the width of the background game object divided by two. This is to make sure that we don’t get half the screen empty in the first run like this:
image

The image shows the blue area where there isnt yet a part of our background object since they havent scrolled there yet (or the player havent moved away from the start position yet). By subtracting this, we move all the background objects 25.6f to the left.

Next, we check the distance of the backgrounds behind the player, and if any of them are further away than 51.2 (that’s the length of the entire background gameobject), we remove it and tell the code that we want to add a new in front.

spawnIndex is used to remember where in the world we are.

On the Main Camera where the EnvironementHandler script is attached, drag the new Background-prefab to the Background Prefab property, and our Player-prefab to the Player property:
image

Now, test to see if we are moving forward, and that you can move the player up and down with the mouse/touch-screen.

 

V. Making sure the camera is “inside” our environment

As you probably see, we can move the player outside of the invironment. And even if we don’t, some of the environments edges are inside of the view, making it possible to see the blue background color of our scene.

It’s time to remove this artifact, something we will do on the script that we attached to our Main Camera earlier.

Click on the Main Camera GameObject, and edit the script attached to it by doubleclicking it:

image

Change the script with the following modifications:

#pragma strict

var target : Transform;
var smoothTime = 0.3;
private var thisTransform : Transform;
private var velocity : Vector2;

function Start()
{
    thisTransform = transform;
}

function Update()
{
    thisTransform.position.x = Mathf.SmoothDamp( thisTransform.position.x,
        target.position.x, velocity.x, smoothTime);
   
    thisTransform.position.y = -0.5;
}

This will lock the cameras Y-axis to the given position.

Try running the scene again and we can see that the camera is now placed on –0.5 on the Y-axis (this coordinate was found by trail and error based on where the sidewalk on the texture is).

VI. Making sure our player is on the sidewalk

The last thing we will do today is to make sure the player is inside the sidewalk. We do this the same way as with the camera, but inside the PlayerHandler-script. Here we will limit the minimum and maximum value of the players Y-position.

This is very simple. We check that the player is between –2.0 and – 5.5 (found by trial and error). If you press Play on the scene, move the player to the top part of the sidewalk:
imageimage

..and then click the Player in the scene hierarchy to view the properties, you can see that Y is around –2.0. This is the method I used to create these bounds.

using UnityEngine;
using System.Collections;

public class PlayerHandler : MonoBehaviour {
    float speed = 4.0f;
    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
        Vector3 movePlayerVector = Vector3.right;

        if (Input.GetMouseButton(0))
        {
            Vector3 touchWorldPoint = Camera.main.ScreenToWorldPoint(
                new Vector3(Input.mousePosition.x,
                            Input.mousePosition.y,
                            10.0f));

            if (touchWorldPoint.y > this.transform.position.y)
            {
                movePlayerVector.y = 1.0f;
            }
            else movePlayerVector.y = -1.0f;
        }

        this.transform.position += movePlayerVector * Time.deltaTime * speed;

        if (transform.position.y > -2.0)
        {
            transform.position = new Vector3(transform.position.x,
                                            -2.0f,
                                            transform.position.z);
        }

        if (transform.position.y < -5.5)
        {
            transform.position = new Vector3(transform.position.x,
                                            -5.5f,
                                            transform.position.z);
        }
    }
}

Now, pressing play again – you can see that we can move our robot up and down, he is kept between the bounds of the sidewalk and the camera is inside the environment.

The last thing we want to do is to set the target of our player a bit in front of us, so that we can see longer in to the scene than what we can do now.

Right now it’s:

image

This is simple. Add a new empty GameObject to our scene and drag it inside our Player Game Object. Give it the name “CameraTarget” and position position to 6,0,0

a) Create the GameObject, put it inside the player and set the name to CameraTarget
image

b) Set the position to 6,0,0
image

 

Next, we set this as the target for our SmoothFollow2d script on our Main Camera.

Click the Main Camera GameObject:

image

Drag the CameraTarget from the Hierarchy to the target property of the script:

imageimage

Now, run the game again and you can see that our visibility is much better! Smilefjes

image

In the next tutorial, we will create the enemies and spawn them. We will also make is possible to shoot them with our laser!

Download project, sources and assets here.

This entry was posted in Tutorial, Unity. Bookmark the permalink.

2 Responses to Unity for Windows VII–Creating a more advanced game, Part 2

  1. Pingback: Unity for Windows VIII–Creating a more advanced game, Part 3 | digitalerr0r

  2. Everything else worked fine, but backgrounds are not extended to infinite. Only first two are laid out properly..

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.