Animation scripting
Drive an entity's animator from C#: set parameters, switch states directly, and react when a state changes.
Getting the Animator
using JoystickEngine;
public class Player : GameEntity
{
private Animator? m_Animator;
protected override void OnCreate()
{
m_Animator = GetComponent<Animator>();
}
}The entity needs an Animator component with a controller assigned. GetComponent<Animator>() returns null if it doesn't have one.
Setting parameters
Parameters are the inputs your controller's transitions test against — see Animator controllers for how they're declared.
m_Animator?.SetFloat("Speed", velocity.Length());
m_Animator?.SetBool("Grounded", isOnGround);
m_Animator?.SetInt("ComboStep", combo);
m_Animator?.SetTrigger("Attack");
m_Animator?.ResetTrigger("Attack");| Method | Use for |
|---|---|
SetFloat(name, value) | Continuous values — speed, health fraction |
SetInt(name, value) | Counters and discrete modes |
SetBool(name, value) | On/off conditions |
SetTrigger(name) | One-shot events; consumed automatically once a transition takes it |
ResetTrigger(name) | Cancels a pending trigger before it's consumed |
Matching getters exist: GetFloat(name), GetInt(name), GetBool(name).
Reading state
if (m_Animator?.CurrentState == "Attack" && m_Animator.NormalizedTime > 0.9f)
canQueueNextAttack = true;| Member | Type | Meaning |
|---|---|---|
CurrentState | string | Name of the state playing now |
NormalizedTime | float | Progress through the current clip, 0 to 1 |
IsTransitioning | bool | Whether a transition is in progress |
IsPlaying | bool | Whether the animator is running (not paused) |
Speed | float | Playback multiplier; read and write |
Controlling playback directly
m_Animator?.Play("Idle"); // switch immediately, restart the clip
m_Animator?.CrossFade("Run", 0.1f); // blend into this state over 0.1s
m_Animator?.Pause();
m_Animator?.Resume();| Method | Meaning |
|---|---|
Play(state, normalizedTime = 0) | Switch to a state immediately, optionally starting partway through |
CrossFade(state, duration) | Blend into a state over duration seconds |
Pause() / Resume() | Freeze and unfreeze the animator |
These are the same transition mechanics a .janimator file's own transitions use — property values blend, sprite frames snap halfway through. Prefer parameters and transitions authored on the controller for anything condition-driven; reach for Play/CrossFade when your script needs to force a specific state directly.
Reacting to state changes
Override these on your GameEntity subclass — not events on the Animator component itself, since a fresh Animator object is handed back every time you call GetComponent<Animator>(), and only overrides on your own persistent script instance can reliably hear about state changes:
public class Player : GameEntity
{
protected override void OnAnimatorStateEntered(string stateName)
{
if (stateName == "Attack")
m_HitboxOpen = true;
}
protected override void OnAnimatorStateExited(string stateName)
{
if (stateName == "Attack")
m_HitboxOpen = false;
}
}Both fire once per transition, Exited immediately before Entered for the same switch — including transitions taken from "Any". These fire for any Animator component on the entity; if you have more than one, check stateName against the states you expect from each.
Layering motion on top of a pose
public class Player : GameEntity
{
protected override void OnAnimatorPose()
{
var head = FindChild("Head")!;
head.Translation += new Vector3(0.0f, m_RecoilOffset, 0.0f);
}
}OnAnimatorPose fires every frame, right after the animator writes that frame's sampled pose — the hook for procedural motion (recoil, look-at, breathing) that should sit on top of a clip without next frame's sample overwriting it.
Animation events
Mark a method [AnimationEvent] to make it callable by name from a clip's event track:
public class Player : GameEntity
{
private AudioSourceComponent? m_Footstep;
private bool m_HitboxOpen;
protected override void OnCreate()
{
m_Footstep = GetComponent<AudioSourceComponent>();
}
[AnimationEvent]
void OnFootstep() => m_Footstep?.Play();
[AnimationEvent]
void OpenHitbox() => m_HitboxOpen = true;
[AnimationEvent]
void CloseHitbox() => m_HitboxOpen = false;
}Supported signatures: no parameters, or a single string, float, or int. The event key in the .janim file supplies whichever value matches — see Asset files for how event keys are authored. A misspelled or missing method name is reported once in the Log panel and the event is skipped; nothing throws.
Animation.Sample
Animation.Sample(entity, "Animations/Idle.janim", 0.25f);Intended for posing an entity to a specific point of a clip with no Animator component involved — thumbnails, cutscene setup, editor tooling.
Not implemented yet
This call is a placeholder in the current build: it logs that it was called but doesn't actually pose the entity. Use an Animator component and Play(state, normalizedTime) for anything that needs to work today.
See also
Two other API Reference topics come up often alongside animation scripting:
- Physics2D — a ground check (
Physics2D.Raycast) is the usual way to drive theGroundedparameter behind a jump/land transition. - Session — carries a value (which outfit is equipped, a combo counter) across a scene change, so an Animator picking a state based on that value stays correct after
Scenes.Load.