Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Animancer - Less Animator Controller, More Animator Control

Discussion in 'Assets and Asset Store' started by Kybernetik, Oct 8, 2018.

  1. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    943
    Then i'm a bit lost. If i play() the mixer transition it creates a state. I have to use that state (keep a reference to it) to set the parameter (the idle-walk-run blend amount), don't i? Or do i have to override it with every new play(transition) to have the fade back to the mixer working (if that's what it's doing) and reassign the parameter?
     
    Last edited: Jul 3, 2020
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    If you are only using the transition on one object (rather than defining the transition in a ScriptableObject and sharing it between multiple characters) then you can use the
    transition.State
    instead of needing to keep a separate reference to it.

    But yes, you use the transition to play it in accordance with that transition's settings (fade duration, speed, events, etc.) and then you control the mixer state's parameter as necessary. The
    transition.State
    remembers the state that transition was most recently applied to, but there is no link from the state back to the transition.
     
  3. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    943
    Okay, thanks. I have them defined in scriptableobjects for sharing, so re-applying the parameters seems like the way to go then.
     
  4. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Hey everyone. @Flavelius has posted a suggestion that the Play(object) method should be called something else to avoid issues where you refactor an AnimationClip or transition field into something else and it silently changes to that Play method and stops working until you realise you've got a runtime bug.

    I would have preferred to just add a runtime error since that is exactly the sort of thing you need to pay attention to when refactoring anyway, but I've realised that there is actually a rather important difference between that method and the others. Play(clip), Play(transition), and Play(state) will always work because you are providing what it needs to create a state if one doesn't already exist, but that's not the case for Play(object) which can only play an existing state.

    Since it would be a notable change to the public API either way, I figured I'd see if anyone else has an opinion they'd like to share on the matter.
    • Should Play(object) throw an error if the state doesn't exist?
    • Should it be renamed to something else? If so, what should it be called?
    • Both?
     
  5. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
  6. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Hi there,
    Just wondering, what would be the best way to initialise a mixer with an AnimationClip and a LinearMixer?
    Code (CSharp):
    1.        
    2.         testMixer.Initialise(2);
    3.         testMixer.SetChild(0, testLinearMixer);
    4.         testMixer.SetChild(1, testAnimationClip);
    5.  
    I've tried this but it doesn't like the animation clip being set there as it's looking for a state. In the docs, it says to use .CreateState() but that doesn't seem to be available. Maybe because I'm in v5?
    Any ideas?

    Hey loving the new CustomFades in v5 by the way!
     
  7. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    I renamed CreateState to CreateChild but must have forgotten to update the documentation page.
     
  8. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Oh cool! Thanks.
    Hey just wondering, is there a way to change the name of the linear mixer states to make it a little clearer in the Animancer window? No stress, just thought it might be kinda handy. Also, can you see anything that looks wrong with this? I might have a little repro to send you. It seems that when I play this state I get one frame of the character in a reset pose.
    Screen Shot 2020-07-23 at 12.30.04 pm.png

    Thanks,
    Pete
     
  9. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Custom state names should be easy. Also, do you think I should indent the green bars with the child states? It might look neater, but would mean the bars don't line up when times are synchronised any more.

    Yeah, send me a repro. I don't know of any lingering issues that would cause things to not work for a single frame.

    Those warning icons suggest that the animations are trying to control something that doesn't exist on the character. You can click them to get a description of the issue, but that shouldn't have anything to do with the issue you described.
     
  10. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Okay I've sent you a file, see how you go.
    Hmm, yeah I think offsetting the lines would definitely be a lot clearer in this instance but might be annoying if you were looking to see the sync visually...
     
  11. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    If you go to the base MixerState class and make its CreatePlayable method call RecalculateWeights after creating the playable that seems to solve the issue. It wasn't properly propagating the dirty flags onto the nested mixers.
     
    petey likes this.
  12. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Ahh cool!
    Hey, I'm a little worried I might break something. Could you go into a little more detail on modding that script :p
    Is this the one?
    Code (CSharp):
    1. public abstract class MixerState<TParameter> : ManualMixerState
     
  13. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    No, you want MixerState.cs (not T).
    Code (CSharp):
    1.         protected override void CreatePlayable(out Playable playable)
    2.         {
    3.             playable = AnimationMixerPlayable.Create(Root._Graph, ChildStates.Count, false);
    4.             RecalculateWeights();// Add this.
    5.         }
     
    petey likes this.
  14. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Awesome Thankyou!
     
  15. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Animancer v5.1 is now up on itch.io (and should be approved for the Asset Store in a few days). It has a few minor bug fixes and improvements, as well as the ability to set a custom display name for any state as suggested by @petey.
     
    petey likes this.
  16. EnderAtreides

    EnderAtreides

    Joined:
    May 10, 2020
    Posts:
    4
    Animancer has been helpful so far, but I recently encountered an error that I'm trying to understand:
    We are using a Hybrid Animancer Component to better control an Animator, with Animation events mixed in, but are new to both Unity and Animancer. (Recently updated to Unity 2020/Animancer 5.1)

    What kind of situations trigger this warning? Within the context of a Hybrid Animancer, I'm trying to use Animancer tools when I can without outright breaking the underlying Animator. Within the context of design, this is 2D, and most transitions are essentially instantaneous.
     
  17. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    That warning is triggered any time you try to use Animancer Events on a ControllerState, which is what the HybridAnimancerComponent uses to play its Animator Controller. So if you call
    animancer.Play(clip)
    to play a separate animation and then register an event on that state it will be fine, but if you call
    animancer.Play("State Name")
    to play one of the states inside the Animator Controller then register an event, it will give the warning.

    Does that make sense?
     
    EnderAtreides likes this.
  18. EnderAtreides

    EnderAtreides

    Joined:
    May 10, 2020
    Posts:
    4
    Ah, that does make sense, thank you!
     
  19. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Are you able to share the files that you modified? I use Puppetmaster and Final IK, primarily for the Biped Stagger, so I wasn't sure if I would be able to use Animancer, which is what lead me to searching and finding your post, if you happen to remember what you changed to get it to work, I would be super appreciative. Did you happen to try it with Final IK as well, or only Puppetmaster?
     
  20. holdingjason

    holdingjason

    Joined:
    Nov 14, 2012
    Posts:
    135
    Hi just started integration of your product into our current game and came across this odd issue. Probably something I am ignorant on. So far its pretty simple. I am just playing various animation clips, mostly just normal character movement stuff right now, run, turn right, idle etc. Simply calling _animancer.Play(clip, 0.25f); This works fine. However when I play an animation with Rotation set to 0 in the base animation the character locks up. Meaning it keeps resetting the rotation back to Vector3.zero of the character AFTER the animation has been fully played and something else (say idle or run) is now playing. I can see that the animation with the Rotation that caused the issue is still listed in states but I can see its now running or active. However it acts like somehow it is still, under covers, running that first bit and constantly resetting the rotation based to zero (that is a guess on my part but one I can recreate).

    So first is this some sort of bug? Something I am doing wrong (other then probably should not be setting the rotation like this but still seems like an issue.) I am not sure I fully understand the states and why once a clip has been played it stays in the list of states forever, are we suppose to destroy the state at some point etc. Are the states somehow still active in some sense and what are they doing if they are not actively running?

    Perhaps you could point me to something that would give me a bit more detail on how those work.

    Thanks appreciate the help. So far so good with everything else. Here is an example of a clip that causes the issue. Removing that Rotation setting from the animation clip "fixes" the issue but not sure how that is running over and over once we are playing a different clip.

    upload_2020-8-11_8-32-14.png
     
  21. SenseEater

    SenseEater

    Joined:
    Nov 28, 2014
    Posts:
    84
    Usually when a state gets created it gets registered in an internal Dictionary using a particular key so that it can later be retrieved using that key and reused.

    By default, the AnimationClip the state is playing will be used as its key, but the system allows you to use any object as a key (every variable in C# is an object).


    from the Manual , State : https://kybernetik.com.au/animancer/docs/manual/playing/states#Keys
    also checkout State API remarks : https://kybernetik.com.au/animancer/api/Animancer/AnimancerState/
     
  22. holdingjason

    holdingjason

    Joined:
    Nov 14, 2012
    Posts:
    135
    * Update to my original issue.

    So a related issue. The state for these animations seems to always be returning "playing" on a non looping clip until I play another animation. These animations are short, non looping, emote type animations (2 seconds). Why would the state constantly return playing? The animation plays fine and finishes fine except its state never stops reporting playing.

    *Update

    The normalized time just keeps growing forever and this never stops playing unless I trigger another animation.
    upload_2020-8-11_15-32-44.png

    *Update

    So this works the same in the examples. So not sure what the proper use of isPlaying isActive would be. It looks like after firing one off animations (emotes etc) the pattern is to attach a onEnd handler that puts us back into an looping idle animation in order to truly "end" the one off animation. I was trying to use isPlaying in a polling situation to check to see if we should drop back into idle instead of attaching something to the onEnd.

    Is this basically a correct assumption on my part?

    BTW not complaining or anything just trying to make sure I understand the patterns that should be used and get my head wrapped around the best way to use the tool.
     
    Last edited: Aug 11, 2020
    SenseEater likes this.
  23. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Q: Why is rotation resetting when playing a different animation.
    A: Any value controlled by any animation state that exists in the character will be set every frame, and if that animation isn't currently playing then the value will be set back to 0 by default. The only exception to this is Root Motion, which is probably what you want in this case.

    Q: Why are the states still there when not playing?
    A: Because destroying and recreating them has a performance cost which is usually much more important than the RAM used by just keeping them around. If you Right Click on one of them, you can use the Display Options menu to "Hide Inactive States", but that's just hiding them in the Inspector, they will still exist.

    Q: Why are non-looping animations still "playing" after they end?
    A: That's just how the Playables API works (and Animator Controllers and the Legacy animation system too).

    Q: What can I poll instead of using an OnEnd event?
    A: Events are based on the animation time, so either
    state.Time > state.Length
    or
    state.NormalizedTime > 1
    .

    I think that was all your questions. Let me know if I missed any.
     
  24. holdingjason

    holdingjason

    Joined:
    Nov 14, 2012
    Posts:
    135
    Yep I think you covered it. Thanks for the fast response and details. Now back to work...
     
  25. launzone

    launzone

    Joined:
    Dec 2, 2015
    Posts:
    57
    Hi!
    I am trying to make blend trees but I don't understand how to actually make use of the "MixerTransition2D" assets. I can create one in my project, assign it to my Animancer component and play it. But how do I change the Parameter that is being read for the Thresholds at runtime?
     
  26. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Take a look at the LinearMixerLocomotion script in the Linear Blending example.
     
    launzone likes this.
  27. launzone

    launzone

    Joined:
    Dec 2, 2015
    Posts:
    57
    Thank you for the quick response! I ended up not using the assets and just creating the mixer in the script.

    I would have another question if you don't mind: I want to play some clips on an Additive Layer. It works fine as long as only one of them has been played. As soon as another one starts playing the Character gets a weird offset.

    To further explain: I set the Layer to additive once in the start. Whenever I want to play an animation on the layer i do Layer[1].Play. Not more than 1 animation is ever playing on it at the same time. After an animation is done playing I tried stopping the Layer, setting all weights to 0 and even destroying the state that was just playing. It doesn't matter as soon as I play another Animation there is a weird offset.
    The animations clips themselves don't even change positions, just rotations, so I don't know where the offset could be coming from.
     
  28. launzone

    launzone

    Joined:
    Dec 2, 2015
    Posts:
    57
    Maybe to understand it better:
    In the first case I have only played one Animation, everything is fine.
    upload_2020-8-14_13-58-35.png

    Then when another Animation has been played the Character has an offset, even though the weights of the other states are 0 and they are not playing
    upload_2020-8-14_13-57-47.png
     
  29. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    That certainly sounds like a bug. Do you think you could make a simple reproduction project and email it to animancer@kybernetik.com.au so I can take a look?
     
  30. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    I have played with Animancer Pro examples and could not find the one, I needed.
    I would like to play different animations on the humanoid character by pressing the keys 1, 2, 3, 4 until 9.
    How can I achieve that?
    I have added animancer component to the character and added a couple animations there.
    But what to do next?
    An example script would be much appreciated.
    It is like the demo scene, to present different animations by pressing number keys.
     
  31. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Try something like this:
    Code (CSharp):
    1. [SerializeField]
    2. private AnimancerComponent _Animancer;
    3.  
    4. [SerializeField]
    5. private ClipState.Transition[] _Animations;
    6.  
    7. private void Update()
    8. {
    9.     var count = Mathf.Min(9, _Animations.Length);
    10.     for (int i = 0; i < count; i++)
    11.     {
    12.         var key = KeyCode.Alpha1 + i;
    13.         if (Input.GetKeyDown(key))
    14.         {
    15.             _Animancer.Play(_Animations[i]);
    16.         }
    17.     }
    18. }
     
  32. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    Sorry, when I have pasted the above code into script file PlayAnimsViaNumberKey.cs
    I got bunch of errors:
     

    Attached Files:

  33. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    You need to put it inside a class, just like every other script you write.
     
  34. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    When I have put the script shown below, it compiles, but does not work.
    Only first animation from the list will play.
    Could you please help me with this issue.

    Code (CSharp):
    1. #pragma warning disable CS0649
    2.  
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine;
    7. using Animancer;
    8.  
    9. public class PlayAnimsViaNumberKey : MonoBehaviour
    10. {
    11.     [SerializeField]
    12.     private AnimancerComponent _Animancer;
    13.     [SerializeField]
    14.     private ClipState.Transition[] _Animations;
    15.     private void Update()
    16.     {
    17.         var count = Mathf.Min(9, _Animations.Length);
    18.         for (int i = 0; i < count; i++)
    19.         {
    20.    var key = KeyCode.Alpha1 + i;
    21.    if (Input.GetKeyDown(key))
    22.    {
    23.        _Animancer.Play(_Animations[i]);
    24.    }
    25.         }
    26.     }
    27. }
    28.  
     
  35. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Use Debug.Log to find out what values it's getting so you can narrow down the problem. Maybe the object you're looking at only has one animation assigned so the count is only 1. Maybe the key is getting the wrong code. Maybe it is properly getting in and calling Play, but the animation is incompatible with the character you are trying to play it on. The code looks fine so there isn't really anything else I can do to help without more information.
     
  36. Artini

    Artini

    Joined:
    Jan 29, 2016
    Posts:
    181
    Thanks a lot, for the help. I will try to debug it.
    Despite playing with Unity for couple of years, I am still newbie with the scripting part of the engine.
     
  37. launzone

    launzone

    Joined:
    Dec 2, 2015
    Posts:
    57
    Hi Kybernetik,
    Thank you for the reply!
    It is kind of hard for me to share a reproduction, I would have to replace the character asset and a lot of other things because I am currently not allowed to share this work.

    I found the culprit though and made it work, I will try to explain it. I think it might not necessarily be a bug with Animancer but it is odd that this always happened exactly when I was calling the second Animation.
    So the character uses a Rigidbody and capsule collider and starts slightly off the ground before falling on it. When I called the new Animation it seemed to snap back to an offset close to its start position. Even though the capsule collider and rigidbody still had the correct positions.
    I hope that helps? Basically I adjusted the ground plane and then it was fine without changing anything in the animation system. Let me know if I could share any other info with you. I will see if I can find the time this week to maybe replace the character with just a bunch of cubes and make a version that I can share with you.
     
  38. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    I still don't really understand the problem so I'll have to wait and see what you send me.
     
  39. classofthirteenth

    classofthirteenth

    Joined:
    Nov 1, 2019
    Posts:
    16
    Hi Kybernetik,

    Is it possible to add AnimationClip reference via code instead of inspector one-by-one in AnimancerNamedComponent instance? Since my project has a lot of animation clip state that need to be referenced. Thank you

    upload_2020-8-20_12-16-54.png
     
  40. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Of course. You can set the Animations array to contain whatever you want or just play animations directly without putting them in the array first (in which case you could just use a regular AnimancerComponent instead of a NamedAnimancerComponent).
     
  41. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Hiya!
    Just wondering, is there a way to play an animation at a low weight so it doesn't completely affect the existing states? I'm working on something where I'd just like to introduce a hint of another animation (not synced up).
    The new state naming feature is great by the way!
    Thanks,
    Pete
     
  42. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    You can set the Weight and IsPlaying properties to whatever you want on individual states, but the easiest way to manage multiple animations is usually with layers.
     
  43. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Yeah, I think this could be a good case for layers, thanks!
    Pete
     
  44. ratking

    ratking

    Joined:
    Feb 24, 2010
    Posts:
    349
    Hi,
    I have a looping attack animation (1.5s) with two Animancer events, one at 0.25s and one at 0.85s. After a short while of attacking the first one doesn't get fired anymore, and sometimes the second one too is missing. Is something like that to be expected? How reliable are events?
     
  45. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    I don't know of any reliability issues with events at the moment.

    Do you think you could make a Reproducible Example of the issue and send it to animancer@kybernetik.com.au?
     
  46. ratking

    ratking

    Joined:
    Feb 24, 2010
    Posts:
    349
    I tried, but unfortunately the wrong behaviour does not happen when I put the stuff in an empty test scene and recreate the animation setup, and I don't have time right now to tear my own scene apart.
     
  47. ratking

    ratking

    Joined:
    Feb 24, 2010
    Posts:
    349
    I solved my problem with the events not firing by starting the attack animation always from 0 by using FadeMode.FromStart (afterwards I changed it from a loopable animation to non-looped, but the first change already helped). Maybe the problem actually was that I called animancerComponent.Play(animClipAttack, 0.15f); every ~1.5 seconds?
     
  48. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    Calling Play shouldn't do anything if that animation was already playing so I don't think that would be the issue, but it's hard to know without seeing it in action.
     
  49. ratking

    ratking

    Joined:
    Feb 24, 2010
    Posts:
    349
    One question out of interest: is it possible to update the animation manually? This is so I could easily have objects that animate at a lower framerate.
     
  50. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,554
    animancer.Playable.PauseGraph() and animancer.Evaluate(deltaTime).

    That question comes up quite a lot so I'm thinking I'll add an example for it in the next version.
     
    ratking likes this.