Homeplay 2
Let’s take a look at some of the games from the second homeplay
Animation Scripting
To control different aspects of the animator inside of a script, you can get a reference to the component using the GetComponent method.
In addition to the public properties on the Animator component in the Inspector, the Animator allows you to control which animations are playing, the speed of the animations, and user-defined parameters within the Animation controller.
For some tests, open a scene that has an animated object.
Changing the speed
Create a new script called AnimationController and add it to the object being animated. Rather than making the animator variable public and connecting the component to the script in the inspector, we’ll use GetComponent to automatically find and connect the animator.
Copy and paste this code into the script:
using UnityEngine;
public class AnimationController : MonoBehaviour
{
public float speed = 1f;
private Animator animator;
void Start()
{
// get the animator
animator = GetComponent<Animator>();
}
void Update()
{
animator.speed = speed;
}
}
Try playing the game. You can change the speed of the animation directly from the inspector. You could modify this script to have the speed change over time:
animator.speed = speed + Time.time;
Triggering an animation (Animator State Machine)
Rather than relying on the auto-play feature of the animator, it’s possible to create a trigger parameter that will tell the animator controller to change from one animation state to another. Let’s recreate the animation delay, but using an animation trigger.
-
Start by opening the Animator window either by double-clicking on the controller in the project tab or going to Window > Animation > Animator
- There should be a few different boxes which represent the current state of the Animator. Lines represent transitions between the states, with the arrows showing the direction of the transition. The Entry state will always transition to a “Default State” when the component becomes active. Because there is only one animation clip in the controller, that animation will always start playing immediately.
-
Create a new, empty state to use as an intermediate state. Right-click in an empty part of the state machine area. Select Create State > Empty
- A “New State” box will appear. Selecting it will bring up the state’s properties in the inspector window. You can modify the name of the state there or add an animation clip to the state on the Motion parameter.
-
Right-click on the new empty state and select “Set as Layer Default State” the transition from Empty will now go to the empty state.
-
Now create a new transition from the new state to the other animation clip in the controller. Right-click on the empty state and select “Make Transition” and then click on the other animation clip.
-
If you were to press play now, the animation would wait a moment in the empty state and then immediately transition to the next state. To turn off the automatic transition, select the Transition and in the inspector uncheck the “Has Exit Time” box.
- Now create a trigger parameter that will tell the controller when to transition from the empty state to the animation state. At the top left of the Animator window, change to the Parameters tab and click + > Trigger to create a trigger parameter. Name it “start”.
- Select the Transition again and in the inspector under Conditions, click the “+” button. This should automatically add the start trigger to the transition condition.
- If you press play and keep the Animator window open you can click on the circle next to the trigger parameter to transition from the empty state to the animation state.
- With the trigger set up, we can now modify the delay script to control the transition automatically using the SetTrigger method of the Animator class.
using System.Collections;
using UnityEngine;
public class AnimationController : MonoBehaviour
{
public float delayTime = 1f;
private Animator animator;
void Start()
{
// get the animator
animator = GetComponent<Animator>();
// use coroutine to create the delay
StartCoroutine(RunAfterDelay(delayTime));
}
IEnumerator RunAfterDelay(float delay)
{
// wait a moment
yield return new WaitForSeconds(delay);
// trigger the animation
animator.SetTrigger("start");
}
}
The function can take in the name or id of the parameter containing the parameter you would like to trigger.
Animation triggers and properties in other situations
Going from Idle to Walk and back.
For this example I’m adding the animation to the player character sprite.
- Select the player game object and open the Animation window. Click the “create” button if there aren’t any animations yet.
-
Create another clip so that there are two animations associated with this controller. You can add the keyframes for each animation later.
- Open the Animator window (Window > Animation > Animator). Make sure that the Idle animation has the transition from the “Entry” node.
- Create a transition from Idle to Walk and another transition from Walk to Idle.
-
Click the “Parameters” tab and click the ‘+’ button to add a new Bool parameter called “moving”
-
Select each transition and add a new condition in the inspector. For idle to walk, the condition is “moving: true” and walk to idle will be “moving: false”. You can also turn off any transition timing so that the animations will change immediately.
- Now open up your player movement / player controller script. You’ll need to add in a new variable for the Animator and get the Animator component in the Start method.
- Next you’ll check if the direction is zero and you’ll set the “moving” Animator Parameter using the SetBool method.
Here’s an example of a PlayerController script that sets the animation parameter inside the Update function, the script also shows another way to connect Inputs to callback methods:
using UnityEngine;
using UnityEngine.InputSystem;
public class SimplePlayerController : MonoBehaviour
{
public float speed = 1f;
Vector2 direction;
Rigidbody2D rb;
Animator anim;
void Start()
{
// shortcut for getting the current map of input actions
var map = GetComponent<PlayerInput>().currentActionMap;
// bind the movement to the "performed" -- similar to keydown
map["Move"].performed += ctx => direction = ctx.ReadValue<Vector2>();
// reset direction when button released
map["Move"].canceled += ctx => direction = Vector2.zero;
// get rigidbody
rb = GetComponent<Rigidbody2D>();
// get the animator
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
// move the player
Vector2 newPosition = rb.position + direction * Time.deltaTime * speed;
rb.MovePosition(newPosition);
}
void Update()
{
// change animation based on movement
if(direction == Vector2.zero)
{
anim.SetBool("moving", false);
} else
{
anim.SetBool("moving", true);
}
}
}
Playing animations by name
If you’re finding the state machine a bit overwhelming (I do!), you can bypass all the parameters and transitions by telling the animator play a state.
animator.Play("walk");
As long as the animation clip is attached to the animator controller (it shows up as a box in the Animator window) you can change to that animation clip.
While this is a convenient way to switch animations, you won’t reap the benefits of the transition system and you’ll have to script the logic for determining when an animation should be triggered.
Studio Time
