Unity for Windows VIII–Creating a more advanced game, Part 3

image

Continuing from Part 2 of the more advanced game tutorial, we will add enemies and the possibility to shoot them with our laser!

You can download the project, source and game assets here.

I. Adding the enemy GameObject

The enemy GameObject will be built up the same as our Player – a main game object, a texture and a script to handle it. Go ahead and create a new empty game object, this will function as the main enemy game object:
image

Give it the name “Enemy”:
image

Set the position to 0,0,0:
image

Now we need to give the enemy a look, a texture. Create a new Quad game object:
image

Give it the name “Texture”:
image

Set the transform position to 0,0,0:
image

Put it inside the enemy game object:
image

Now, we need to create a look for our enemy. We start by creating a new material, assign our texture to it and add it to our enemy texture:
a) Add the Material and name it EnemyMaterial:
image

b) Give it the Enemy texture:
image
image

c) Set the shader to be Unlit/Transparent:
image

d) Assign it to the texture game object inside the enemy:
image

Now, we need to add animations to the enemy. We do this by using the same script we created in the previous tutorial.

Go to the Scripts folder and drag the AnimationHandler script to the enemy game object:
a) Find the AnimationHandler
image

b) Assign it to the enemy game object:
image

c) Set the Animation Set to 1 and drag the Texture Game Object inside the Enemy to the Texture To Animate property:
image

 

II. Scripting the enemy

The next thing we want to do is to script how the enemy behaves, and how it should spawn. We want it to spawn far out on the left side of our screen and move towards us.

Go ahead and create a new script in the Scripts folder, and name it EnemyHandler:
image

Assign it to the Enemy GameObject:
image
You can see that it’s now a component of the game object:
image

Edit the script in Visual Studio:

using UnityEngine;
using System.Collections;

public class EnemyHandler : MonoBehaviour {
    float speed = 4.0f;

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
        Vector3 moveVector = new Vector3(-speed, 0.0f, 0.0f);
        transform.position += moveVector * Time.deltaTime;
    }
}

The scripts contains a variable called speed that will be used to control the speed of our enemy. Then we use this to move it towards us (negative A-axis). Shouldn’t be anything new here Smilefjes som blunker

What’s mission is the possibility to add collisions to our Enemy. Let’s fix this by adding a rigidbody component and a box collider component to the Enemy:

a) Add a rigidbody component to the enemy (just clikc Add Component and find Rigidbody inside physics):
image

b) Set the Constraints so we freeze rotation, movement on the Z-axis and remove the tick from User Gravity. This is becuse we don’t want any outside forces to change the rotation or Z-position of our enemy.

image

c) Add a box collider to the Enemy:
image

d) Make sure the properties of the box collider so it surrounds our enemy object, including the Z-axis. This should happen automatically:
image
image

The last thing we need to do is to tag the enemy so we can find it and test collisions easily. To do this, we need to create a new tag for the enemy:

a) Do this by clicking the tags property on our enemy and then Add Tag..

image
image

b) Name the tag “Enemy”
image

c) Click the Enemy game object in the hierarchy view and set the tag to the new Enemy-tag:
image

Now, in the enemy script – for now, what we want to do is to remove the enemy form the scene if the position is behind our player (no need for it anymer) and if it hits the player. Make the following changes to our script:

using UnityEngine;
using System.Collections;

public class EnemyHandler : MonoBehaviour
{
    float speed = 4.0f;
    GameObject player;

    void OnCollisionEnter(Collision collision)
    {
        if (collision.rigidbody != null)
        {
            if (collision.rigidbody.name == “Player”)
            {
                Destroy(this.gameObject);
            }
        }
    }
    // Use this for initialization
    void Start()
    {
       
GameObject _p = GameObject.Find(“Player”);
        if (_p != null)
        {
            player = _p;
        }
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 moveVector = Vector3.left;
        transform.position += moveVector * speed * Time.deltaTime;

        if (player != null)
        {
            if (this.transform.position.x <= player.transform.position.x – 10.0f)
            {
                Destroy(this.gameObject);
            }
        }
    }
}

 

This implements the collision handler, checks it it collides with “Player” and if yes, remove itself from the world!

We also remove it if it walks too far behind us where we don’t need it anymore.

Right now the background is also collidable. Click the background prefab from the prefabs folder:
image

Uncheck the mesh collider:
image

This makes sure our enemies wont collide with the background.


 

III. Making collisions possible

To make collisions possible, we must do the same thing for our player. Go ahead and add a rigidbody to the player, and set the Constraints for the same reasons as with the enemy:

image

Also, add a box collider:
image
image

If you want to test this, move the enemy somewhere a bit in front of the player and press play. When the enemy crash with the player, it is removed. Also, replay the scene to test if the player is removed when walking past you (you can see that the enemy gameobject is removed from the scene hierarchy).

image

 

IV. Spawning the enemy

We want to create a logic that automatically spawns enemies over time. Let’s create a new script called GameHandler in the Scripts-folder:
image

Attach it to the Main Camera of the scene:

image

Perfect!

Now, we must make the enemy to a prefab so we can spawn with our script. Drag the enemy from the hierarchy to the Prefabs folder as we did with the background:

image

Delete if from the scene:

image

image

 

The next thing we need is to script the GameHandler so it spawns new enemies. Open the script, it will look like this:

using UnityEngine;
using System.Collections;

public class GameHandler : MonoBehaviour {

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

The first thing we want to do is to add a level variable. This will be used to indicate how far in to the game we are.

using UnityEngine;
using System.Collections;

public class GameHandler : MonoBehaviour {
    public int level;
    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
   
    }
}

Now, add another variable that will spawn our enemies based on what the level indicator says.

using UnityEngine;
using System.Collections;

public class GameHandler : MonoBehaviour {
    public int level;

    float spawnNewEnemyTimer = 10;
    // Use this for initialization
    void Start () {
    }
   
    // Update is called once per frame
    void Update () {
       
spawnNewEnemyTimer -= Time.deltaTime;
        if (spawnNewEnemyTimer <= 0)
        {
            spawnNewEnemyTimer = 5 – (level * 0.25f);
        }

    }
}

We start by spawning a new enemy after 10 seconds (to give the player some time to start). Once the level starts increaseing the time it takes before a new enemy is spawned is reduced slightly.

Then we add the enemy prefab and the player variable – we need the enemy to instansiate and then we need the player for other stuff like where to spawn a new enemy:

using UnityEngine;
using System.Collections;

public class GameHandler : MonoBehaviour
{
    public int level;
   
public GameObject enemy;
    public GameObject player;

    float spawnNewEnemyTimer = 10;

    // Use this for initialization
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        spawnNewEnemyTimer -= Time.deltaTime;
        if (spawnNewEnemyTimer <= 0)
        {
            spawnNewEnemyTimer = 5 – (level * 0.25f);
        }
    }
}

This means that we can instansiate a new enemy whenever we want! Let’s do this next:

using UnityEngine;
using System.Collections;

public class GameHandler : MonoBehaviour
{
    public int level;
    public GameObject enemy;
    public GameObject player;

    float spawnNewEnemyTimer = 10;

    // Use this for initialization
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        spawnNewEnemyTimer -= Time.deltaTime;
        if (spawnNewEnemyTimer <= 0)
        {
            spawnNewEnemyTimer = 5 – (level * 0.25f);
           
Instantiate(enemy, new Vector3(player.transform.position.x + 50.0f,
                    player.transform.position.y, 0.0f), Quaternion.identity);
        }
    }
}

Go back to the editor and set the missing properties on the Main Cameras GameHandler script:

image

(remember, the Enemy is set to the Enemy prefab)

Press play to see the script in action. A new enemy is spawned every 5 seconds 50 units in front of the player.

We will work more with the logic of levels and so on later. First, we need to be able to make our player shoot.

 

V. Creating the laser prefab

The laser will be a quad that will move at a speed towards the right side of the screen, untill it hits a player or goes too far.

Start by create an empty gameobject:
image

Add a quad to the Laser GameObject:
image

Resize the laser using scale to the following:
image

Create a new Material called LaserMaterial to the Materials folder:
image

Give it the tint color of red:
image

Now, assign the material to the lasers texture object:
image

It should now look something like this:
image

Next, we must add a rigidbody and a boxcollider to it:

First, add the rigidbody and make the constraits and gravity as the following:
image

Also, add a box collider:
image

It will now look something like this:

image

The last thing we need to do is to is to set the Shader of the LaserMaterial to Mobile/Particles/VertexLit Blend:
image

 

VI. Scripting the laser

Create a new script called LaserHandler to our Scripts folder:
image

Assign this script to the Laser gameobject:

image
image

Great! It’s time to give the laser some logic. Edit the script and make it move towards the right side of the screen:

using UnityEngine;
using System.Collections;

public class LaserHandler : MonoBehaviour {
    float speed = 16.0f;
    float aliveTimer = 2.0f;

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
        aliveTimer -= Time.deltaTime;

        if (aliveTimer > 0.0f)
        {
            transform.position += Vector3.right * speed * Time.deltaTime;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }
}

This will make the laser move, and be destroyed after two seconds if it haven’t hit anything yet.

Now, create a prefab out of the laser gameobject by draging it to the Prefabs folder:
image

Delete it from the scene:
imageimage

Now that our Laser is ready for spawning, we must change our player script to enable shooting:

using UnityEngine;
using System.Collections;

public class PlayerHandler : MonoBehaviour {
    float speed = 4.0f;
    public GameObject laserPrefab;

    float shootTimer = 0.0f;
    float setShootTimerTo = 0.5f;

    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {
        Vector3 movePlayerVector = Vector3.right;
        shootTimer -= Time.deltaTime;

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

            if (touchWorldPoint.x < this.transform.position.x + 5.0f)
            {
                if (touchWorldPoint.y > this.transform.position.y)
                {
                    movePlayerVector.y = 1.0f;
                }
                else movePlayerVector.y = -1.0f;
            }
           
else
            {
                if (shootTimer <= 0)
                {
                    Vector3 shootPos = this.transform.position;
                    shootPos.x += 2;
                    Instantiate(laserPrefab, shootPos, Quaternion.identity);
                    shootTimer = setShootTimerTo;
                }
            }
        }

        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);
        }
    }
}

What we do here is to create a variable that holds the laserPrefab, and a timer that controls how frequent we are able to shoot.

Then we change how the input works. If we touch on the left side of the screen it will move our player, if we touch the right side it will shoot. Should not be anything new here!

If you play the scene now, you should be able to shoot the lasers! But when we hit an enemy with a laser, it will just push the enemy away. Let’s open the enemy script again and make sure that if a laser hits it, it will destroy both the laser and the enemy.

Edit the EnemyHandler script with the following modifications:


 

using UnityEngine;
using System.Collections;

public class EnemyHandler : MonoBehaviour
{
    float speed = 4.0f;
    GameObject player;

    void OnCollisionEnter(Collision collision)
    {
        if (collision.rigidbody != null)
        {
            if (collision.rigidbody.name == “Player”)
            {
                Destroy(this.gameObject);
            }

            if (collision.rigidbody.tag == “Laser”)
            {
                Destroy(this.gameObject);
                Destroy(collision.gameObject);
            }

        }
    }
    // Use this for initialization
    void Start()
    {
        GameObject _p = GameObject.Find(“Player”);
        if (_p != null)
        {
            player = _p;
        }
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 moveVector = Vector3.left;
        transform.position += moveVector * speed * Time.deltaTime;

        if (player != null)
        {
            if (this.transform.position.x <= player.transform.position.x – 10.0f)
            {
                Destroy(this.gameObject);
            }
        }
    }
}

Now, what we are doing here is to check it the laser got the tag Laser, and then if yes, destroy both.

This script won’t work before we set the Laser to the “Laser” tag. Click the Laser prefab:

image

And add a new tag called “Laser”:

image

And set the tag of the Laser prefa to “Laser”:

image

 

Play the game again, and you will be able to shoot lasers, destroy enemies and move the player! It sure starts looking like a game now! Smilefjes

image

 

Whats next and download the source

This concludes this tutorial, in the next part we will implement explosions, a system where the player can get XP and Level ups (making the game harder), loose health and die.

We will also create a simple UI so we can see what’s going on.

You can download the project, source and game assets here.

 

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

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

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

  2. Happypsycho says:

    adding a rigid body to the enemy gives this error:
    Actor::updateMassFromShapes: Compute mesh inertia tensor failed for one of the actor’s mesh shapes! Please change mesh geometry or supply a tensor manually!
    UnityEditor.DockArea:OnGUI()

Leave a comment

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