Monthly Archives: January 2015

Using the Debug Class

Unity has a Debug class with some really useful functions for speeding up development, testing, and debugging.

You probably already use Debug.Log() to add messages to the Console, such as keeping track of variables or notifying you of certain conditions:

Debug.Log("Player inside trigger area");
Debug.Log("X value: " + x.ToString());

If you don’t use Debug.Log() you should! It will print anything you want into Unity’s console window while running the game in the Editor.

Warnings and Error

The Debug class also lets you write warnings and errors to the Console. This lets you give yourself valuable feedback when debugging.

Here’s what the different log types look like in the Console window:

logs

Debug .Log, Debug.LogError, and Debug.LogWarning

 

Debug.LogError("This is a debug error message");
Debug.LogWarning("This is a debug warning message");

Pause the Game

Call Debug.Break() to pause your game in the Editor, allowing you to freeze the action at a particular point and look what’s happening:

Debug.Break();

Lines

debug_lines

Debug.DrawLine and Debug.DrawRay

The Debug class also lets you draw lines inside the Scene view while your game is playing. This is invaluable for working with linecasts and raycasts as it lets you see exactly what is happening in your scene, taking out the guesswork.

Debug lines are especially useful for making sure your vector maths is correct.

Debug.DrawLine() takes a start point, an end point, and a colour and draws a line (only visible in the Scene window while the game is running):

Debug.DrawLine(transform.position, othertransform.position, Color.magenta);

Debug.DrawRay() is similar, but draws a ray from an origin position in a given direction:

Debug.DrawRay(transform.positon, Vector3.up, Color.blue);

Link

Unity documentation for the Debug class: Unity Scripting API: Debug.

Beginner’s Guide: Create a Pong Clone in Unity: Part 10

Polishing it Off

We’re now at the end of our fun, enlightening, and probably exhausting journey to recreate Pong. In this final part we will add polish to the game and learn a few more titbits of Unity wisdom before signing off on Pong (or whatever you’ve called your version). Then we’ll build a standalone version of the game that can run on any computer without needing Unity. If you have access to a mobile device, I’ll touch a little bit on building and deploying to those, but with so many platforms and other variables, it’s outside of our scope to go into detail about that.

Snazzy Effects

We’ll add a few cool effects to our game to really up the fun factor. The best games have a lot of ‘juice’ – extra touches that make every frame addictive fun. Think of the Candy Crush clunk sounds or Angry Birds’ crashing, tumbling blocks. Granted, our Pong clone is not the height of fun or sophistication, but with these extra touches we’ll prove that even the simplest of games can be improved a lot by a few flourishes.

Shake the Camera

A simple, effective drop of juice is the camera shake. You see it in lots of games, and it gives a sense of kinetic energy, augmenting sound and vision to create something physical on a flat screen.

If you recall all the way back to Part 1 you may remember that our scene (and all scenes) has a default camera. You’ll also recall that all GameObjects (the camera is a GameObject) have a transform component, which determines its placement, rotation, and size. Therefore, if you move the camera’s transform you are effectively moving the view of the scene, or – from the perspective of the player – you’re moving the game area. If you quickly move the camera in small, random jolts, the screen will shake!

We will add a script to our MainCamera GameObject with a simple Shake() method, and we’ll call this method from GameManagerScript.

Create a new C# script called CameraShakeScript (remember to place it in the Scripts folder). Paste the following code into the script:

using UnityEngine;
using System.Collections;

public class CameraShakeScript : MonoBehaviour {
    // remember the correct starting camera position so we can revert back once shaking is complete
    private Vector3 originPosition;
    private Quaternion originRotation;

   public float originalDecay = 0.006f;
   public float originalIntensity = 0.04f;
   float shake_decay;
   float shake_intensity;
   private bool shaking; // is the camera supposed to be shaking at the moment
   Transform cameraTransform;

   void Start() {        
       cameraTransform =  Camera.main.transform;        
   }

   void Update (){
       if(!shaking)            
           return;        

       if (shake_intensity > 0f)
       {
            cameraTransform.localPosition = originPosition + Random.insideUnitSphere * shake_intensity;
            cameraTransform.localRotation = new Quaternion(                
            originRotation.x + Random.Range (-shake_intensity,shake_intensity) * .2f,                
            originRotation.y + Random.Range (-shake_intensity,shake_intensity) * .2f,                
            originRotation.z + Random.Range (-shake_intensity,shake_intensity) * .2f,                
            originRotation.w + Random.Range (-shake_intensity,shake_intensity) * .2f);
            shake_intensity -= shake_decay;
       }

      else
      {        
            shaking = false;
            // reset the camera to its original state
            cameraTransform.localPosition = originPosition;            
            cameraTransform.localRotation = originRotation;            
      }
   }

   public void Shake(){

      if(!shaking) {            
        originPosition = cameraTransform.localPosition;            
        originRotation = cameraTransform.localRotation;
      }

      shaking = true;        
      shake_intensity = originalIntensity;        
      shake_decay = originalDecay;
  }
}

I won’t go into detail about this code, but here’s what it does:

When Shake() is called, the camera is moved around randomly based on the intensity and decay variables (the decay determines how long the shake lasts and the intensity determines how much movement there is). Every frame the camera will shake if the shaking boolean variable is set to true. Once the shake is finished that value reverts to false.

  • Save that script and attach it to the GameManager GameObject.

Open GameManagerScript. We’ll use Unity’s find method to get a reference to the camera to demonstrate the syntax a bit more, but you could just as easily use [SerializeField] and drag CameraShakeScript into the empty field in the Inspector.

Add this variable to the script:

CameraShakeScript camShake;

Now, in Start(), populate the variable so it can be used in the script (place this line before the StartNewGame() call:

camShake = GetComponent<CameraShakeScript>();

Now we can make the camera shake by calling the Shake() method on cameraShake like this, which you need to add to the GoalScored() method at the start, so the camera will shake whenever a goal is scored:

camShake.Shake();

Test the Shakes

Run the game and see the shake effects. Nice. The shaking really ‘sells’ the action…

You can experiment with the shake by adjusting the Original Decay and Original Intensity variables via the Inspector. Can you modify the script to shake the camera every time the ball hits a wall?

Particles

A common technique used to create effects is the particle system. A particle system is a graphical effect created by an algorithm. Smoke is usually a particle effect. Particle effects let you create attractive effects with relatively little work (and, incidentally, low processing power).

Our particle effect is going to be rudimentary, but it will give you an idea of how particle systems work. We will display an ‘explosion’ of debris when a goal is scored.

Like everything else, a particle system is a component. We will attach our particle system to the goals, and to do this we will add it to the goal prefab.

Create a new ParticleSystem in the Hierarchy:

  • GameObject | Particle System
If you don’t see the particle system, double-click the new GameObject in the Hierarchy to centre the scene view on it. You may need to zoom in.

It should look like this:

We’ll change this to make a few bits of white debris to fly off the goal when a goal is scored.

With the particle system selected in the Hierarchy you’ll notice it has a lot of settings in the Inspector:

Make the following modifications:

  • Change Duration to 0.25 (how long the particle system shoots out particles)
  • Change Start Lifetime to 0.5 (how long a particle sticks around for)
  • Untick Play On Awake (we don’t want the particle system to automatically start)
  • Change Emission Rate to 40 (click the Emission heading to expand it first)
  • Make the particle system a child of Player1Goal.
  • Reset the particle system’s transform (i.e. set its position to 0, 0, 0 or click the cog in the Transform component and choose Reset).
  • Make the Particle System GameObject a child of Player1Goal (drag-and-drop it in the Hierarchy).
  • Reset the particle system’s transform by clicking the cog and selecting Reset in the Inspector with the Particle System GameObject selected. This sets the particle system’s transform to match the goal it’s attached to.
  • Change the Particle System‘s transform’s rotation values to X = 0, Y=90, and Z = 0. This makes the particles shoot out from the goal.

 

  • Lastly, untick the Looping property of the particle system. This will turn off the particle simulation.

Now we’re going to do something new. We’re going to ‘re-prefab’ our GoalPrefab. This means we are going to update GoalPrefab with changes we’ve made to one of its instances. To do this, drag-and-drop Player1Goal from the Hierarchy onto GoalPrefab in the Prefabs folder (you’ll need the Prefabs folder to be open in the Project window). Once you’ve done this the particle system will become part of the prefab, and Player2Goal will automatically get a matching particle system! That’s the power of prefabs, sir or madam!

Because Player2Goal is a carbon copy of Player1Goal the particle on Player2Goal will face in the same direction – but it needs to be facing the opposite direction, away from its own wall. To fix this, simply change Player2Goal’s Particle System Transform Rotation X value to 180 in the Inspector. This flips it on its X axis.

Script the Particle System

Before we can see our particles in action we need to fire it off at the appropriate time. Open GoalScript.

Insert this new variable:

[SerializeField]
ParticleSystem partSys;

Then change the OnCollisionEnter2D() method to this:

void OnCollisionEnter2D(Collision2D other)
{
    if(other.transform.name == "Ball")
    {
        gameMan.GoalScored(attackingPlayer);
        partSys.transform.position = new Vector2(partSys.transform.position.x, other.transform.position.y);
        partSys.Play();
    }
}

Here we move the particle system to the same position as the ball at the moment it hits the goal, then play the particle emission at that location so it looks like some debris is being chipped off the goal by the ball. Snazzy.

  • Save the script then head back into Unity.

For each of the player goal GameObjects:

  • Select the object, then drag its particle system child into the Part Sys field in the Goal Script Inspector entry. This populates the partSys variable with the particle system so the script has something to play.

Play the game…

Game Over

We’re done! We’ve completed our Pong clone. It’s no masterpiece, but hopefully it has taught you the main building blocks of creating a game in Unity. If you look back through these ten lessons you’ll see that you’ve learned a lot, and hopefully some of it has stuck! You should have a pretty solid grasp of GameObjects, MonoBehaviour scripts, components, the Inspector, and so on, perhaps enough to embark on your own game.

There are also lots of ways to improve on our Pong clone. Here are some suggestions:

  • Improve the UI.
  • Animate something in the main menu screen (a bouncing ball perhaps).
  • Stop the ball after every goal and have a 3…2…1…GO timer before play resumes.
  • Add some extra effects:
    • A bounce sound when the ball hits a wall
    • Flashing when a goal is scored
  • Implement an AI opponent for single-player action
  • Show the score on the End Game screen.

I hope you’ve learned a lot from these tutorials and – more importantly – I hope you’ve had fun!

Beginner’s Guide: Create a Pong Clone in Unity: Part 9

Wired for Sound

In this part of our Pong tutorial series we will finally add sound to our game! We’ll also get a bit more practice with scripting and the Unity UI system.

Sound Assets

You probably know the drill by now – create a new folder within Assets called ‘Audio’, and drag the sound files from the assets .zip into that folder (you can download the assets .zip file here). They will automatically have the correct names based on the file names.

We want to add sounds when the game is played, so start by opening the main game scene (Scene1).

  • Select GameManager in the Inspector
  • Add an AudioSource component (in the InspectorAdd Component | Audio | AudioSource).

An AudioSource is a component that plays audio in your scene.

 An AudioClip is an actual sound component.
 

Update GameManagerScript

We need to add variables that hold references to our sounds in GameManagerScript so we can play them at our leisure. Open GameManagerScript and add the following variables:

[SerializeField]
AudioClip goalScored;
[SerializeField]
AudioClip endGame;

Also add this variable, which we’ll treat a bit differently:

AudioSource audSource;

Save the script.

Remember, until you save a script, any serialized (or public) variables you have added won’t appear in the Inspector.

Drag the relevant audio clips onto the above variable fields via the Inspector in the same way we’ve done for other components in previous parts. This lets us populate those variables with the correct sound file.

We could (or rather should) do the same with the AudioSource (i.e. drag a component into the Inspector), but we’ll use a different method just so you can see this other method in use. Unity has ways to ‘find’ a GameObject or component within the current scene (or the GameObject that the current script is attached to). We’ll use one of those ways to find the AudioSource.

Add the following to GameManagerScript‘s Start() method (it doesn’t matter whereabouts in the method this goes):

audSource = GetComponent<AudioSource>();

That line looks through the GameObject this script is attached to and finds a component of type AudioSource, then puts a reference to it in our audSource variable. A similar method lets you find a GameObject:

// not code for your Pong game, just sample code to illustrate
player = GameObject.Find("Player1");

There are a few variations on these that we won’t go into, but you can find anything in your scene using these finder methods.

Searching for Unity components and GameObjects can be very slow (or ‘expensive’ in programming terms). You should never search for a component or GameObject during any of your game’s update methods (Update, FixedUpdate, or LateUpdate) or inside loops, as code can run very often, compounding the slowness. If you need to use a specific GameObject or component in repeating code (such as in Update()), get the reference once and store it in a variable, then use the variable in your loop or Update() method. 

We need a method to play a sound, so add this method to GameManagerScript:

void PlaySound(AudioClip soundClip)
{
    audSource.clip = soundClip;
    audSource.Play();
}

That should be pretty easy to understand. We must call this method any time we want a sound to play. We send the specific sound clip as a parameter so the method knows which to play. The audSource variable is our audio source, and the soundClip parameter is the specific sound we want to play via the audio source.

Add Calls to PlaySound()

Now, let’s add our calls to PlaySound(). At the beginning of the GoalScored() method, add:

PlaySound (goalScored);

At the end of the GameOver() method, add:

PlaySound (endGame);

End Game Fix

The next thing we need to do is clear up a gameplay issue that’s currently in the game. When a player reaches 3 points, the game resets abruptly. We will add a popup to congratulate the winner and provide a ‘New Game’ button to restart the match.

Open BallScript and create this new method that we can access from other scripts to stop the ball moving:

public void Stop()
{
    // this method stops the ball
    myBody.velocity = Vector2.zero;
}

While you have BallScript open we will make a slight change so that the ball doesn’t always start off traveling in the same direction after a goal is scored.

At the end of the Start() method, add this extra line:

forceValue = forceValue * -1;

That line effectively reverses the ball’s starting direction every time the game resets after a goal is scored. This works because the screen centre is (0,0), meaning a positive force value will push the ball to the right, and a negative value will push the ball left. Multiplying forceValue makes sure that the next time the ball starts it will go the other way. A simple little hack, but it works.

Save BallScript to apply the changes.

Now open GameManagerScript and find the GameOver() method. Replace the line:

gameBall.Reset();

with:

gameBall.Stop();

Now add the following new method to GameManagerScript:

public void StartNewGame()
{
     playerOneScore = 0;
     playerTwoScore = 0;
     UpdateScoreText ();
     gameBall.Reset ();
}

This method just needs to tell the ball to start again, and we will trigger it to run when our ‘New Game’ button is pressed.

Before we get to creating our end game screen, delete the following lines from the GameOver() method (as we have now placed them in the StartNewGame() method instead):

playerOneScore = 0;
playerTwoScore = 0;
UpdateScoreText ();

This just means the score stays visible until the game is reset so the winner can gloat. Save the script and go back into Unity.

EndGame Popup

Create a new GameObject and call it EndGame. Make EndGame a child of Canvas by dragging it into the Canvas GameObject.

Add three new empty GameObjects as children to EndGame with the following names (and in the following order in the Hierarchy):

  • Background
  • ResetButton
  • GameOverText.

Unity will render items in the order they appear in the Hierarchy, and whatever is rendered last renders on top of everything else. We need our text and button to be rendered on top of the background, so we set Background higher in the Hierarchy.


With the new GameObjects created the Canvas should look like this in the Hierarchy:


  • Give ResetButton a UI Button component.
  • Give GameOverText a UI Text component.
  • Select GameOverText in the Hierarchy and in the Inspector add “Game Over” in its Text field.
  • Style to text to be quite large, and move the transform so the text appears in the middle of the screen. (You may need to change the Width property of the Rect Transform in the Inspector to fit all the text on the screen.
  • Drag the Bangers font into the Font field as well, and change the text colour if you want.
  • Select ResetButton in the Hierachy.
  • Add a UI Image component and drag in the PlaySprite that we used on our main menu screen.
  • Within the Inspector, drag the Image (Script) component onto the Target Graphic field of the Button(Script) component just like we did on the main menu button earlier.
  • Reshape the Rect Trnasform to make the button look less stretched (again, just like we did earlier). If you select the Scale tool in the toolbar in the top-left of the Unity screen you can resize transforms easily by dragging the axis lines with the squares on the end (just like how you can move the transform in Transform mode by dragging the arrows):

 

  • Add a UI Image component to Background.
  • Change Background’s Color property in the Inspector (on the Image (Script) component). Choose a colour to act as a background. This will form a box to display our little game over screen (if you want to add an image instead, go ahead – it works just like adding any other image).
  • Stretch and position Background’s Rect Transform to look something like this:


If you can’t see the text or button, make sure Background is listed above them in the Hierarchy.

Next we need to make the button restart the game. To achieve this: 

  • Select ResetButton in Hierarchy.
  • In the Inspector, click the + at the bottom of the Button Script() component’s On Click() events area.
  • Drag the GameManager GameObject from the Hierarchy into the empty field currently containing None (Object).
  • In the drop-down menu (that currently reads ‘No Function’, select GameManagerScript | StartNewGame().

Now you might (rightly) be thinking ‘wait, we’ve covered our game screen with this menu’. We must implement a way to show and hide the menu. 

Show and Hide the Menu

Unity lets us turn GameObjects on and off via the SetActive() method. We’ll add a reference to the EndGame GameObject in GameManagerScript, then at the relevant times we will set EndGame’s active status to on (true) or off (false).

Add a serialized field to GameManagerScript:

[SerializeField]
GameObject endGameScreen;

Now you must populate that serialized field with the EndGame object. Select GameManager in the Hierarchy and drag EndGame onto the End Game Screen field.

Let’s clean up some code as well. You will notice that the Start() and StartNewGame() methods have some identical code. We don’t need repetition. We don’t need repetition. We don’t need repetition. Replace those two methods with the code below, to which I’ve also added a command to hide the end game screen:

public void StartNewGame()
{
    playerOneScore = 0;
    playerTwoScore = 0;
    UpdateScoreText ();
    endGameScreen.SetActive (false);
    gameBall.Reset ();
}

void Start ()
{
     audSource = GetComponent<AudioSource>();
     StartNewGame ();
}

Add this to the GameOver() method, just after the gameBall.Stop() line:

endGameScreen.SetActive (true);

That turns ON the end game screen when the match ends.

Now disable EndGame by default by turning off its transform. Select EndGame in the Hierarchy, then untick the little checkbox in the upper-left corner beside its name:


This also hides it while we’re in Unity working on our game.

Test the Game

Now hit the Play button and try out the game…

…weird, huh? The ball just moves up and down! It’s almost like we’ve taken a step backwards…

What happened is that when we changed GameManagerScript we inadvertently made the Ball’s Start() script execute twice, pushing the ball in one direction, then immediately in the opposite direction. This sort of thing can happen when you access public methods and variables between scripts, which is one reason you should avoid public whenever possible.

Fix BallScript

Let’s rework BallScript a bit to remedy the above problem. Open BallScript. As you see, the Reset() function calls the Start() function. We also call Reset() from GameManagerScript whenever a new point or game starts.

Cut the following lines from Start() and paste them into Reset() at the end of the method:

myBody.AddForce (new Vector2 (forceValue * 50, 50));
forceValue = forceValue * -1;

Also, remove the call to Start() from within Reset(). Save the script, save the scene, then playtest the game. That’s better!

Recap

A lot of what we did was familiar, such as populating fields that were exposed in the Inspector via [SerializeField]. We added audio clips to GameManagerScript this way. We then used references to those audio clips to play the sounds we wanted at specific times during the game. OK, the sounds aren’t exactly thrilling, but hey, you’ve learned how to add sounds to a Unity game, right?

We also touched upon Unity’s ways of finding components and GameObjects from a script via the GameObject.Find and GetComponent methods. We learned that these shouldn’t be used in any code that frequently repeats.

We did a bit more work with Unity 4.6’s new GUI system to create our end game screen, and learned a few more scripting techniques in the process. We went and added a few improvements to our scripts. The game still needs a little more…juice.

More about that in Part 10.