How to make a game in Unity3D – Part 2

Fractal artwork used under the GPL 3.0 License from http://opengameart.org/content/fractal-alien-landscape-pack
Download link for complete project Link here.

become a professional vr game developer with unity

Pre-Order The Complete Virtual Reality Game Development with Unity and learn to create immersive games and experiences by building 10 VR games. The course assumes no prior Unity or VR experience – We’ll teach you C#, Unity and 3D programming from the ground-up

Check it out on Zenva Academy and get Early Access!

 

Today, we will be taking the design concept we made in part 1 and actually be developing the game. Whilst this game will not be of AAA quality, it will show the fundamentals of game design and implementation. We will be using concepts learned from all of my previous tutorials in some way, shape, or form to be creating this game. For example; we could use JSON or XML file format for saving data, algorithms for the missiles flying at the player from random directions, and so much more.
Today, we will focus on the primary game play for this game. That means, we will be working in a single scene. We will also only implement the scripts needed to get the base game to run.
I hope you are as excited as I am about this tutorial. It has been quite a few months and tutorials to lead up to this one. So, let’s jump right on in and start developing this long awaited game.

Part 1: Setting up the game skeleton

This one should be fairly obvious for all of us now. We need to first set up the skeleton of the whole project within the Unity3D editor. This can be as complete as you want it to be, but I like to start with the bare essentials. The bare essentials are the scripts, art, prefabs, and scene folders.

1

Next up, we take all of the art that we have gathered / created and place them into the art folder. This includes the voxel jet, voxel missile, and the fractal art from open game art.

2

We now save our base scene and call it “Game Play Screen”.

3

Okay, now we can set up our scripts skeleton that we may or may not fully utilize when creating the game. The scripts we need are boundary, player controller, missile controller, destroy missile, and scroll plane.

4

We should now set up our prefabs, our prefabs will consist of the player ship and the missile at the present time. This is how they should be scaled and look.

5

Now we delete the missile prefab from the Hierarchy pane. It should still be in the prefabs folder, make sure not to delete it.

6

In the art folder, fractal sub directory; Make sure the fractal texture is set to texture, wrap mode of repeat, and a filter mode of trilinear. The name of the texture we will be using is fractal smoke.

7

Create a plane that is 100 x 100 x 100, y position set at -38.23, z position at 545.27. Attach the fractal image called fractal smoke to the plane.

8

Our base game skeleton is now complete. We can now begin working on the game itself. This is where the fun begins!

Part 2:  Choosing where to begin

Before we can really move forward, we need to decide if the back end or front end is of the most importance. A visually based person may decide to go with the front end first and then work on the back end. A person with a mind and knack for the abstract will go with the back end first. We will go with back end first because it is the industry standard. It is the industry standard because art, music, and mechanics may change throughout the development process; Back end can easily be scaled and modified to fit the new ideas whilst front end will struggle with it.

With this game, the back end will be setting up the game boundaries, the missile controller, the player controller, background controller, and the destruction script. So, before we jump into the code, we should specify this information.

Section 1: Game Boundaries

Since we know this is an endless flight game, we don’t want the player to move too far to the left, right, up, or down but we want them to have enough free movement that they can dodge the obstacles. So we will give these a rough value of 10, we can modify these values as needed when we test the game play later on.

Left X has a max value of -10.
Right X has a max value of 10.
Upper Y has a max value of 10.
Lower Y has a max value of -10.

Since we know this will be in a class of its own, we also need to make sure the class is set to have the ability to be serialized.

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
    public float xMin, xMax, yMin, yMax;
}

System.Serialializable being attached to this class will allow us to modify the data in the class that calls this one in the Unity editor. More on this later.

Section 2: Player Controller

The player controller only needs to store the methods for moving the player around on the screen.

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour
{
    public Boundary boundary;
    public Rigidbody stiffBody;
    public float tilt;
    public float speed;

    void Update()
    {
        var horizontal = Input.GetAxis("Horizontal");
        var vertical = Input.GetAxis("Vertical");

        Vector3 movement = new Vector3(horizontal, vertical, 0f);
        stiffBody.velocity = movement * speed;

        stiffBody.position = new Vector3
        (
            Mathf.Clamp(stiffBody.position.x, boundary.xMin, boundary.xMax),
            Mathf.Clamp(stiffBody.position.y, boundary.yMin, boundary.yMax)
        );

        stiffBody.rotation = Quaternion.Euler(0.0f, 0.0f, stiffBody.velocity.x * -tilt);
    }
}

As you can see, we called the Boundary class within the player controller, although we have not specified the data directly in the code. You may not be familiar with the implementation of the Vector3 we have in this code.
This allows us to more explicitly state what we want the vector 3 values to be, since I only have 2 items in it, it defaults to Vector3(float x, float y). Mathf.Clamp allows you to clamp a value between a minimum float and maximum float value. Quaternion.Eurler is used to return a rotation that rotates z degrees around the z axis, x degrees around the x axis, and y degrees around the y axis (in that order).

Section 3: Missile Controller

The missile controller will house the methods and algorithms for when and how the missiles will spawn.

using UnityEngine;
using System.Collections;

public class MissileController : MonoBehaviour
{
    public GameObject hazard;

    private float spawnWait = 1f;

    void Start()
    {
        StartCoroutine(SpawnWaves());
    }

    IEnumerator SpawnWaves()
    {
        while (true)
        {
            var xMinMax = Random.Range(-15f, 20f);
            Vector3 spawnPosition = new Vector3(xMinMax, 10f, 25f);
            Quaternion spawnRotation = Quaternion.Euler(new Vector3(90f,0f,0f));
            Instantiate(hazard, spawnPosition, spawnRotation);
            yield return new WaitForSeconds(spawnWait);
            spawnWait -= 0.01f;
            if (spawnWait < 0.05f) spawnWait = 0.05f;
        }
    }
}

IEnumerator is Unity’s version of parallel programming and it is supposed to be used in conjunction with StartCoRoutine.

Section 4: Destroying Objects

We now need a way to make sure the player ship and the missile that hit the ship is destroyed when the collision has been detected. We also want to make sure the spawned missiles will automatically be destroyed after a certain time has passed.

using UnityEngine;
using System.Collections;

public class DestroyMissile : MonoBehaviour
{
    public float lifetime;

    void Start()
    {
        Destroy(gameObject, lifetime);
    }

    void OnTriggerEnter(Collider other)
    {
        Destroy(other.gameObject);
        Destroy(gameObject);
    }
}

We have 2 separate destroy capabilities in this code. The first one, inside of the Start method will destroy the specified game object at the appropriate time frame which we will specify as 5 seconds. OnTriggerEnter is called when the Collider other enters the trigger. Basically, when one of the specified objects collide with a different object or another object of the same type; The object is destroyed.

Section 5: Adding life to the background

We should make it so that our plane with the fractal image scrolls to simulate a flying ship. It adds some life to the game, although it is not 100% needed. There are two ways we could do this, one would be attaching it to player movement or by creating a script to handle it alone. I opted for the standalone script due to the fact that the player is supposed to dodge obstacles and isn’t going to constantly be moving.

using UnityEngine;
using System.Collections;

public class ScrollPlane : MonoBehaviour
{
    public MeshRenderer rend;

    private float scrollSpeed = 0.5F;

    void Start()
    {
        rend = GetComponent<MeshRenderer>();
    }
    void Update()
    {
        float offset = -Time.time * scrollSpeed;
        rend.material.SetTextureOffset("_MainTex", new Vector2(0, offset));
    }
}

 

Now that we have some of our back end done, let’s start building it with Unity.

Part 3: Using Unity to build out the game

The fun part is about to begin, we will now attach scripts to their rightful places and test to make sure everything works out according to plan. We all know that bugs can happen or items could be placed in the correct area.

Step 1:

Attach the Player script to the Jet. We want the player to control the Jet, we also want the Jet to move independently from the camera.

Part2Screen1

The script says we need a rigid body component, so we should add that to our jet via add component, physics, rigid body.

Part2Screen2

Make sure to set angular drag to 0, and uncheck the use gravity property.

Part2Screen3

Now we can drag the jet game object onto the stiff body in the player controller. We also need to set our x min and y min to be -10. X max and y max should be 10. Tilt should be set at 5, and speed should be 10.

Part2Screen4

Step 2:

Moving on to the Missile prefab. We should click on it and add component, script, destroy missile.

Part2Screen5

Change the Lifetime property to be 5. We want the missile to last for 5 seconds before it destroys itself off screen.

Part2Screen6

Step 3:

Create an empty Game Object in the hierarchy pane and rename it to Game Controller. (Note: You don’t have to change the x, y, z coordinates for this; I chose to because I am neurotic.)

Part2Screen7

Add component, script, missile controller or drag and drop the missile controller script onto Game Controller.

Part2Screen8

Attach the Missile prefab to the Hazard property in the Inspector Pane.

Part2Screen9

Step 4:

Select the Plane object and add the scroll plane script to it.

Part2Screen10

drag the plane from the hierarchy pane to the rend property in the Inspector pane.

Part2Screen11

Step 5:

Run the game and let’s see how it goes.

Part2Screen12

Whoops, looks like something is over writing our jet’s z position. This is why testing is important. We all make mistakes, including myself. So, let’s go back over the player controller script to see where the problem lies.

The problem does not lie in the code, rather, it lies in the constraints section of the Rigid body component. We need to make sure that we freeze the position and rotation on the z axis.

Part2Screen13

Now, this isn’t too much of a game currently even though it runs correctly now. We need to add some collisions to make the hazards… Well… hazardous!

Step 6:

Select the Jet and add component, physics, box collider.
Part2Screen15

Switch from game to scene view to take a look at how the box collider would be around the Jet.

Part2Screen15

Set the size to be as followed. X 68, Y 10, Z 68 and put a check in the box for is trigger.

Part2Screen16

We now need to do essentially the same thing with the Missile. I suggest you put a copy of the prefab on screen for editing.

Part2Screen17

Add the box collider component to it and Unity should auto size it to be perfect. Make sure Is Trigger is checked.

Part2Screen18

Click the apply button at the top of the inspector pane. This will save the changes to the prefab itself.

Part2Screen19

Now you can delete the Missile from the hierarchy pane.

Part2Screen20

Here are the final results:

BoomGoesTheVoxel

Side Note:

If Unity keeps giving you issues about the rigid body component on the Missile, you can delete the code that references it in the Missile Controller Script or simply remove the rigid body from the missile in the Unity editor.

Revision to the code for the missile controller, in case you want to go that route.

using UnityEngine;
using System.Collections;

public class MissileController : MonoBehaviour
{
    public GameObject hazard;

    private float spawnWait = 1f;

    void Start()
    {
        StartCoroutine(SpawnWaves());
    }

    IEnumerator SpawnWaves()
    {
        while (true)
        {
            var xMinMax = Random.Range(-15f, 20f);
            Vector3 spawnPosition = new Vector3(xMinMax, 10f, 25f);
            Quaternion spawnRotation = Quaternion.Euler(new Vector3(90f,0f,0f));
            Instantiate(hazard, spawnPosition, spawnRotation);
            yield return new WaitForSeconds(spawnWait);
            spawnWait -= 0.01f;
            if (spawnWait < 0.05f) spawnWait = 0.05f;
        }
    }
}

Well, that’s it for today. To reiterate what we have gone over, we have set up the basic game skeleton for the game play. We expanded upon it by adding and writing the scripts needed for the game play. We added all of the images and models we needed for the basic game play as well.  Part 3 will cover the remaining portions for making this a full on game. I hope to see you there. May your code be robust and bug free, This is Jesse signing out.