Sharing a small utility add-on for Animancer
daenius opened this issue · 3 comments
I made a simple ScriptableObject
for running any custom code alongside playing an ITransition
similar to the AttackTransition
found in Platform Game Kit. It works the same way as Unity's stock StateMachineBehaviour
but for Animancer and I found it to be easier to work with thanks to AnimancerState
being a more useful data container than the stock AnimatorStateInfo
.
An alternative to subclassing or rolling your own ITransition
for times when you might not be able to do so. In my case, I find it useful for easily converting existing AnimatorController
s that came with a bunch of StateMachineBehaviour
from a previous project or Asset Store to Animancer.
Not sure where would be a good place to share this with the wider community. I'll post the core ScriptableObject
class here first so you guys can review it. Am I allowed to post this on Asset Store or Itch.io at some point?
public abstract class AnimancerStateBehaviour : ScriptableObject
{
public void Play(AnimancerState state, Object userData)
{
// Animator doesn't use this not sure about Timeline
// Safe freebie for binding at run time for things like Particle Systems or CharacterBrain etc
state.Playable.GetGraph().GetOutput(0).SetUserData(userData);
state.Root.RequirePostUpdate(new Updater(state, this));
OnEnter(state);
}
public virtual void OnEnter(AnimancerState state)
{
}
public virtual void ProcessFrame(AnimancerState state)
{
}
public virtual void OnExit(AnimancerState state)
{
}
// Retrieve your particle system or CharacterBrain etc
protected T UserData<T>(AnimancerState state) where T : Object =>
(T)state.Playable.GetGraph().GetOutput(0).GetUserData();
#region Updater
private class Updater : IUpdatable
{
public Updater(AnimancerState state, AnimancerStateBehaviour behaviour)
{
_state = state;
_behaviour = behaviour;
Key = new();
}
private readonly AnimancerStateBehaviour _behaviour;
private readonly AnimancerState _state;
public Key Key { get; }
public void Update()
{
if (!_state.IsPlaying)
{
_state.Root.CancelPostUpdate(this);
_behaviour.OnExit(_state);
return;
}
_behaviour.ProcessFrame(_state);
}
}
#endregion
}
What are you using the UserData for? It seems a bit odd to set it every time you play something. I'd probably implement the get and set as extension methods and have some other script set it on each character on startup.
Am I allowed to post this on Asset Store or Itch.io at some point?
Feel free to do so if you think others will find it useful.
What are you using the UserData for? It seems a bit odd to set it every time you play something. I'd probably implement the get and set as extension methods and have some other script set it on each character on startup.
I had it originally to bind arbitrary Object
similar to setting up PlayableOutput
s, and the idea was this way you wouldn't need to do a clone/instantiate on the ScriptableObject
while still having different GameObject
s correctly access live values of something. You are right though because it turned out to be less useful than expected so I ended up getting rid of it shortly after xD As you described, I got more mileage out of having the subclasses take care of themselves with binding whatever they need.
As for sharing this later, how should I declare the assembly dependency for Animancer? Should I be depending on Lite or Pro?
I don't think the Asset Store has a way to specify optional dependencies so for my Platformer Game Kit I just said it needs Animancer at the start of the description.