Implementing Footsteps with Wwise in Unity

When implementing footsteps in Unity, there are different techniques we can use according to game genre and style (2D, FPS, etc.) Depending on whether the game uses animations to “move” the player in the world, or if the game moves the player through physics alone, we can choose one or the other method.

In this tutorial I’ll show you how to implement footsteps with and without using Animation Events.

Footsteps setup in the Wwise Authoring Tool

Let’s create a Switch Container with Random Containers representing the different terrain surface types. Insert the footsteps audio files into the corresponding Random Containers:

Switch Container Footsteps example in Wwise
Switch Container Footsteps example in Wwise

Switch to Game Syncs Tab and add a Switch Group to your desired Work Unity. For each Switch, add a child Switch to the Switch Group:

Switch Group creation in Wwise
Switch Group creation in Wwise

Go back to the Switch Container and select the Switch Group you created in the General Settings in the Group field:

Switch Group selection in Wwise
Switch Group selection in Wwise

Make sure to also define a Default Switch to avoid any errors in the game engine.

Now you can assign the Sound Objects inside your Switch Container to the Switches in the Switch Group by dragging and dropping the objects from the Contents Editor to the Switches (Assigned Objects) on the right:

Assign Sound Objects to Switches in Wwise
Assign Sound Objects to Switches in Wwise

Finally create a new Event and assign the Switch Container created in the first place as a target of the play action:

Wwise Event with Switch Container
Wwise Event with Switch Container

As a last step add the Event to your desired SoundBank (don’t forget to generate the banks!).

Implementing Footsteps with Animation Events in Unity

If our player has animation in form of animation clips, then we can use animation events to implement sounds. These are quite useful when it comes to syncing audio to animations.

How do Animation Events work?

Animation events allow us to call any method on a specific keyframe. The script with the method must be located in the same GameObject that contains the Animator component.

Footsteps setup in Unity

In Unity we have to define additional layers and assign them to our ground GameObjects. We go to Edit -> Project Settings -> Tags & Layers and create new layers:

Unity Layers
Unity Layers

Water is already a Builtin layer. We simply use this layer for our purposes. Then we go through our ground GameObjects and assign the corresponding layer in the upper right corner of the inspector:

Unity Layer selection
Unity Layer selection

C# code for playing footsteps sounds with Wwise in Unity

After setting up the Unity layers we select the GameObject in which the Animator component responsible for the player animations is located. There we create a script for the footsteps sounds. We first declare an enumerator for the different ground types and of course also Wwise Event type and an array of Wwise Switches:

private enum CURRENT_TERRAIN { GRASS, GRAVEL, WOOD_FLOOR, WATER };

[SerializeField]
private CURRENT_TERRAIN currentTerrain;

[SerializeField]
private AK.Wwise.Event footstepsEvent;

[SerializeField]
private AK.Wwise.Switch[] terrainSwitch;

We then create the CheckTerrain method, which will help us to identify he correct ground type the player is currently walking on:

 private void CheckTerrain()
    {
        RaycastHit[] hit;

        hit = Physics.RaycastAll(transform.position, Vector3.down, 10.0f);

        foreach (RaycastHit rayhit in hit)
        {
            if (rayhit.transform.gameObject.layer == LayerMask.NameToLayer("Gravel"))
            {
                currentTerrain = CURRENT_TERRAIN.GRAVEL;
            }
            else if (rayhit.transform.gameObject.layer == LayerMask.NameToLayer("Wood"))
            {
                currentTerrain = CURRENT_TERRAIN.WOOD_FLOOR;
            }
            else if (rayhit.transform.gameObject.layer == LayerMask.NameToLayer("Grass"))
            {
                currentTerrain = CURRENT_TERRAIN.GRASS;
            }
            else if (rayhit.transform.gameObject.layer == LayerMask.NameToLayer("Water"))
            {
                currentTerrain = CURRENT_TERRAIN.WATER;
            }
        }
    }

Basically we send a ray from the player position to Vector3.down with a distance of 10 game units. In the if statements we check if the ray hits a GameObject with the respective layer. If so, we change currentTerrain. We put this method into Unity’s Update() method:

  private void Update() 
    {
        CheckTerrain();
    }

Now we’ll take care of playing the footstep sounds. We create a very simple PlayFootsteps method:

  private void PlayFootstep(int terrain)
    {
       terrainSwitch[terrain].SetValue(this.gameObject);
       AkSoundEngine.PostEvent(footstepsEvent.Id, this.gameObject);
    }

The method takes an int argument that is used to set the terrainSwitch game sync. We specify this variable in another method:

public void SelectAndPlayFootstep()
    {     
        switch (currentTerrain)
        {
            case CURRENT_TERRAIN.GRAVEL:
                PlayFootstep(0);
                break;

            case CURRENT_TERRAIN.GRASS:
                PlayFootstep(1);
                break;

            case CURRENT_TERRAIN.WOOD_FLOOR:
                PlayFootstep(2);
                break;

            case CURRENT_TERRAIN.WATER:
                PlayFootstep(3);
                break;

            default:
                PlayFootstep(0);
                break;
        }
    }

With this switch case we finally play a footstep sound. But how do we know that the int values correspond to certain ground types? When we attach the footsteps script to our player we’ll be able to choose the footsteps Event and the correct Switch for each Switch array value:

Footsteps component in Unity (Wwise)
Footsteps component in Unity (Wwise)

Add the footsteps Event to animations using Animation Events

Now open the Animation window, click the player GameObject (or a Child GameObject that contains the Animator component), and then select one of the walk or run animations from the Animation Clip drop-down list.

Unity Animation Clip
Unity Animation Clip

We right click below the timeline and above the keyframes on the free dark grey space. Select the Create Animation Event option. As a result, a small button/arrow (the Animation Event) should have been placed at the desired position/keyframe. In the inspector we now see that we can choose between different methods from a drop-down list:

Animation Event Drop-Down list in Unity
Animation Event Drop-Down list in Unity

There we select the SelectAndPlayFootstep method. It is best to always select the keyframes where the player places the foot on the floor:

Animation Events inside of an Animation Clip in Unity
Animation Events inside of an Animation Clip in Unity

In some situations where this may not be quite clear, it is also sufficient if the two animation events are at the same distance from each other. Repeat this process for more animation clips. If you’ve done everything right, you should be able to hear your footsteps in Play Mode.

Implement footsteps without animations in Unity

We can also implement footsteps without animation clips for movements. That is useful for first person games for example. In theory, we create a timer that plays a footstep sound when the player moves at a specific time we choose.

In practice, we declare a Rigidbody, create a float variable for the timer and a float variable for the repetition rate of the footsteps:

private Rigidbody rb;

float timer = 0.0f;

[SerializeField]
float footstepSpeed = 0.3f;

In Unity’s Awake() method, we access the Rigidbody of the GameObject (make sure you are using one):

private void Awake()
{
        rb = GetComponent<Rigidbody>();
}

We then use the Update() method to check whether the player is moving and standing on the floor. We add the timer with Time.deltaTime. At the same time we check if the timer has reached our fixed footstepSpeed variable, play a footstep sound and reset the timer:

private void Update()
    {
        CheckTerrain();

        if (rb.velocity.magnitude > 1f && Mathf.Abs(rb.velocity.y) < 0.1f)
        {
            if (timer > footstepSpeed)
            {
                SelectAndPlayFootstep();
                timer = 0.0f;
            }

            timer += Time.deltaTime;
        }
    }

If we want to play the footsteps faster, we can change the footstepSpeed variable and make it smaller. rb.velocity.magnitude checks if the player is moving, rb.velocity.y if the player is in air. You would want to tweak this settings depending on how your player moves. If you are using a common Player Controller, you could also get access to properties like isWalking or isGrounded. Check with your developer about how the game is handling physics first.

↑ To the Top