Animation

In this tutorial, you will learn to animate a character from the Asset Store! You will also create a patrol path for an enemy character to follow.

Open the project

Download the AnimationFun project to the desired location on you computer.

Extract the zip file, open the project, and play the game. Right now the player is using a First-Person camera. This will be fine for now.

The first step to animating, have something to animate!

Find characters

The Asset Store in Unity provides many assets you may use in your game. Characters from the Asset store may be used for the player character (PC) and for non-player characters (NPCs).



In Unity, open the Asset Store window. Search for Rigged Character. Refine your search to only free Assets.



In order to animate a character, it needs to be rigged. You can find many objects on the asset store, including many characters, but if the characters are not rigged then they can't be animated.

Click on the Renderedpeople Free Rigged Models to read about the asset. Point out anything noteworthy. Note 384.7 MB filesize. High poly. Don't want this.

Start the search over by searching for "low poly". Refine your search by selecting Humanoids, Free Assets, and Unity 2019.x.

Take a look at the Lopoly Ninja. 298.8 KB. Much better! 1621 triangles and 812 vertices. But not so great looking.

Search for "spaceman" and the select Free Assets to refine your search. Click on the "Free Animated Spaceman". Notice this is 2.5 MB and comes with 5 animations.



This asset has already been added to the project along with some other free characters from the Asset store.

Place characters

Locate the characters that were included with the project. The folders imported from the Asset Store containing the assets were renamed to be more concise and then moved into the Characters folder to keep the project files organized.

Place all characters in Scene and rename them. Line up the characters side by side. Resize the skeleton relative to the other characters.



Play the game. Notice some of the characters are already animated.



You can open the Animator Controller of a character to see the underlying animation structure. Open the Animator of the Skeleton and move it to the same panel as the Project window so you can see it while the game is playing. You can use your middle-mouse wheel to zoom in or out on the Animator window; and you can use your middle-mouse buttom to pan. After improving your view, play the game to see the animations progress within the Animator window.



Turn off animations for the SpaceMan and Skeleton by disabling their Animator components. Play again. Notice the Skeleton still changes direction.



When something odd is happening, it is often the result of some added code. Remove the PlayerController Script from the Skeleton. The Skeleton should no longer turn randomly with the script removed.



Assets from the Asset Store almost always have a demo scene included to allow you to check out the asset. Locate and open the demo scene for the SpaceMan. Be sure to save the changes to your scene when prompted.



Open the demo scene for the Elf. This scene is not so impressive. Likely, no animations were included with this asset. However, the T-pose the Elf is in indicates that it is likely rigged and ready to be animated.



It is sometimes nice to preview animations from the inspector. Look into the animation folder of the Skeleton. Select an animation and press play in the inspector for a preview.



Return to your own Scene01 scene by double clicking it from within the Assets > Scenes folder.

In the next section you will be applying the Idle and Attack animations to the Skeleton to trigger based on how close the player is to the Skeleton.

Apply an Animation



Create an AnimationController for Skeleton named "SkeletonAnimatorController".



Click on Skeleton in the Hierarchy to see the "Animator" component in the Inspector. Move the Animator Window back to the same panel as the Scene window so it is visible at the same time as the Project window.



Drag the "SkeletonAnimatorController" from the projects window to the Controller field of the Skeleton's Animator component. This will cause it to become active in the Animator window.



Right-click in the gray area of the Animator window to create an empty state. Then click on the newly created state and rename it at the top of the inspector window to "Idle".



In the Project Window, expand the "skeleton@Idle1" animation within the Assets > Characters > Skeleton > animation folder and move the Idle1 motion clip to the "Motion" field of the newly created "Idle" state.



Make sure the animator component of the skeleton is enabled, and play the game to see the Skeleton in its idle state.



Of course, usually a character needs more than just one animation.

Trigger an Animation

There are many actions that could trigger an animation, such as when a key is pressed or when the characters health reaches zero. Of course, one way to trigger an animation is using a trigger!



Setup a Sphere Collider as a trigger in front of the Skeleton. Y=3, Z=2, and Radius=6. The Collider will be used to trigger an attack when the player approaches.



Locate the SkeletonBehavior script in the Scripts folder. Double-click to open it in Visual Studio.

You may want to understand this code as you will be adding to it throughout the lesson.

The public variable player is used by this script to determine when the skeleton should enter the attack animation.

In the Start method, the script finds the animator component of the skeleton and stores it in a private variable. The animator component is then used for all the functionality for animations.

The Update method, the condition checks to see if the Skeleton is in the attack state. If the skeleton is in the attack state, it will always turn towards the player's location.

The OnTriggerEnter method checks if the object that entered the skeleton's trigger is the same as the player that was set up in the player variable. If it is, the boolean for the attack animation is set to true so the skeleton will attack. The OnTriggerExit method checks for when the player exists the trigger. When that happens, the boolean is set to false, causing the skeleton to stop attacking.


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

public class SkeletonBehavior : MonoBehaviour
{
    public GameObject player;
    private Animator animator;

    void Start () {
        animator = GetComponent<Animator>();
    }

    void Update(){
        if( animator.GetBool("Attack") ){
            transform.LookAt( player.transform ) ;
        }
    }

    void OnTriggerEnter (Collider other) {
        if(other.gameObject == player){
            animator.SetBool("Attack", true);
        }
    }

    void OnTriggerExit (Collider other) {
        if(other.gameObject == player){
            animator.SetBool("Attack", false);
        }
    }
}


Attach the script to the Skeleton. Then, set the value of the Player property by dragging the FPSController into the Player field.



Now we have a script that is attempting to communicate to the Animator Controller by setting a boolean variable named Attack to true or false.

In the Animator, click on the parameters tab to see what parameters (or variables) the Controller has. The list should be empty. Then, click on the + icon to add a Bool parameter named Attack.



With the Animator showing, play the game. Watch the value of the Attack parameter change as the player enters and exits the Skeletons Sphere Collider.



Stop the game. The information being sent from the script to the Animator can now be used to determine which animation should play. Create a new Empty State and name it Attack.



Locate the Attack1h1 motion clip in the skeleton's animation folder. Move the motion clip to the Motion field of the Attack state.

Right-click on the Idle state and select "Make Transition" to begin making a transition. To complete the transition, click on the Attack state.



Click on the transition to select it. Click the + icon to add a condition that will trigger the transition when the Attack property is true.



Create another transition from the Attack state to the Idle state so the Skeleton will be able to stop attacking. Select the transition and add a condition that will trigger the transition when the Attack property is false.

Play the game with the Animator Window showing. Notice the skeleton always finishes the entire Idle motion clip before it transitions to the Attack.



Stop the game to fix this. Select the transition from Idle to Attack. In the Inspector, uncheck the Has Exit Time checkbox.



For the transition from Attack to Idle, it makes sense to leave this checked so that the skeleton will complete his attack before returning to an idle state.

Playing the game now, the Skeleton should immediately begin attacking when the player is near. Notice however that when the Skeleton faces the player to attack, its back leg sinks into the ground. The closer the player is to the Skeleton, the more the Skeleton's back foot sinks.



This is because the LookAt method in SkeletonBehavior's Update method is causing the Skeleton to look upward at the player, who is a bit taller than the Skeleton.

Stop the game and modify the code in the condition to look at the player while maintaining the same y value for its rotation.

if( animator.GetBool("Attack") ){
  Vector3 playerPos = player.transform.position;
  Vector3 lookPos = new Vector3( playerPos.x, transform.position.y, playerPos.z ) ;
  transform.LookAt( lookPos ) ;
}


Previously, the Update method in the SkeletonBehavior just looked at the player position. Now, the player position is saved into playerPos variable.

Then, the lookPos variable is a new position which includes the player's x and z, but takes on the y position of the skeleton. This means the skeleton won't look up or down towards the player.

The last line uses the new position for the LookAt method, rather than the player's actual position.


Save the code and play the game again to ensure the Skeleton remains upright when attacking.



Idling and attacking is great. But what animation should be used when moving about the scene?

Walk this way

Time to get the Skeleton moving.



You may be tempted to immediately use the walk animation of the skeleton. However, the skeleton needs to move during this animation so it is not walking in place.

Modify the SkeletonBehavior script so it may be used on skeletons that are on patrol and those that are standing idle.

Add a public property onPatrol that will be used to determine whether or not the Skeleton should move or stand idle.

  public bool onPatrol;


Add a property to store the speed at which the Skeleton can move. The property is set to private so it cannot be modified in the editor. The value of 1.8 works work well with it's walk animation.

  private float speed = 1.8f;


In Start, add a line of code that sends the value of onPatrol set in the editor to the Animator.

  animator.SetBool("OnPatrol", onPatrol);


Add an else if statement to the Update method with the following code that moves the Skeleton forward when it is not attacking if it is on patrol.

else if( onPatrol ){
  // move forward
  transform.position += transform.forward * Time.deltaTime * speed;
}


Save the file. Play the game with the On Patrol property unchecked. The skeleton should stand idle as before until the player comes within attack range.



Stop the game, check on the On Patrol property checked, and play again. You should see the skeleton continuously move forward. The skeleton should stop moving when attacking and begin to move again when it stops attacking.



Stop the game and return to the Animator Window. Add OnPatrol as a Bool parameter to the Animator.

Play the game again with the Animator Window showing. The OnPatrol should automatically switch on when the game begins due to the code in the Start method.



The information that is now being successfully sent from the script to the Animator should be used to begin a walk motion when OnPatrol is true.

Create a new empty state and name it "Walk" and add the Walk 1 motion clip.

Make a transition from Idle to Walk that occurs when OnPatrol is true. Be sure to uncheck the Has Exit Time property so the skeleton can immediately switch from the Idle state to the Walk state.



Make another transition from Walk to Attack that occurs when the Attack property is true and uncheck the Has Exit Time so the skeleton can attack immediately without finishing the walk cycle.

Then, play the game again to see the skeleton walk



Patrol Path

Currently, when the skeleton is not attacking, it walks forward forever. The Skeleton could use a path to follow.



Add a new GameObject named SkeletonOnPatrol. Reset the position of the GameObject to the origin.



Drag the Skeleton to be a child on the SkeletonOnPatrol. Then right-click on SkeletonOnPatrol and select Create Empty to create another child. Name the empty GameObject "Path".



The Skeleton will be moving in a straight line along the path, so it is important that the y position of the Path matches the y position of the Skeleton.

Click on the Skeleton and select the y value of the Skeletons position. Use Ctrl + C to copy the value. Then click back on the Path, delete the current y value of the Path's position, and paste in the copied value using Ctrl + V.



Right-click on Path and select 3D Object > Sphere to create a sphere. Change the scale of the Sphere to 0.4 to make it smaller. Remove the collider so no objects, such as the player, will collide with it.



With the Sphere selected, press Ctrl + D to duplicate it. Move the new sphere along the X and Z axis to the next point on the path. The Y value of the each Sphere should remain 0 so they are the same height as the Path. Repeat this to add a few more points along the path.



The order of the Spheres in the Hierarchy will determine the path the Skeleton will follow. Click on the first Sphere in the Path and then use the down arrow to see the sequence of path points the Skeleton will follow.



When the Skeleton gets to the last point, it will move back to the first Sphere and start the patrol over.

Update the code to instruct the Skeleton to follow the path. First, add a public property to reference the path. The value will be set later in the editor.

  public GameObject path;


Add targets as a private property that will be used store the Spheres that make up the path.

  private Transform[] targets;


The targets property will actually store the Transforms of each of the Spheres, which is why it is declared with Transform as the data type.

The square braces [] indicates an Array. Arrays can be used to store many values instead of one. Without the [] we could only use targets to store one Sphere. With the [] we can store any number of Spheres! The first Sphere will have an index value of 0, the next Sphere will have an index value of 1, and so on.


Add two more private properties.

  private Transform target;
  private int targetIndex = 0;


The target will store the Sphere that the Skeleton is currently moving towards (i.e. targeting).

The targetIndex will store the index value (or position) of the target Sphere. The first Sphere in the path will have an index value of 0.

In Start method, add a block of code that will execute if the Skeleton is on patrol and a path has been set. If this is the case, the new properties will be initialized and the Skeleton will be rotated to look at the first Sphere.

  if( onPatrol && path != null ){
    targets = path.GetComponentsInChildren<Transform>();
    target = targets[targetIndex];
    transform.LookAt(target);
  }


This condition checks two variables before activating. It checks that the unit is set up to patrol, and that the path GameObject has been set in the inspector window for the object in the scene.

If both those conditions are met, it collects all the Transform components in objects underneath the designated path object.

It sets the first target to be the first object inside of the path, and then has the skeleton look at that location.


In the Update function, change the else block to:

  // move towards target
  else if( onPatrol ){
    if (path == null){
      // move forward
      transform.position += transform.forward * Time.deltaTime * speed;
    }
    else{
      // move towards target
      transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
    }
  }


Save the code. Select the Skeleton in Unity to see the public properties for the script. Check off the On Patrol property and Leave the Path property with no value and play the game. The Skeleton should stay in one location with either the idle or attack animation running.



Option 1 for Skeleton behavior complete!

Stop the game, check the On Patrol property, and play again. Now the Skeleton should walk straight forward, only stopping and changing direction when attacking.



Option 2 for Skeleton behavior complete!

Stop the game. With the Skeleton selected, drag the Path GameObject from the hierarchy and drop it to set the Path property. Play the game again and you should see the Skeleton walk to the location of the first sphere and then just walk in place.



Good start for option 3 of Skeleton behavior!

Stop the game and add code to the Update function to instruct the Skeleton to look at the target and switch to a new target when the current target is reached.

  else{
    // look at target
    Vector3 targetPos = target.position;
    Vector3 lookPos = new Vector3( targetPos.x, transform.position.y, targetPos.z ) ;
    transform.LookAt( lookPos ) ;
    
    // move towards target
    transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);

    if(transform.position == target.position){
      // switch target to next Sphere on path
      targetIndex++;
      if(targetIndex < targets.Length){
        target = targets[targetIndex];
        transform.LookAt(target);
      }
      else{
        targetIndex = 0;
        target = targets[targetIndex];
        transform.LookAt(target);
      }
    }
  }


There are two main parts to this code. The first part looks like the code that is in the attack condition, only instead of looking at the player the skeleton is looking at a target.

The internal if(transform.position == target.position) condition will trigger once the skeleton reaches the target it is currently moving towards.

Inside of that condition, it will add 1 to the targetIndex variable [targetIndex++. If there is an potential target at that index of the array [if(targetIndex < targets.Length)], it will set that target as the new target [target = targets[targetindex]] to look at [transform.LookAt(target)].

If there is no potential target at that index (for example, you only have 3 spheres along the path but it's looking for the 4th sphere), then it will reset the index to 0 [targetindex = 0], meaning the new target will be the first sphere in the path. Then it performs the same set action and looks at that target instead.


Play the game again and you should see the Skeleton follows the path even after attacking. Play the game long enough to ensure that the Skeleton starts the Patrol over when it reaches the last Sphere.



To make turns less abrupt, additional spheres may be added to round the corners of the path.

Once the patrol is complete, hide the Spheres that make up the path by disabling their Mesh Renderer. To do this to all the Spheres at once, click on the first Sphere and then shift click on the last Sphere. With all Spheres of the path selected, toggle off the Mesh Renderer.



Another option would be to remove the Mesh Renderer from the Spheres, but leaving it allows you to toggle them back on to easily see their location when additional edits to the path are needed.

Now this script may be used to instruct Skeletons how to behave in one of three possible ways (idle, patrol with no path, or patrol with a path).