Search Unity

Playables graph locking animated properties with values at the last frame

Discussion in 'Animation' started by WeltallZero, Jan 9, 2019.

  1. WeltallZero

    WeltallZero

    Joined:
    Oct 23, 2016
    Posts:
    19
    I've been trying to use a mixture of Animator and Playables in my game, and for the most part it works well, but there's two issues that I've been having for a long time, and I've at best worked around them. Today I bashed my head against them again, and after finding no solution online I decided to get my lazy ass to finally ask for help.

    The basic setup is that my characters have:
    - An Animator with its controller, state machine, etc. that is used mostly for movement, jumping, climbing, etc. In case this is relevant, each character has an override controller of a generic one.
    - A very simple playable graph with just an output (wrapping the animator) and an input (wrapping the specific clip I want to play at the time). This is used for actions and attacks.

    The problems I have are:

    1- I can't seem to figure out an elegant, clean way to know when the clip fed to the graph (second part above) is finished. Currently I circumvent this by simply calculating how long the clip is and dividing by the current animation speed factor; I also have to account for when the animation is paused (e.g. hitstop). This gets the job done but is quite unelegant, and I'm sure there must be a better way.

    2- Most importantly, when I'm done with the graph and standalone animation, the values of all of the properties the clip touches become locked at their last value. They stay locked even during any animation played by the regular animator; even if any of these later animations change its value, it snaps back to that locked "last frame" value when they end. I've tried several things to solve this:
    2.1- Set the default / desired value of the properties in the idle / default animation (to "mark" them as animatable properties in the normal animator's animation). This only fixes the issue for whatever animation is touched; any other animation played after that instantly reverts to the value locked by the last frame of the animation played by the graph.
    2.2- Destroy the playable wrapping the animation (I do this anyway for cleanup since I need to recreate it each time a new animation plays).
    2.3- Destroy the graph and recreate it each time (surprisingly, even this keeps the values locked).
    2.4- Disabling the animator and enabling it again.

    I'm frankly starting to lose my mind with the second problem, so any help would be exceedingly appreciated. Thank you in advance!
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    My Animancer plugin uses the Playables API to make it easy to play individual animation clips without an AnimatorController.

    You can also play and blend between AnimatorControllers if you want to, though it's pro-only so you can try it out in the Lite version but you need to buy Pro if you want to use that feature in a build.
     
  3. WeltallZero

    WeltallZero

    Joined:
    Oct 23, 2016
    Posts:
    19
    Thank you for your reply. Can Animancer be used on top of an Animator, like you can use a graph to play individual clips but still have the Animator take care of others?
     
  4. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Yes, but probably not how you're thinking.

    With Animancer, you use an AnimancerController component which you do everything through instead of touching the Animator directly.

    The simplest use is to tell it to play an AnimationClip (literally just animancerController.Play(clip) or CrossFade) which creates and returns an internal state that tracks the animation and lets you control its speed/time/etc (or reuses the existing one for that clip). You can also use that state to register a callback for when the animation finishes as shown in this screenshot.

    But you can also create your own states manually, which can be any type of state. One such type is AnimatorControllerState which takes a RuntimeAnimatorController in its constructor and gives you most of the functions you would normally see on the Animator (CrossFade, set parameters, get current state, etc). So you keep a reference to the state you created and pass it into AnimancerController.Play or CrossFade when you want to play it, and you control its internal state specifically, not via the root Animator.

    This screenshot shows a FloatParameterControllerState which inherits from AnimatorControllerState to simply add a wrapper for a particular parameter in the AnimatorController ("Speed" in this case so it can control the blend tree). That means you could have an AnimatorController containing nothing but a blend tree for movement while other scripts play individual animations. You could even have other scripts that play other AnimatorControllers, each independent of the others instead of needing one giant mess of a state machine.
     
  5. WeltallZero

    WeltallZero

    Joined:
    Oct 23, 2016
    Posts:
    19
    I'm assuming it's not possible to let the animator control its state normally while using Animancer to occassionally play specific clips, then? I don't really want to give up on all the state machine logic that's already working.

    Also blending is not particularly useful for me, since my game is 2D and entirely sprite-based, which I now realize I should have prefaced my original post with (sorry).

    Again, thanks a lot for your time and help.
     
  6. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    If you assign an AnimatorController to the Animator while Animancer is using it, the Animator window will show it operating its states as normal but it won't have any effect on the model.

    But you don't need to give up on your state machine logic. You can just make an AnimatorControllerState with your state machine in it. While it's playing you control it through that state like you would normally control it through the Animator. When you want to play a separate clip, you do so, and when it's done you just play the AnimatorControllerState again and go back to controlling its state machine.

    I recommend you check out Animancer Lite. It lets you try out all the features in the Unity Editor so you only need to buy Pro if you like it and want to use those features in actual builds.
     
  7. WeltallZero

    WeltallZero

    Joined:
    Oct 23, 2016
    Posts:
    19
    I see, thanks! I'll give it a try later on.