Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
June 25, 2019
arrowPress Releases







If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

Arrival in Hell: Dev blog #3: Animating movement

by Matthew Shaile on 11/24/15 05:56:00 pm   Featured Blogs

3 comments Share on Twitter    RSS

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

If you read the first dev blog post I wrote for Arrival in Hell, you’ll know how the navigation system was built. It works really well thanks to Unity’s excellent built-in pathfinding, however the player just floats around and doesn’t actually animate. It’s a little bit creepy actually.

No animation during movement

No animation during movement

The first step in fixing this is to apply an animation to the skeleton of the player model. For this we used a few motion capture (mocap) animation assets from the Unity asset store. There are many free ones available, I recommend checking them out.

With our mocap animation selected, I created a Mecanim state machine and made two states: ‘Idle’ and ‘Walk’. I added a ‘speed’ parameter which, if above 0, will transition us to the Walk state, and if it drops below 0.1, will return us back to the ‘Idle’ state.

A simple Mecanim state machine to control movement animation

A simple Mecanim state machine to control movement animation

Next job was to hook that ‘speed’ parameter up to the player navigation script. The code does the following:

  1. When the user clicks to move, a ‘navigating’ flag is set to true
  2. If ‘navigating’ is true, and the path calculation isn’t pending:
  3. Get the current speed of the NavMeshAgent and the distance from it’s destination
  4. Set the ‘speed’ parameter in the Animator to this speed
  5. Check if the remaining distance is insignificant (less than 0.25), if so, set ‘speed’ to 0 and set ‘navigating’ to false

Here is an example of how the code might look (this isn’t exactly what’s in the game, but it’s close enough)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (navigating && !agent.pathPending)
 {
     float remainingDistance = agent.remainingDistance;
     float animSpeed = agent.velocity.magnitude / agent.speed;
  
     animator.SetFloat("speed", animSpeed);
  
     if (remainingDistance <= 0.25f)
     {
         animator.SetFloat("speed", 0);
  
         navigating = false;
     }
 }

This works relatively well, however because the NavMeshAgent is moving the entire model at a fixed speed, the walking animation looks a bit odd. Instead of taking steps, the player appears to be sliding or, as I like to call it, moonwalking.

30% speed, 2D view of player moonwalking

30% speed, 2D view of player ‘moonwalking’

In order to fix this, we need to turn off the NavMeshAgent’s ability to move the player model, and instead have the animation itself update the model’s position. This can be achieved by checking the ‘Apply root motion’ box in the Animator, however this in turn would create two more issues. Firstly the idle state would update our players position (which could be dangerous and lead to glitches), and secondly when the player is rotating he’ll also be moving forward, so his turning circle will suffer.

The players turning circle is very wide, which is not the effect I want

The player’s turning circle is very wide, which is not the effect I want

In order to achieve the look I was aiming for, I applied the following changes to the above code:

  1. Store the current rotation every frame
  2. Compare the current rotation to the last rotation
  3. Set applyRootMotion on the Animator to true if the rotation hasn’t changed (we want to move forward), and false if it has (we’re turning, so we don’t want to move forward)
  4. Set updatePosition on NavMeshAgent to be the opposite of applyRootMotion, since we want either the Animator OR the NavMeshAgent to be responsible for movement, but never both
  5. Reset the values when the destination is reached

Here is the modified code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (navigating && !agent.pathPending)
        {
            float remainingDistance = agent.remainingDistance;
            float animSpeed = agent.velocity.magnitude / agent.speed;
  
            animator.SetFloat("speed", animSpeed);
  
            animator.applyRootMotion = (Quaternion.Angle(transform.rotation, lastRotation) <= 1.0f);
            agent.updatePosition = !animator.applyRootMotion;
  
            lastRotation = transform.rotation;
  
            if (remainingDistance <= 0.25f)
            {
                animator.applyRootMotion = false;
                agent.updatePosition = true;
  
                animator.SetFloat("speed", 0);
  
                navigating = false;
            }
        }
The turning circle has been eliminated and the player turns on the spot

The turning circle has been eliminated and the player turns on the spot

Movement is now synced to the animation

Movement is now synced to the animation

This was one of the hardest things to tweak and get exactly as I wanted it, but I’m quite happy with the result now. The final little cherry on top to complete player movement is syncing footstep sounds with the animation. To achieve this I used one of my favourite features of Unity animation: AnimationEvents. In the Animation window you can click on any frame of an animation and add a call to a function. Although this is limited to functions with a maximum of one parameter, it’s still extremely useful when trying to get animation to sync up with something. I added events to the ‘Walk’ animation which calls a function called ‘Footstep’; this function simply plays a footstep sound attached to the player GameObject.

Animation events placed on frames where the foot makes contact with the ground

Animation events placed on frames where the foot makes contact with the ground

The Footstep function is called on these frames

The Footstep function is called on these frames

At this point there was nothing holding Alex back from building the rest of the prison environment and exploring it, but in terms of game-play all we had was a player walking around. My next job would be to create a system for making interactive objects which the player can look at, interact with and pick up. That’s what I’ll be writing about next week. The example project I used for this article can be foundhere. See you next time!


Related Jobs

Electronic Arts
Electronic Arts — Madrid, Spain
[06.25.19]

EA Sports Madrid - UI Software Engineer
New World Interactive
New World Interactive — Calgary, Alberta, Canada
[06.25.19]

Full Stack Game Programmer
Disbelief
Disbelief — Cambridge, Massachusetts, United States
[06.24.19]

Senior Programmer, Cambridge, MA
Legends of Learning
Legends of Learning — Washington, DC, District of Columbia, United States
[06.21.19]

Senior Unity Engineer - $140k - Remote OK





Loading Comments

loader image