UNITY 3D – Game Programming – Part 8 - CodeProject

:

Introduction

In part eight of the article we will look at how to improve the experience and make our game idea to be more attractive. We will add obstacles in our game play. In addition we will introduce sound and light effects that will enhance the environment considerable and bring it to life.

If you have not already done so, please take a moment and read:

  1. Unity 3D – Game Programming – Part 1
  2. Unity 3D – Game Programming – Part 2

  3. Unity 3D – Game Programming – Part 3

  4. Unity 3D – Game Programming – Part 4

  5. Unity 3D – Game Programming – Part 5

  6. Unity 3D – Game Programming – Part 6

  7. Unity 3D – Game Programming – Part 7

  8. Unity 3D – Game Programming – Part 8

  9. Unity 3D – Game Programming – Part 9

  10. Unity 3D – Game Programming – Part 10

Unity 3D Networking Article(s):

  1. Unity 3D - Network Game Programming

Unity 3D Leap Motion and Oculus Rift Article(s):

  1. Unity 3D - Leap Motion Integration

In the first part of the series we started by the very basics of the Unity 3D environment. Getting a feel of the IDE and the different sections which you will be working with throughout your project. We also covered how to use the tools in the designer to apply different transformation to a selected Game Object: positioning, rotation and scaling. We finally looked at how to create our first script and using the script apply a rotation transform on the Y-Axis of our cube.

In the second part of the series, we looked at more of the transformation of a given object through coding. We also looked at how to create light sources that are crucial for the rendering of your objects in the scene.

In the third part of the series we looked at how to process user input through the keyboard and based on the key code take particular actions.

In the fourth part of the series, we looked at creating a simple user interface. The user interface that we developed provided us a means to feedback to the user, and also another method for the user to input to our game or simulation.

In the fifth part, we started the idea of a simple game. We also looked at how to import 3D models into the game engine.

In the sixth part, we expanded on our game idea and making it more interesting and more complete. We introduced several concepts regarding game play and game design as well as created a simple user interface for our game.

In the seventh part, we answered some of the questions that got raised in Part 6.

In part eight, we will be creating a better user experience and also visuals for our players.

Windows Phone 8.x Demo:

I have provided a free phone application that you can download and preview the demos on your Windows Phone. To download the mobile application, follow the link: CodeProjectArticleSample

https://www.codeproject.com/KB/game/876015/Icon_106.png
Code Project Articles Sample Mobile App

Live Preview of Article Code and Visuals:

https://www.codeproject.com/KB/game/876015/preview_screen.png

Link to live preview: http://www.noorcon.com/CodeProject/CodeProjectArticlePreview.html

Background

NOTE: For this particle, I will be using SketchUp to create some simple building blocks, which I will use to import into Unity! I am not a 3D Modeler or Designer, so please be patient and excuse the mess!

It is assumed that the reader of this article is familiar with programming concepts in general. It is also assumed that the reader has an understanding and experience of the C# language. It is also recommended that the reader of the article is familiar with Object-Oriented Programming and Design Concepts as well. We will be covering them briefly throughout the article as needed, but we will not get into the details as they are separate topics altogether. We also assume that you have a passion to learn 3D programming and have the basic theoretical concepts for 3D Graphics and Vector Math.

Lastly, the article uses Unity 3D version 4.6.1 which is the latest public release as of the initial publication date. Most of the topics discussed in the series will be compatible with older versions of the game engine, and perhaps also the new version which is supposed to be release sometime this year. There is however, one topics which is significantly different in the current 4.6.1 version compared to the older version of the game engine, and that is the UI (User Interface) pipeline. This is due to the new UI architecture in the engine which is far superior to what we had prior to this release. I for one, am very happy with the new UI architecture.

Using the code

Downloading the project/source code for article series: Download source.

With each consecutive article that is submitted, the project/source code will be also expanding. The new project files and source files will be inclusive of older parts in the series.

NOTE: To get the latest code, go to the most recent published part in the series and download the code.

Improving the Gameplay

One major thing that is missing from our game is some sort of an obstacle. Indeed, we actually have one obstacle already defined in our game, and that is, time. The player is bound to the amount of time given at the beginning of the game to run around and collect his or her coins. This is challenging, but it is going to get old after a while.

Players usually want to face some challenge and overcoming the challenge is the satisfaction one gets when they achieve their objective in a game. Therefore, as a game designer you have to be able to create obstacles that are challenging enough to keep the player alert and engaged, but not overly complicated to discourage the player.

For our little example game, I want to introduce one such challenge. The idea I have is rather simple but it will enhance the gameplay a little bit more. I want to introduce a GameObject that will be used as a base to shoot cannon balls. If these cannon balls hit the player, then the player will fail.

As always, since I am not a graphics designer, I will be sticking to simple models to illustrate and implement our cannon!

Modeling the Cannon and the Cannon Ball

For the cannon, I will be using a Cube Primitive. The dimensions of the base will be 10 cm x 10 cm x 10 cm. In other words, (0.1,0.1,0.1) for the scale on the (x,y,z) axis. That’s as far as the 3D visual aspect of our cannon goes.


Figure 1-Cannon Base

I also created a material for the Cannon GameObject The material can be attached to the newly created Cube Primitive to give it some color.

Introduction to Model Hierarchy

Our Cannon GameObject visually looks simple, but the way I am approaching its design, it will be a little more involved from a hierarchical perspective. In order to make my cannon work the way I have envisioned, I would need to introduce two more GameObjects to the structure of the cannon. I call one CannonBase and the other CannonStart.

These two GameObjects are what’s called Empty GameObject. That is, they do not have any visual component to them. By default they only have a Transform component attached to them.

We will be using Empty GameObjects for a few important parts of our cannon. First, CannonBase will be used to rotate the nozzle of our cannon. Second, CannonStart will be used to indicate the starting position of our cannon ball.


Figure 2-Structure of Cannon GameObject

Take a look at Figure 2. Notice, that the Cannon GameObject has two child GameObjects. These child objects are our Empty GameObjects representing the CannonBase and CannonStart.

NOTE: Positioning of the child GameObjects are important. When you make a GameObject a child of another GameObject, the transform of the child GameObject is relative to the parent GameObject. This is very important and you must be aware of the relation and relative position.

The following figures will illustrate the Inspector Window for each GameObject representing the Cannon:

 

I have made the figures available as a visual clue. Notice that the Cannon GameObject as the parent GameObject is sitting at a position of (-3.892, 0.05, 1.082), CannonBase GameObject which is a child of the Cannon GameObject is sitting at a position of (0, 0.55, 0). This position is relative to the parent GameObject. So this means, that CannonBase is 0.55 meters above the center of the parent GameObject. Then, CannonStart GameObject is a child of CannonBase GameObject is sitting at a position of (0, 0.1, 0), relative to its parent object. Also note, that the CannonStart GameObject has a rotation of 347 degrees on its X-Axis. You will figure out why shortly.

NOTE: Usually it is a good idea to do a Reset on the child GameObject when you first attach it to its parent. This is done by using the Settings drop-down from the Inspector Window for the Transform Component of the selected GameObject. This will move it to the center of the parent GameObject. Then you can adjust accordingly.


Figure 9-Reset Child GameObject

Now that we are happy with our cannon model, it is time to bring it to life with some magic! Yes, you guessed it, programming!

using UnityEngine;
using System.Collections;

public class LaunchCannon : MonoBehaviour {

 public float canonBallSpeed = 0.5f;  // spped of our cannon ball
 public float rateOfFire = 5.5f;   // cannon blast rate in seconds
 public float fireDelay;

 public GameObject cannonBall;   // used to store our cannon ball prefab
 public GameObject cannonBase;   // used to store our cannon base
 public GameObject cannonStart;   // used to store our cannon nozle starting point

 // Use this for initialization
 void Start () {

  this.canonBallSpeed = Random.Range (3, 4); // randomize cannon ball speed between 3 and 4
  this.rateOfFire = Random.Range (3, 6.5f); // randomize rate of fire between 3 and 6.5 seconds

  // set a fire delay time for the cannon
  this.fireDelay = Time.time + this.rateOfFire;
 }
 
 // Update is called once per frame
 void Update () {

  // if the current game running time is larger then our fire delay time, then fire!
  if (Time.time > this.fireDelay){

   // cannon ball speed and rate of fire will be randomly generated based
   // on the defined boundaries ...
   this.canonBallSpeed = Random.Range (3, 4);
   this.rateOfFire = Random.Range (3, 6.5f);

   // re-set our fire delay
   this.fireDelay = Time.time + this.rateOfFire;
   
   // instantiate our cannon ball at the specified location
   GameObject fire = GameObject.Instantiate(this.cannonBall,
                                            this.cannonStart.transform.position,
                                            this.cannonStart.transform.rotation) as GameObject;

   // self-destruct our cannon ball after 10 seconds
   Destroy(fire, 10.0f);

   // use the physics engine to push/give velocity to our cannon ball
   fire.rigidbody.velocity = this.cannonStart.transform.TransformDirection(
    new Vector3(0,this.canonBallSpeed,0));
  } 

  // rotate the cannon base around its Y-Axis continiously
  this.cannonBase.transform.Rotate (Vector3.up, 10 * Time.deltaTime);
 }
}

The script is pretty simple. Let’s take a look at it. We have the following GameObject variables defined: cannonBall, cannonBase and cannonStart. The variable names should be self-descriptive. The variable cannonBall is a reference to the prefab that will represent our cannon ball, the variable cannonBase is a reference to the cannon base Empty GameObject in the cannon model, and cannonStart is a reference to the cannon start Empty GameObject in the cannon model.

The variable cannonball is used to reference and instantiate our cannon ball when the cannon is ready to go off. The variable cannonStart is used to dictate the initial position of the cannon ball when it is instantiated. The variable cannonBase is used to rotate itself and the attached child object cannonStart continuously on the Y-Axis.

Notice in the Start() and the Update() functions we set the cannonBallSpeed and the rateOfFire variables to a randomly generated number. This is done to make the cannon’s act and feel independently and at random to make it more interesting.

Another element to notice is that we have a timer set and the cannon only fires if the timer condition is met. The if (Time.time > this.fireDelay) statement takes care of that for us. Time.time is the actual running time of the game! It starts from 0 … N, N being when you exit or terminate the game. The variable fireDelay is set to be the addition of the rateOfFire and current Time.time. This will make sure that the cannon does not fire continuously cannon ball after cannon ball and flood the game with cannon balls! To see the difference, just comment out the if() statement.

One more very important thing to notice: Destroy(fire, 10.0f); is used to destroy the specified game object. Can you guess why this is important?

Imagine the following, assume that your cannon is blasting cannon balls every 2 seconds. That means every two seconds we create a new cannon ball GameObject. So in 10 seconds we will have 5 cannon balls in the scene, in 60 seconds we will have 30, and in 5 minutes we will have 150 cannon balls generated per cannon in the scene!

Now assume we place 5 cannons in our level, this would generate 750 cannon balls in 5 minutes! That is a lot of cannon balls in the scene! It will not only not allow the player to get around from a gameplay point of view, but it will also waste a lot of memory and CPU power. Remember, that these object are rigidbody objects and each one interacts with the physics engine, therefore, the game engine has to calculate and compute the actual interaction of all of these game objects continuously while they are living in the memory! So you will need to take that into consideration when developing your level.

So the Destroy(GameObject,TimeInSeconds) function will remove from memory the referenced GameObject after a specified time in seconds! In our case, each cannon ball has a lifespan of 10 seconds in the game!

The Cannon Ball

The cannon ball itself is nothing more than a Sphere Primitive. I have scaled it down to (0.05, 0.05, 0.05) on all three axis. Apply a Rigidbody to it and set the Interpolate option to Interpolate. One more component I have introduced was the Audio Source. When you attach an Audio Source to a GameObject, you are able to generate sound from the GameObject, in this case, we want our cannon to give us a sound effect of shooting a cannon ball, and therefore, the easiest way to apply sound is to apply it to the cannon ball itself. Now you can apply an audio clip to the audio source and have it play when needed.


Figure 10-Rigidbody for CannonBall


Figure 11-Audio Source for CannonBall

Once you are done and satisfied with your cannon ball, go ahead and make a Prefab of it. You will need to assign this Prefab to the script described above.

Enhancing the Scene and Putting Everything Together

I have gone ahead and also added four additional light sources, and places each one at one of the corners. Since, my level does not have any textures, I thought giving it some light effects will enhance it visually, and also can be used as a visual clue for the player to know where they are in the level.


Figure 12-Adding Light Sources and Etc...

This can come handy as you start expanding on the idea and introducing new features. I added four point lights with unique colors of Red, Blue, Orange and Green.

The next step was to attach the script to the Cannon GameObject. Once attached, I went ahead and assigned the following variables to their respective elements: cannonBall, cannonBase, cannonStart. If you recall, cannonball is a reference to the CannonBall Prefab, cannonBase and cannonStart are a reference to the child objects on the Cannon GameObject hierarchy! Once done, I made the Cannon GameObject into a Prefab as well.

Now, you can drag and drop your Cannon Prefab as many times as you would like on the scene. I have placed 5 Cannons. You can visually see where they are from Figure 12 as they have pinkish tone to them.

One last thing I have done is add another Audio Source to the CP (Character Player) and I have attached the background level music to this Audio Source. So now when you start the game, you hear the background level music and also the sound effects of the cannon ball when they are fired.

Points of Interest

We did not create a means for the cannon balls to destroy the player or cause some damage to the player as of yet. The next step would be to come up with a mechanism to damage our player if they are hit by the cannon balls.

History

This is the eighth article of a series which I would slowly contribute to the Code Project community.

  1. Unity 3D – Game Programming – Part 1
  2. Unity 3D – Game Programming – Part 2

  3. Unity 3D – Game Programming – Part 3

  4. Unity 3D – Game Programming – Part 4

  5. Unity 3D – Game Programming – Part 5

  6. Unity 3D – Game Programming – Part 6

  7. Unity 3D – Game Programming – Part 7

  8. Unity 3D – Game Programming – Part 8

  9. Unity 3D – Game Programming – Part 9

  10. Unity 3D – Game Programming – Part 10

Unity 3D Networking Article(s):

  1. Unity 3D - Network Game Programming

Unity 3D Leap Motion and Oculus Rift Article(s):

  1. Unity 3D - Leap Motion Integration