Created
March 2, 2016 21:16
-
-
Save xanathar/d5dd1a78c33fa5ccab0d to your computer and use it in GitHub Desktop.
Animator state machine for simple, stateful, immediate mode 2D animations in Unity3D
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public struct StateAnimatorData<T> | |
{ | |
public StateAnimator<T> Animator { get; internal set; } | |
public StateAnimatorHandler<T> AnimatorState { get; internal set; } | |
public T State { get; internal set; } | |
public float StateTime { get; internal set; } | |
public float AbsoluteTime { get; internal set; } | |
public float StateProgress { get; internal set; } | |
} | |
public class StateAnimatorHandler<T> | |
{ | |
private List<Action<StateAnimatorData<T>>> m_CallbackList = new List<Action<StateAnimatorData<T>>>(); | |
internal StateAnimatorHandler (T state) | |
{ | |
State = state; | |
} | |
public T State { get; private set; } | |
public float? Duration { get; private set; } | |
public T ExpireState { get; private set; } | |
public bool HasExpireState { get; private set; } | |
public StateAnimatorHandler<T> Calls(Action<StateAnimatorData<T>> callback) | |
{ | |
m_CallbackList.Add(callback); | |
return this; | |
} | |
public StateAnimatorHandler<T> ExpireAfter(float duration) | |
{ | |
Duration = duration; | |
return this; | |
} | |
public StateAnimatorHandler<T> ExpireTo(T state) | |
{ | |
ExpireState = state; | |
HasExpireState = true; | |
return this; | |
} | |
public void Trigger(StateAnimatorData<T> data) | |
{ | |
foreach(var callback in m_CallbackList) | |
callback(data); | |
} | |
} | |
public class StateAnimator<T> | |
{ | |
Dictionary<T, StateAnimatorHandler<T>> m_StateHandlers = new Dictionary<T, StateAnimatorHandler<T>>(); | |
T m_CurrentState = default(T); | |
StateAnimatorHandler<T> m_CurrentHandler; | |
float m_TimeBase = -1f; | |
float m_StateTime = -1f; | |
public StateAnimatorHandler<T> Add(T state) | |
{ | |
var animstate = new StateAnimatorHandler<T>(state); | |
m_StateHandlers.Add(state, animstate); | |
return animstate; | |
} | |
public void Process() | |
{ | |
float totalTime = Time.realtimeSinceStartup; | |
float stateTime = (totalTime - m_StateTime); | |
float stateProgress = 0f; | |
if (m_CurrentHandler.Duration.HasValue) | |
{ | |
stateProgress = Mathf.Clamp(stateTime / m_CurrentHandler.Duration.Value, 0f, 1f); | |
} | |
var data = new StateAnimatorData<T>() | |
{ | |
Animator = this, | |
AnimatorState = m_CurrentHandler, | |
State = m_CurrentState, | |
StateTime = stateTime, | |
AbsoluteTime = totalTime, | |
StateProgress = stateProgress | |
}; | |
m_CurrentHandler.Trigger(data); | |
if (stateProgress >= 1f && m_CurrentHandler.HasExpireState) | |
{ | |
CurrentState = m_CurrentHandler.ExpireState; | |
} | |
} | |
public T CurrentState | |
{ | |
get { return m_CurrentState; } | |
set | |
{ | |
Debug.LogFormat("Changing state from {0} to {1}", m_CurrentState, value); | |
if (m_TimeBase < 0) | |
m_TimeBase = Time.realtimeSinceStartup; | |
m_StateTime = Time.realtimeSinceStartup; | |
m_CurrentHandler = m_StateHandlers[value]; | |
m_CurrentState = value; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample usage: