THE ROAD RUNNER TUTORIAL 11: ADDING SOUND EFFECTS(SFX) TO OUR GAME

Check out the gameplay of the finished game below:



Sounds play a big part in making or breaking a game. Good SFX makes the gameplay much more vibrant, and thereby hooking the player up.
This is precisely what we will be learning in this post, adding the Sound Effects.
If I have to be honest, I would say that this part of developing the game took more time than anything else, which, of course, can be due to the lack of creativity, or may be something else. But, yes! I managed to put up something which works.

So follow along to add SFX to your game.

Before we start with the steps to add the sounds, download the sounds that we will be using from this LINK.

Step 1:
Create a folder named Sounds in your Project and add the mp3 files found in the rar file you just downloaded.

Step 2:
Open the MainMenuScene. Add an Audio Source to the Main Camera by navigating to Component->Audio->Audio Source. (Note: Make sure you have selected Main Camera in the Inspector)
- Populate the Audio Clip field with bgmenu.mp3 file.
- Check the boxes, Play On Awake and Loop.


menu background music

Save the scene and take a deep breath. That is pretty much it for this scene.

Step 3:
Open the main scene, where in we have the main game built. Add an Audio Source to the 3rd Person Controller, populate the Audio Clip field with the run.mp3 file. Also make sure you have checked the Play On Awake and Loop boxes.

Step 4:
Create an empty gameobject(by now, you know how to create one, I hope.), name it as CountdownSound, add an Audio Source to this. select 321go.mp3 in the Audio clip field.
This time make sure you don't have any of the boxes checked. Also, change the pitch to 0.8 so as to sync it with the countdown.

Countdown Sound

Step 5:
Duplicate the CountdownSound gameobject by right clicking it and selecting Duplicate or simply press ctrl+d in Windows/ cmd+d in Mac. Rename the duplicated gameobject as JumpSound. Add the jump.mp3 to the Audio Clip field.
Again, none of the checkboxes should be checked. The pitch should be 1.

Step 6:
Duplicate the CountdownSound gameobject twice, name the two new gameobjects as PowerupCollectSound and SnagCollectSound. Populate the Audio Clip field of these two gameobjects with yes.mp3 and no.mp3 files respectively, from the Sounds folder.
Make sure nothing is checked and keep the default pitch, which is 1.

Step 7:
Open the CountdownScript and add the two variables

public AudioSource countdownSound; //reference to the audio source
public bool isCountDown = false; //countdown flag

In the start function, disable the audio source added to the 3rd Person Controller by adding the below line

character.GetComponent<AudioSource>().enabled = false;

To sync the countdown sound with the countdown, we need to delay the playing of the 321go.mp3 by some value, I found that 0.4sec is close to being good. This can be done by adding the following line to the beginnin of IEnumerator CountdownFunction() function

countdownSound.PlayDelayed(.4f);

We need to stop playing this sound once the count is down, we stop this sound in the else condition of the for loop in the CountdownFunction. Also set the isCountDown to true to indicate that the coundown is up
The else condition will look like

else{
 guiTextCountdown.text = "GO!";
 yield return new WaitForSeconds(1);
 //stop the sound
 countdownSound.Stop();
 isCountDown = true;  //set the flag to true
}
Finally we enable the Audio Source of the character by adding
character.GetComponent<AudioSource>().enabled = true;

The entire CountdownScript will look like
using UnityEngine;
using System.Collections;

public class CountdownScript : MonoBehaviour {

 public GameObject character;
 public GameObject wall1;
 public GameObject wall2;
 public GameObject ground;
 public AudioSource countdownSound; //reference to the audio source
 public bool isCountDown = false; //countdown flag
 public int countMax;  //max countdown number
 private int countDown;  //current countdown number
 public GUIText guiTextCountdown;//GUIText reference

 // Use this for initialization
 void Start () {
  MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents<MonoBehaviour>();   //get all the script components attached
  //loop through all the scripts and disable them
  foreach(MonoBehaviour script in scriptComponentsGameControl) {
   script.enabled = false;
  }
  //disable all the scripts attached to the walls, ground. Also disable the animation of character
  wall1.GetComponent<GroundControl>().enabled = false;
  wall2.GetComponent<GroundControl>().enabled = false;
  ground.GetComponent<GroundControlGroundControl>().enabled = false;
  character.GetComponent<Animation>().enabled = false;
  character.GetComponent<AudioSource>().enabled = false;
  //Call the CountdownFunction
  StartCoroutine(CountdownFunction());
 }

 IEnumerator CountdownFunction() {
  countdownSound.PlayDelayed(.4f);
  //start the countdown
  for(countDown = countMax; countDown>-1;countDown--){
   if(countDown!=0){
    //display the number to the screen via the GUIText
    guiTextCountdown.text = countDown.ToString();
    //add a one second delay
    yield return new WaitForSeconds(1);    
   }
   else{
    guiTextCountdown.text = "GO!";
    yield return new WaitForSeconds(1);
    //stop the sound
    countdownSound.Stop();
    isCountDown = true;  //set the flag to true
   }
  }
  //enable all the scripts and animation once the count is down
  MonoBehaviour[] scriptComponentsGameControl = gameObject.GetComponents<MonoBehaviour>();   
  foreach(MonoBehaviour script in scriptComponentsGameControl) {
   script.enabled = true;
  }

  wall1.GetComponent<GroundControl>().enabled = true;
  wall2.GetComponent<GroundControl>().enabled = true;
  ground.GetComponent<GroundControl>().enabled = true;
  character.GetComponent<Animation>().enabled = true;
  character.GetComponent<AudioSource>().enabled = true;
  //disable the GUIText once the countdown is done with
  guiTextCountdown.enabled = false;
 }
}

To Complete this step, add the CountdownSound gameobject to it's respective field in the Countdown Script component of the GameController gameobject.


Step 8:
Open the PlayerControl script and add the references of the AudioSources as mentioned below, also add the CountdownScript and PauseMenuScript instances

public CountdownScript count;  //CountdownScript instance
 public PauseMenuScript pause;  //PauseMenuScript instance
 //audio source reference variables
 public AudioSource powerupCollectSound;
 public AudioSource jumpSound;
 public AudioSource snagCollectSound;

The if condition inside the Update function will have an added filter to check if the count is down. Also we check if the game is paused and disable the run sound if so.
The complete if condition is as below

//check if grounded and countdown is done with
  if (controller.isGrounded && count.isCountDown  ) {
    // We are grounded, so recalculate
    // move direction directly from axes
    animation.Play("run");
    //check if game is paused
    if(pause.paused==false)
     gameObject.GetComponent<AudioSource>().enabled = true;
    else
     gameObject.GetComponent<AudioSource>().enabled = false;
    moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, 0);
    moveDirection = transform.TransformDirection(moveDirection);
    moveDirection *= speed;

    jumpSound.Stop();
    if (Input.GetButton ("Jump")) {
     animation.Stop("run");
     animation.Play("jump_pose");
     
     jumpSound.Play();
     gameObject.GetComponent<AudioSource>().enabled = false;
     moveDirection.y = jumpSpeed;
    }

   }
We also check if the game is over and disable the run sound if so by adding another if condition inside the Update function

if(control.isGameOver){ 
 gameObject.GetComponent<AudioSource>().enabled = false;
}

Next, we play the powerupCollected sound and snagCollectedSound once the player collects the respective objects.

void OnTriggerEnter(Collider other){
  if(other.gameObject.name == "Powerup(Clone)")
  {
   powerupCollectSound.Play();  //play powerup collected sound
   control.PowerupCollected();
  }
  else if(other.gameObject.name == "Obstacle(Clone)")
  {
   snagCollectSound.Play();  //play snag collected sound
   control.AlcoholCollected(); 
  }
  Destroy(other.gameObject);
  
 }

The complete PlayerControl script is as below:

using UnityEngine;
using System.Collections;

public class PlayerControl : MonoBehaviour {
 // Use this for initialization
 
 public GameControlScript control;
 CharacterController controller;
 public float speed = 6.0f;
 public float jumpSpeed = 8.0f;
 public float gravity = 20.0f;
 private Vector3 moveDirection = Vector3.zero;

 public CountdownScript count;  //CountdownScript instance
 public PauseMenuScript pause;  //PauseMenuScript instance
 //audio source reference variables
 public AudioSource powerupCollectSound;
 public AudioSource jumpSound;
 public AudioSource snagCollectSound;


 //start 
 void Start () {
  //Debug.Log("Inside player control script start");
  controller = GetComponent<CharacterController>();
 }
 
 // Update is called once per frame
 void  Update (){
  //check if grounded and countdown is done with
  if (controller.isGrounded && count.isCountDown  ) {
    // We are grounded, so recalculate
    // move direction directly from axes
    animation.Play("run");
    //check if game is paused
    if(pause.paused==false)
     gameObject.GetComponent<AudioSource>().enabled = true;
    else
     gameObject.GetComponent<AudioSource>().enabled = false;
    moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, 0);
    moveDirection = transform.TransformDirection(moveDirection);
    moveDirection *= speed;

    jumpSound.Stop();
    if (Input.GetButton ("Jump")) {
     animation.Stop("run");
     animation.Play("jump_pose");
     
     jumpSound.Play();
     gameObject.GetComponent<AudioSource>().enabled = false;
     moveDirection.y = jumpSpeed;
    }

   }
  //disable run sound if game is over
  if(control.isGameOver){ 
   gameObject.GetComponent<AudioSource>().enabled = false;
  }
  // Apply gravity
  moveDirection.y -= gravity * Time.deltaTime;
  
  // Move the controller
  controller.Move(moveDirection * Time.deltaTime);
 }
 
 void OnTriggerEnter(Collider other){
  if(other.gameObject.name == "Powerup(Clone)")
  {
   powerupCollectSound.Play();  //play powerup collected sound
   control.PowerupCollected();
  }
  else if(other.gameObject.name == "Obstacle(Clone)")
  {
   snagCollectSound.Play();  //play snag collected sound
   control.AlcoholCollected(); 
  }
  Destroy(other.gameObject); 
 } 
}

Finally, we add the sound source objects to their respective fields in the Player Control script component of the 3rd Person Controller. Drag and drop the PowerupCollectedSound, SnagCollectedSound and the JumpSound gameobjects to their respective fields.
Also drag and drop the GameController gameobject to both the Count and Pause fields of the PlayerControl component of the 3rd Person Controller
Refer the image below


Now, you are all set to play this game of ours. But before that go to File->Build Settings and add both the scenes, if you have not already added them, by clicking on Add Current. (Note: to sync the scenes inter connectivity, you need to add the main scene first and then the MainMenuScene i.e. the index of main should be 0. This is to be done as we have given the index of the scene to be loaded for Main Menu in the menu's as 1)


Finally, this game of ours seems completely connected and playable with cool sound effects.

Download the completed version of this game from the Resources page.

The Road Runner Tutorial 1: Setting Up The World
The Road Runner Tutorial 2: Setting Up The World Continued
The Road Runner Tutorial 3: Adding A Character To Our Game
The Road Runner Tutorial 4: Set The Ground Moving
The Road Runner Tutorial 5: Adding Snags and Powerups to Our Game
The Road Runner Tutorial 6: Collecting The Snags and Powerups
The Road Runner Tutorial 7: Adding Gameplay Logic
The Road Runner Tutorial 8: Creating a Custom GUI Skin
The Road Runner Tutorial 9: Creating a Pause Menu
The Road Runner Tutorial 10: Adding Countdown and Main Menu
The Road Runner Tutorial 12: Porting The Game To Android
Share on Google+

About Sujit Horakeri

Sujit Horakeri is a game freak just like any other next door guy you would come across. He is a Web Developer by Profession, Game Developer by Choice.
Connect with him on:
    Blogger
    Facebook

12 comments:

  1. extraordinary, brilliant, massive, Owsum, great tutorials ..what a lovely guy sujit u are...Simply Amazing...

    ReplyDelete
  2. Great Tutorial, but i have some problem with my Character:

    he moves from the place when i play with him, the camera change rotation too, when i walk to the righr or left he go back and fall from the platform

    ReplyDelete
  3. I created this game using this tutorial 3 times but i am facing the same error after adding sound effects and i am using unity 4.5

    MissingComponentException: There is no 'AudioSource' attached to the "3rd Person Controller" game object, but a script is trying to access it.
    You probably need to add a AudioSource to the game object "3rd Person Controller". Or your script needs to check if the component is attached before using it.
    CountdownScript.Start () (at Assets/Scripts/CountdownScript.cs:18)

    ReplyDelete
    Replies
    1. will you get answer for this missing component expception

      Delete
  4. Link to download sound pack is not working ...plz fix it... THANKS...

    ReplyDelete
    Replies
    1. Resource Link is also not workind...when i click on Android ...it show a DropBox error 509

      Delete
  5. This comment has been removed by the author.

    ReplyDelete
  6. I am having trouble with this page of the tutorial, I have followed everything correctly but the fields of the scripts for Countdown and PlayerControl are not appearing. I am also getting the following error message with the countdown script

    Assets/Scripts/CountdownScript.cs(26,37): error CS0246: The type or namespace name `GroundControlGroundControl' could not be found. Are you missing a using directive or an assembly reference?

    I have double checked the scripts to make sure the variables are there to add the sound etc to their respective fields but they do not show.

    ReplyDelete
  7. i understand a to z nothing but only 1 thing oh ya :0 that how to kick on my own ass and jump toward the fast car from the road to make sucide attempt.

    ReplyDelete
  8. I got this error
    MissingComponentException: There is no 'AudioSource' attached to the "3rd Person Controller" game object, but a script is trying to access it.

    ReplyDelete