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:
Now we need to give the enemy a look, a texture. Create a new Quad game object:
Set the transform position to 0,0,0:
Put it inside the enemy game object:
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:
c) Set the shader to be Unlit/Transparent:
d) Assign it to the texture game object inside the enemy:
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
b) Assign it to the enemy game object:
c) Set the Animation Set to 1 and drag the Texture Game Object inside the Enemy to the Texture To Animate property:
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:
Assign it to the Enemy GameObject:
You can see that it’s now a component of the game object:
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
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):
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.
c) Add a box collider to the Enemy:
d) Make sure the properties of the box collider so it surrounds our enemy object, including the Z-axis. This should happen automatically:
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..
c) Click the Enemy game object in the hierarchy view and set the tag to the new Enemy-tag:
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:
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:
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).
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:
Attach it to the Main Camera of the scene:
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:
Delete if from the scene:
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:
(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:
Add a quad to the Laser GameObject:
Resize the laser using scale to the following:
Create a new Material called LaserMaterial to the Materials folder:
Give it the tint color of red:
Now, assign the material to the lasers texture object:
It should now look something like this:
Next, we must add a rigidbody and a boxcollider to it:
First, add the rigidbody and make the constraits and gravity as the following:
It will now look something like this:
The last thing we need to do is to is to set the Shader of the LaserMaterial to Mobile/Particles/VertexLit Blend:
VI. Scripting the laser
Create a new script called LaserHandler to our Scripts folder:
Assign this script to the Laser gameobject:
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:
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:
And add a new tag called “Laser”:
And set the tag of the Laser prefa to “Laser”:
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!
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.
Pingback: Unity for Windows IX–Creating a more advanced game, Part 4 | digitalerr0r
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()