Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Game Development How to Make a Video Game Game Audio Additional Audio Scripting

Joseph Rimar
Joseph Rimar
17,101 Points

Player Footsteps not always playing and when they do the timing is off.

I've have almost the same problem as another user...when I play the game and open the inspector on playerfootsteps i can see the script box become checked every time I hit an arrow key and move however, I only get sound some of the time. I've checked my scripts multiple times and everything seems to be in order. I've also looked over all my inspector elements to make sure I don't have any errors but alas I cannot find anything wrong. Restarting Unity several times has not helped either. Maybe a bug in Unity on Mac OSX???

PlayerMovement Script

using UnityEngine;
using System.Collections;

public class PlayerMovement : MonoBehaviour {

    private Animator playerAnimator;
    private float moveHorizontal;
    private float moveVertical;
    private Vector3 movement;
    private float turningSpeed = 20f;
    private Rigidbody playerRigidBody;
    [SerializeField]
    private RandomSoundPlayer playerFootsteps;

    // Use this for initialization
    void Start () {
        // Gather components from the Player GameObject
        playerAnimator = GetComponent<Animator> ();
        playerRigidBody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update () {

        // Gather input from the keyboard
        moveHorizontal = Input.GetAxisRaw("Horizontal");
        moveVertical = Input.GetAxisRaw ("Vertical");

        movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
    }

    void FixedUpdate () {

        // If players movement vector does not equal zero...
        if (movement != Vector3.zero) {

            // ...then create a target rotation based on the movement vector
            Quaternion targetRotation = Quaternion.LookRotation(movement, Vector3.up);

            // ...and create another rotation that moves from the current rotation to the target rotation
            Quaternion newRotation = Quaternion.Lerp (playerRigidBody.rotation, targetRotation, turningSpeed * Time.deltaTime);

            // ...and change the players roation to the new incremental rotation
            playerRigidBody.MoveRotation (newRotation);

            // ...then play the jump animation
            playerAnimator.SetFloat ("Speed", 3f);

            //...play footstep sounds
            playerFootsteps.enabled = true;

        } else {
            // ...otherwise don't play the jump animation
            playerAnimator.SetFloat ("Speed", 0f);

            //...disable footstep sounds
            playerFootsteps.enabled = false;
        }
    }
}

RandomSound Script

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class RandomSoundPlayer : MonoBehaviour {

    private AudioSource audioSource;
    [SerializeField]
    private List<AudioClip> soundClips = new List<AudioClip> ();
    [SerializeField]
    private float soundTimerDelay = 3f;
    private float soundTimer;

    // Use this for initialization
    void Start () {
        audioSource = GetComponent<AudioSource> ();

    }

    // Update is called once per frame
    void Update () {

        // Increment a timer to count up to restarting
        soundTimer = soundTimer + Time.deltaTime;

        // If the timer reaches the delay...
        if (soundTimer >= soundTimerDelay) {

            //...reset the timer
            soundTimer = 0f;

            //...choose a random sound
            AudioClip randomSound = soundClips[Random.Range (0, soundClips.Count)];

            //...play the sound
            audioSource.PlayOneShot (randomSound);
        }

    }
}

Any help would be greatly appreciated!!!

Andrew Shiets
Andrew Shiets
3,185 Points

I noticed your forgot the -1 at the end of this line in the RandomSoundPlayer script.

// ...choose a random sound...
            AudioClip randomSound = soundClips[Random.Range (0, soundClips.Count -1)];
Joseph Rimar
Joseph Rimar
17,101 Points

Andrew, Thanks for spotting that. I changed it but unfortunately it has not fixed my problem.

Jefferson Lessa
Jefferson Lessa
5,684 Points

There is no need to add "-1" to the Range function.

When it is called with a whole number, the second parameter is exclusive, so the script won't break by Random.Range returning soundClips.Count. Adding the -1 prevents the last clip on the list to ever be fired.

Is nice to try everything to solve a bug, but remember to undo your unsucessful tries. If you don't, you may end up not knowing how your problem got fixed in the first place =P

3 Answers

Mike Atkinson
Mike Atkinson
6,882 Points

Hi Joseph, There is no problem with you program, more just a limitation. The random sound script is only enabled when the movement variable is above zero. Remember, the movement variable comes from the player input per frame. Also, the random sound player has a delay on it.

In other words, the delay for the random sound is only advanced in frames that input is being found.

While still not perfect, I adjusted the randomSoundPlayer script to reset the timer. I'll paste it here, then explain my changes.

public class RandomSoundPlayer : MonoBehaviour {

    private AudioSource audioSource;

    [SerializeField]
    private List<AudioClip> soundClips = new List<AudioClip> ();
    private float delayTimer;
    [SerializeField]
    private float timerTargetDelay = 3f;

    // Use this for initialization
    void Start () {
        delayTimer = timerTargetDelay;
        audioSource = GetComponent<AudioSource> ();
    }

    void OnEnable () {
        delayTimer = timerTargetDelay;
    }

    // Update is called once per frame
    void Update () {        
        delayTimer += Time.deltaTime;
        if (delayTimer > timerTargetDelay) {
            delayTimer = 0.0f;
            // play random sound from soundClips through audioSource component attached to GameObect
            audioSource.PlayOneShot (soundClips [Random.Range (0, soundClips.Count)]);
        }
    }
}

First, notice that the condition in the void Update () method is set to if (delayTimer > timerTargetDelay) so the random sound will play as soon as the delayTimer is anything above the timerTargetDelay, but not while equal.

Second, I initialised delayTimer in the void Start () method to be equal to the timerTargetDelay. This way, as soon as the timer is incremented for the first time, the conditional statement will fire.

Lastly, I added the

void OnEnable () {
        delayTimer = timerTargetDelay;
}

This will reset the timer every time the instance of the script is reenabled. This means, as soon as you press the keys to move, the random sound will fire immediately.

As a side note At first I tried to check if the script was enabled with an if statement inside void Update (), however if disabled, the class will not call Update () and therefore cannot check itself! So void OnEnable () was the answer to that.

Jefferson Lessa
Jefferson Lessa
5,684 Points

What is the value of your "Sound Timer Delay" field, on the inspector, on your Player object? The value should be like the bird's, 0.4 or something, so the footsteps will play often. If you left the values at 3, the default, the sound will look erratic, like you are describing.

That happens because the script is being enabled and disabled. When the script is disabled, the countdown stops, so the footsteps may take longer then 3 seconds to happen between each other.

Check the value, and see if that was the problem.

I'm also noticing this, with 0.4 for sound timer delay. If I move just once and then wait, the sound never plays. Only if I consistently move.