Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Animancer - Less Animator Controller, More Animator Control

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

  1. b1gry4n

    b1gry4n

    Joined:
    Sep 11, 2013
    Posts:
    146
    Im not quite sure Im doing this correctly. I want to create a handful of LinearMixerState at Start(), 6 total.
    Code (CSharp):
    1.     public class MovementSettings
    2.     {
    3.         public string name;
    4.         [HideInInspector]
    5.         public int index;
    6.         public AnimationClip[] animClips;
    7.         public float[] thresholds;
    8.         [HideInInspector]
    9.         public LinearMixerState mixer;
    10.     }
    Code (CSharp):
    1.     public MovementSettings down;
    2.     public MovementSettings up;
    3.     public MovementSettings left;
    4.     public MovementSettings right;
    5.     public MovementSettings forward;
    6.     public MovementSettings back;
    I want to generate this all through code. Each LinearMixerState has animations and thresholds I assign.

    Code (CSharp):
    1.         settings.mixer = new LinearMixerState(animancer);
    2.         settings.mixer.Initialise(settings.animClips, settings.thresholds);
    3.         settings.mixer.SetWeight(0);
    Then, I want to add all these LinearMixerStates to a ManualMixerState. This way I can manually control the linear blends of animation clips while also blending the LinearMixerStates with eachother.

    Code (CSharp):
    1.         mixer.Initialise(7);
    2.         mixer.States[0] = animancer.States.GetOrCreate(movement.idle);
    3.         mixer.States[1] = movement.back.mixer;
    4.         mixer.States[2] = movement.forward.mixer;
    5.         mixer.States[3] = movement.left.mixer;
    6.         mixer.States[4] = movement.right.mixer;
    7.         mixer.States[5] = movement.up.mixer;
    8.         mixer.States[6] = movement.down.mixer;
    9.         mixer.States[0].SetWeight(1);
    10.         animancer.Play(mixer);
    The problem is when I create a new linearmixerstate it automatically adds it to the animancer component. I end up with duplicates in the animancer component after adding the linearmixerstates to the manualmixerstate. Im not quite sure how I could use something similar to "GetOrCreate" with a mixer and cant seem to find it anywhere, so that animancer will use the already created mixer rather than dupicating it inside this new manualmixer

    Am I thinking of this incorrectly? Do I need to even mix the linear mixers together? Im not sure how I would tell the animancer component to "play" individual linear mixers all at once without a parent mixer
     
    Last edited: Feb 19, 2020
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    If you use a
    LinearMixerState.Transition
    you get a nicer Inspector interface instead of having separate arrays for the clips and thresholds and you can pass it into GetOrCreate.

    But I can now see a big problem in the way I designed the API: setting
    mixer.States[x] = something
    will let the mixer control that state because anything with a reference to a state can control it, but it will not actually set the mixer as that state's parent.

    new LinearMixerState(animancer)
    is actually shorthand for
    new LinearMixerState(animancer.Layers[0])
    which sets the default layer as the new state's parent then
    mixer.States[1] = movement.back.mixer;
    makes the manual mixer think the new state is a child without actually changing its parent. So you aren't getting duplicated mixers, they are just getting drawn in two places because they aren't parented correctly.

    Instead, you can either call
    new LinearMixerState(animancer.Playable)
    to create it without actually setting a parent then
    movement.back.mixer.SetParent(mixer, 1);
    to set the parent properly or you can directly create it as a child of the mixer using
    new LinearMixerState(mixer, 1)
    .

    I'll have to fix the mixer nesting section in the documentation and think about how I can redesign the API for the next version.

    Also, you should probably not use [HideInInspector] in this situation because the value will still get saved in the scene even though it isn't being shown in the Inspector. So if the index got set to some value in Edit Mode it would get saved with that value even though you are probably expecting it to always start at 0. If you actually want a field to not be saved you can use [System.NonSerialized] instead. And you don't need either one on the mixer field because LinearMixerStates can't be serialized anyway.
     
  3. b1gry4n

    b1gry4n

    Joined:
    Sep 11, 2013
    Posts:
    146
    Thanks, I was able to get it working using the
    new LinearMixerState(parentMixer, index);
    approach instead of assigning the states manually in the array

    I am using this setup for air movement (we talked on reddit about this) Here is how I am initializing each linearmixer and assigning it to a parent mixer

    Code (CSharp):
    1.      
    2.  
    3.     private void Start()
    4.     {
    5.         airmixer = new ManualMixerState(animancer);
    6.         airmixer.Initialise(3);
    7.         SetupMixer(airMovement.horizontal,0, airmixer);
    8.         SetupMixer(airMovement.vertical, 1, airmixer);
    9.         SetupMixer(airMovement.forward, 2, airmixer);
    10.         airmixer.SetWeight(1);
    11.         animancer.Play(airmixer);
    12.     }
    13.  
    14.     void SetupMixer(AirMovement.MovementSettings settings, int index, ManualMixerState mms)
    15.     {
    16.         settings.index = index;
    17.         settings.mixer = new LinearMixerState(mms, index);
    18.         settings.mixer.Initialise(settings.animClips, settings.thresholds);
    19.     }
    20.  

    and then when its time to update the parameters:
    Code (CSharp):
    1.         airMovement.horizontal.mixer.Parameter = localVelocity.x;
    2.         airMovement.vertical.mixer.Parameter = localVelocity.y;
    3.         airMovement.forward.mixer.Parameter = localVelocity.z;
    4.  
    5.         airmixer.States[airMovement.horizontal.index].Weight = Mathf.Abs(localVelNormalized.x);
    6.         airmixer.States[airMovement.vertical.index].Weight = Mathf.Abs(localVelNormalized.y);
    7.         airmixer.States[airMovement.forward.index].Weight = Mathf.Abs(localVelNormalized.z);
    This is something I was struggling with for a while simply because blending between 3 values in mecanim is a headache. Animancer has allowed me to blend all 3 together and visually it looks much better. Ill be heading over to the asset store real quick to leave a review.
     
    Last edited: Feb 21, 2020
    StevenPicard and Kybernetik like this.
  4. b1gry4n

    b1gry4n

    Joined:
    Sep 11, 2013
    Posts:
    146
    I was able to do the exact same approach with a layer and a mask, in my case using a mask to only affect the right arm, feeding it an xyz parameter as the aim target, and blending between the 3 weights/parameters for that layer. Doing it this way lets me feed in forward/backward up/down and left/right animation poses. This makes me excited for the different things I can do with animancer that were borderline impossible with mecanim.
     
    StevenPicard likes this.
  5. ve110cet

    ve110cet

    Joined:
    Dec 11, 2017
    Posts:
    10
    Hi there!
    I've been playing around with Animancer Pro for the last week and I'm really liking it! Honestly, I'm a bit new to animation but the code based approach in Animancer works much better for me.

    I've been trying to make a 2DMixer since I have left/right leans as well as walk/jog/run blends. I'm trying to modify a number of the examples to work with this and have linear blending for walk/jog/run. As soon as I try to change to a DirectionalMixerState or MixerTransition2D (or even Float2ControllerTransition - this one doesn't allow me to add clips), I can't get the mixer state to work... Here is the LinearMixer that works for me:

    public class LocomotionAnimState : AnimState
    {
    [SerializeField] private LinearMixerTransition _locomotionBlendTree;

    private LinearMixerState _state;

    private void OnEnable()
    {
    AnimStateMachine.Animancer.Play(_locomotionBlendTree);
    _state = _locomotionBlendTree.Transition.State;
    }

    And here is what I'm trying to do (I just want to be able to control the blend tree with two parameters):

    public class LocomotionAnimState : AnimState
    {
    [SerializeField] private MixerTransition2D _locomotionBlendTree;

    private DirectionalMixerState_state;

    private void OnEnable()
    {
    AnimStateMachine.Animancer.Play(_locomotionBlendTree);
    _state = _locomotionBlendTree.Transition.State;
    }


    When I try this, I get a typing error on "_state = _locomotionBlendTree.Transition.State;" I'm also only a slightly better than beginner coder so I don't even understand why the state needs to be set in order to adjust the parameters (just that it works).

    Any help you can provide would be much appreciated.
     
  6. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Float2ControllerTransition is for playing Animator Controllers, not a mixer. So you could use it to play an Animator Controller containing a Blend Tree and control two of its float parameters.

    The error you are getting is because
    _locomotionBlendTree.Transition.State
    is a
    MixerState<Vector2>
    which could be either a
    DirectionalMixerState
    or a
    CartesianMixerState
    depending on which
    Type
    you select in the Inspector, but the compiler can't know which it will be so you can't assign it to that field. Instead, you can just change the field to
    private MixerState<Vector2> _state;
    .
     
  7. ve110cet

    ve110cet

    Joined:
    Dec 11, 2017
    Posts:
    10
    Thanks for that amazingly quick response! (And for the awesome product!)
     
  8. ve110cet

    ve110cet

    Joined:
    Dec 11, 2017
    Posts:
    10
    Hi again... I guess the question that I'm having (and failing to do) is how do I use a MixerTransition2D asset in the same way as the examples that have MixerState.Transition2D components. That is to say so that I can create a Mixer2D object and assign it in the inspector.

    Specifically I'm having trouble with trying to make something similar to this:
    Code (CSharp):
    1. [SerializeField] private MixerState.Transition2D _directionalLanding;
    2.  
    3. private void Awake()
    4. {
    5.     _directionalLanding.Events.Sequence.OnEnd = () => Creature.CheckMotionState();
    6. }
    To something like this:
    Code (CSharp):
    1. [SerializeField] private MixerTransition2D _directionLanding;
    2.  
    3. private MixerState<Vector2> _directionLandingState;
    4.  
    5. private void Awake()
    6. {
    7.     ??????
    8. }
    Thanks for all your help!
     
  9. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Try this:
    Code (CSharp):
    1. [SerializeField] private MixerTransition2D _directionLanding;
    2.  
    3. private MixerState<Vector2> _directionLandingState;
    4.  
    5. private void Awake()
    6. {
    7.     // Play it:
    8.     _Animancer.Play(_directionLanding);
    9.     // Or create the state without playing it:
    10.     _directionLanding.CreateState(_Animancer);
    11.  
    12.     // Either of the above returns an AnimancerState which we could cast to MixerState<Vector2>.
    13.     // But the transition also caches the state as the correct type so we can just use that:
    14.     _directionLandingState = _directionLanding.Transition.State;
    15.  
    16.     // In your first code block _directionalLanding.Events was the serialized event sequence.
    17.     // So you needed to use _directionalLanding.Events.Sequence to access its runtime event sequence.
    18.     // But here we have already created the runtime state so its Events are already a runtime event sequence.
    19.     _directionLandingState.Events.OnEnd = () => Creature.CheckMotionState();
    20. }
     
  10. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Hey everyone, Animancer v4.1 is now up on the Asset Store and is also available from itch.io.

    The main features are:
    • A couple of minor performance improvements and added more detail to the benchmarks on the Performance page.
    • Replaced ExposedCurve with AnimatedProperty so you can properly access custom animation curves which are properly blended rather than using a hacky workaround to serialize individual curves separately. The Uneven Ground example shows how to use them. It requires Unity 2019.1+, so I've put a download for the old ExposedCurve script on the IK page if you need it.
    • PlayableAssetStates now support Timelines with multiple tracks, including non-animation tracks like audio.
    • Cleaned up the Mixer API to avoid the problem @b1gry4n was having.
    As always, the Change Log has the complete list of changes and when upgrading to a newer version of Animancer, you must delete any previous version from your project first.
     
    Last edited: Mar 9, 2020
    slimshader likes this.
  11. ibompuis

    ibompuis

    Joined:
    Sep 13, 2012
    Posts:
    99
    @Kybernetik, possible to set number of loop for animation ?
    Like: _Animancer.Play(_Dresseur_Kneel_Caress, 0.25f).loop(3)

    PS: used Pro version
    Thanks,
     
  12. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    You can use an End Event at normalized time 3 to play a different animation:
    Code (CSharp):
    1. _Animancer.Play(_Dresseur_Kneel_Caress, 0.25f).Events.endEvent = new AnimancerEvent(3, () =>
    2. {
    3.     _Animancer.Play(_Idle);
    4. });
     
  13. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Hey everyone, sorry to keep spamming updates all the time but I've just released Animancer v4.2 to fix some major issues with Animancer Lite (the DLL obfuscation was causing continuous garbage allocation and was doing some things that IL2CPP apparently doesn't support). There are a few other changes, but nothing too significant for anyone using Animancer Pro.
     
    DebugLogError likes this.
  14. DebugLogError

    DebugLogError

    Joined:
    Jul 24, 2013
    Posts:
    54
    @Kybernetik I have a 2D mixer and I want to reuse my walk forward animation for walking backwards. However, when I set the speed of the walk backwards animation to -1 I get this error:

    ArgumentNullException: Value cannot be null.
    Parameter name: The Playable is null.
    UnityEngine.Playables.PlayableHandle.SetSpeed (System.Double value) (at <58a34b0a618d424bb5fc18bb9bcdac20>:0)
    UnityEngine.Playables.PlayableExtensions.SetSpeed (U playable, System.Double value) (at <58a34b0a618d424bb5fc18bb9bcdac20>:0)
    Animancer.AnimancerNode.set_Speed (System.Single value) (at Assets/Plugins/Animancer/Internal/Core/AnimancerNode.cs:702)
    Animancer.ManualMixerState+Transition`1[TMixer].InitialiseState () (at Assets/Plugins/Animancer/Internal/Mixer States/ManualMixerState.cs:526)
    Animancer.MixerState+Transition`2[TMixer,TParameter].InitialiseState () (at Assets/Plugins/Animancer/Internal/Mixer States/MixerState.cs:644)
    Animancer.MixerState+Transition2D.CreateState () (at Assets/Plugins/Animancer/Internal/Mixer States/MixerState.cs:709)
    Animancer.AnimancerState+Transition`1[TState].Animancer.ITransition.CreateState () (at Assets/Plugins/Animancer/Internal/Core/AnimancerState.cs:1120)
    Animancer.AnimancerPlayable+StateDictionary.GetOrCreate (Animancer.ITransition transition) (at Assets/Plugins/Animancer/Internal/Core/AnimancerPlayable.StateDictionary.cs:255)
    Animancer.AnimancerPlayable.Play (Animancer.ITransition transition, System.Single fadeDuration, Animancer.FadeMode mode) (at Assets/Plugins/Animancer/Internal/Core/AnimancerPlayable.cs:639)
    Animancer.AnimancerPlayable.Play (Animancer.ITransition transition) (at Assets/Plugins/Animancer/Internal/Core/AnimancerPlayable.cs:572)
     
    Last edited: Mar 8, 2020
  15. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Looks like there's a bug in the way mixers initialise the speeds of their children. I can't see a simple way to work around it (other than just not using speeds for now), but I'll work on a fix ASAP and send it to you when it's done (probably later tonight or tomorrow).
     
  16. jaggie11

    jaggie11

    Joined:
    Aug 27, 2019
    Posts:
    2
    Hi all,

    I wanted to see if anyone had any suggestions/advice (or at least "where to start" pointers) on implementing more nuanced walking and running animations like starting into the movement, coming to a stop, 180 and 90 degree turns that lead into movement in that direction, etc., into my basic beginning code. I've been able to get a very basic blended animation system of idle, walking, and running to work based on the "Walk and Run Locomotion" example, and it's definitely serviceable, but I'm really wanting it to be more fine tuned.

    I'm still making my way through all of the examples and the manual itself to try and wrap my head around everything, and I'm still somewhat new to C# and Unity (about 8 months), so if the answer seems simple or obvious, I apologize! I want to get through all of the examples and documentation before I really sit down and try to work out my animation controls, but I was curious if those type of animations were covered anywhere or if I would need to really puzzle it out eventually.

    The asset is great, regardless - I never liked working with Mechanim and this has been a fantastic change of pace. Just gotta fully wrap my head around all of the concepts ;)

    Thanks!
     
  17. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    The Turning page in the 3D Game Kit example explains a simple implementation of using special turning animations for sharp turns, but I've never done anything more complex than that.
     
    jaggie11 likes this.
  18. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I've sent @FlockingBehavior a patch to fix the issue with mixer speeds so if anyone else encounters the same problem just let me know. Otherwise I'll add a few more things and release v4.3 sometime soon.
     
    slimshader and DebugLogError like this.
  19. SpyrosUn

    SpyrosUn

    Joined:
    Nov 20, 2016
    Posts:
    144
    Hi ! I bought Animancer Pro some time ago but haven't played with it yet. I love the idea and think it would be useful, but not sure how well it can integrate with other popular assets, like the Top Down Engine, which i am using on the same project. Have you by any chance looked into that ? Would it be simple to integrate for a programmer ?
     
  20. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I'm not familiar with the Top Down Engine, but I expect it to not be at all compatible out of the box. Animancer has a few examples that should help you integrate it though:
    • Directional Sprites (if you are using Sprites) gives you a much easier way of managing directional animations than anything an Animator Controller can achieve.
    • Hybrid Basics and Hybrid Mini Game demonstrate how you can use an existing Animator Controller in Animancer with the ability to play other separate animations alongside it.
    • 3D Game Kit goes through the process of converting an Animator Controller based character to use Animancer instead.
     
  21. SpyrosUn

    SpyrosUn

    Joined:
    Nov 20, 2016
    Posts:
    144
    Thanks ! The Top Down engine is supposed to be animation framework agnostic, but I will try. I am for now learning more about Animancer, but will then look to see how and if it can integrate with the TDE.
     
  22. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Animancer v4.3 is now up on itch.io with the fix for the issue @FlockingBehavior was having, as well as a few other minor improvements and fixes. It will still be at least a few days before it gets approved on the Asset Store.
     
  23. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    When a animation event triggers, I'm trying to find a way to figure out what layer the event was triggered on.
    I tried "animEvent.animationState.layer", but it throws an error:


    I am using a Animation component, my only guess is that something with Animancer tweaked things?

    Is there a built in way to get more info about a AnimationEvent in Animancer?
     
  24. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    You aren't using an Animation component, you're using an Animator. The animationState property only works with the legacy Animation system. Using an Animator only lets you access animatorClipInfo and animatorStateInfo which don't tell you anything about the layer.

    But if you're playing the clip using Animancer (rather than inside an Animator Controller played by Animancer) then you could look up the layer using the clip:
    Code (csharp):
    1. var state = animancer.States[event.animatorClipInfo.clip];
    2. var layer = state.Layer;
     
  25. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    Ahhh that explains it. I actually managed to figure it out by finding an old solution made by myself, funnily enough (this has nothing to do with animancer, as you mentioned)

    Code (CSharp):
    1. private int GetLayer(AnimatorStateInfo animInfo)
    2.         {
    3.             for (int i = 0; i < animator.layerCount; i++)
    4.             {
    5.                 //Check current state on layer
    6.                 AnimatorStateInfo compareAnimEvent = animator.GetCurrentAnimatorStateInfo(i);
    7.                 if (animInfo.shortNameHash == compareAnimEvent.shortNameHash)
    8.                 {
    9.                     return i;
    10.                 }
    11.  
    12.                 //Also check the next, since timing is sometimes a bit off
    13.                 compareAnimEvent = animator.GetNextAnimatorStateInfo(i);
    14.                 if (animInfo.shortNameHash == compareAnimEvent.shortNameHash)
    15.                 {
    16.                     return i;
    17.                 }
    18.             }
    19.             //Couldn't find
    20.             return -1;
    21. }
    22.  
     
  26. ZINI-NGR

    ZINI-NGR

    Joined:
    Jan 28, 2013
    Posts:
    20
    Hi~ Can I use this compatible with ragdoll? And if it possible could you tell me how to use animancer × ragdoll? I wanna build a reaction system through animancer and ragdoll.
     
  27. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I've never heard of a plugin called Ragdoll and a search doesn't find anything with that exact name. But there's a section about Compatibility in the documentation and if you can explain how that system actually interacts with animations normally, I can probably tell you whether the same is possible with Animancer. Most likely it will be possible, but it might not work straight out of the box.
     
  28. ZINI-NGR

    ZINI-NGR

    Joined:
    Jan 28, 2013
    Posts:
    20
  29. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    The only part of that video that has anything to do with animation is right at the start when he disables the Animator component so you can simply do the same thing in Animancer by disabling both the Animator and AnimancerComponent.
     
  30. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    135
    For the example on Nesting Mixers; https://kybernetik.com.au/animancer/docs/manual/blending/mixers/
    when
    _MovementMixer.SetThreshold(0, 0)
    is made, the thresholds are made dirty, which causes the validate thresholds function to be called, which will throw and exception if not all the thresholds have been set.

    ArgumentException: LinearMixerState: Thresholds are out of order. They must be sorted from lowest to highest with no equal values.
    Animancer.LinearMixerState.AssertThresholdsSorted () (at Assets/Plugins/Animancer/Internal/Mixer States/LinearMixerState.cs:102)

    This exception prevents any further code to be run, which in turn prevents further thresholds being set.
    Is there a way to delay the assertion that checks the thresholds some how.

    For now, I've replaced
    Code (CSharp):
    1. movementMixer.SetThreshold(0, 0);
    2. movementMixer.SetThreshold(1, 1);    
    with
    Code (CSharp):
    1. var thresholds = new float[] { 0, 1 };
    2. movementMixer.SetThresholds(thresholds);
    which seems to work ok.
     
    Last edited: Mar 24, 2020
  31. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I've fixed that issue for the new version which I hope to release in the next few days.
     
    hopeful likes this.
  32. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    135
    I'm having issues with blending mixers, the animations do not seem to start properly. I've copied pasted the 3D kit example and replaced the locomotion state with the Mixers blending example, while removing rotation and applying walk forward & back, strafe left/right animations to the 2d blend tree;
    https://kybernetik.com.au/animancer/docs/manual/blending/mixers/

    When a movement key is pressed, the character gets stuck in the same position, the blend tree animation starts to play, but then stops on the 1st frame or there about. With a bit of movement key jiggling, the character sometimes break free and then the animations will play and the character will move correctly.
    As you can see, the upper animation should be playing, but isn't.
    Untitled.png
    I'm really not sure what's causing this to happen.

    I have made a sample available on Github, which can be found at https://github.com/Craigjw/AnimancerCreatureController
    Animancer pro has been left out from repository and will need to be added to the usual directory. The project requires Animancer 4.3 Pro and Unity 2019.3.6f1

    The only 3rd party assets used are the included animations, which are all from Mixamo, so have a CC licence.
     
    Last edited: Mar 25, 2020
  33. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    It seems to be a bug related to having Synchronisation enabled on nested mixers. As a workaround, putting
    _MovementMixer.SynchroniseChildren = new bool[2];
    in your Awake method seems to avoid the problem. And I recommend disabling the Sync toggle in the Inspector for your Idle animations since there is no need to synchronise them with any particular part of the walk cycle (the Synchronisation page explains it in more detail).

    Also, Mixamo doesn't have a CC license. I've never been able to find the actual license terms, but according to this thread redistribution of the source assets is not allowed. So I would recommend uploading to Google Drive or Dropbox and emailing me a private link in the future (not that it seems particularly likely for them to really care anyway).
     
    craigjwhitmore likes this.
  34. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I fixed the issue by going to the ApplySynchroniseChildren method in MixerState.cs and replacing the middle for loop:
    Code (CSharp):
    1. for (int i = 0; i < childCount; i++)
    2. {
    3.     if (i < flagCount && !_SynchroniseChildren[i])
    4.         continue;
    5.  
    6.     var state = childStates[i];
    7.     if (!state.IsValid())
    8.         continue;
    9.  
    10.     var weight = state.Weight;
    11.     if (weight == 0)
    12.         continue;
    13.  
    14.     var length = state.Length;
    15.     if (length == 0)
    16.         continue;
    17.  
    18.     totalWeight += weight;
    19.  
    20.     weight /= length;
    21.  
    22.     weightedNormalizedTime += state.Time * weight;
    23.     weightedNormalizedSpeed += state.Speed * weight;
    24. }
    Let me know if that works for you.
     
    craigjwhitmore likes this.
  35. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    135
    That seems to work fine, thank you.
     
  36. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Animancer v4.4 is now up on itch.io and should be approved for the Asset Store in the next few days. It has some significant bug fixes for Layers and Mixers as well as a few Inspector improvements for Mixers.
     
  37. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,771
    Hiya!
    Just found Animancer and I'm really tempted to check it out because Mechanim is crushing my love for animation. One thing though, how did you make your transform component look so useful :) ?
    Screen Shot 2020-03-27 at 12.58.35 pm.png
     
  38. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
  39. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,771
    Awesome! Grabbing it now :D
    Really excited about checking out Animancer, one thing that worries me though is I use a mirror a lot in my current project. Instead of having the option to mirror with a parameter (as in Mecanim) would I have to set up mixers for those clips?
     
  40. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Unfortunately the Playables API doesn't have a way to mirror animations at runtime so you need to do it in the animation import settings.
     
  41. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,771
    Yeah I reckon I could automate that though a script in Unity or on export in Houdini. I'll grab Animancer and just have a play around :)
     
  42. Razziel

    Razziel

    Joined:
    Nov 1, 2016
    Posts:
    7
    A small suggestion:
    On the extension method "animator.GetOrAddAnimancerComponent" I think you should also set "animator.runtimeAnimatorController = null;"
     
    Kybernetik likes this.
  43. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    135
    I'm trying to use a
    Float2ControllerState
    blend tree using the mixer example I mentioned earlier, but am having issue making it work.

    Essentially, I'm not sure how Blend Tree's should be initialised for use in Mixer States.

    When FixedUpdate runs, the line;
    unarmedLocomotionBT.State.Parameter = movement; 
    the State variable is Null.

    Here's my code.

    Code (CSharp):
    1. public sealed class LocomotionState : CreatureState
    2. {
    3.     /************************************************************************************************************************/
    4.     [SerializeField] private Float2ControllerState.Transition unarmedLocomotionBT;
    5.     [SerializeField] private Float2ControllerState.Transition greatSwordLocomotionBT;
    6.     private LinearMixerState movementMixer;
    7.  
    8.     [SerializeField, Range(0, 1)] private float blend;
    9.  
    10.     private float currentHorizontalSpeed = 0;
    11.     private float currentForwardSpeed = 0;
    12.     /************************************************************************************************************************/
    13.  
    14.     private void Awake()
    15.     {
    16.         movementMixer = new LinearMixerState();
    17.         movementMixer.Initialise(2);
    18.  
    19.         movementMixer.SetChild(0, unarmedLocomotionBT.CreateState());
    20.         movementMixer.SetChild(1, greatSwordLocomotionBT.CreateState());
    21.     }
    22.  
    23.     private void OnEnable()
    24.     {
    25.         Creature.Animancer.Play(movementMixer);
    26.     }
    27.  
    28.     private void FixedUpdate()
    29.     {
    30.         if (Creature.CheckMotionState())
    31.             return;
    32.  
    33.         Creature.UpdateSpeedControl();
    34.  
    35.         currentHorizontalSpeed = Mathf.Lerp(currentHorizontalSpeed, Creature.HorizontalSpeed, smoothing);
    36.         currentForwardSpeed = Mathf.Lerp(currentForwardSpeed, Creature.ForwardSpeed, smoothing);
    37.  
    38.         Vector2 movement = new Vector2(currentHorizontalSpeed, currentForwardSpeed);
    39.  
    40.         // NullReferenceException: Object reference not set to an instance of an object
    41.         unarmedLocomotionBT.State.Parameter = movement;     //State parameter is Null
    42.         greatSwordLocomotionBT.State.Parameter = movement;  //State parameter is Null
    43.  
    44.  
    45.         if (!Creature.Brain.IsStrafing)
    46.             UpdateRotation();
    47.         UpdateAudio();
    48.     }
    49. }
    50.  
     
  44. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    You need to call unarmedLocomotionBT.Apply on the created state for it to set the State property. I'm thinking I'll change the CreateState method to set it as well.
     
    craigjwhitmore likes this.
  45. ve110cet

    ve110cet

    Joined:
    Dec 11, 2017
    Posts:
    10
    Hey there!
    We're trying to use Animancer with an asset store package called Chronos that rewinds, slows, speeds up, etc game objects (including the Animator component). It uses the Animator recording functions like StartRecording, StartPlayback, etc., and it doesn't seem to work with Animancer. Any ideas?
     
  46. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Those functions probably don't work with the Playables API so there's likely nothing I can do about it.

    But if you have any access to the other data Chronos is recording it should be possible to store the relevant details of the Animancer states (time, speed, and weight).
     
  47. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    135
    Thanks, apply works great.
     
    Last edited: Apr 1, 2020
  48. Aezoc

    Aezoc

    Joined:
    Jan 19, 2020
    Posts:
    8
    I've been struggling with this animation event problem for a few days, and I'm hoping there's a simple solution that I'm missing. I have a ScriptableObject with a bunch of ClipState.Transitions that define an animation set. I have multiple actors in my game referencing this set of animations. Each ClipState.Transition has events defined on it, but the list of event handlers is empty. The goal is that each actor will plug in its own event handlers; so at design time I've created a transition representing "shoot a rifle" and created an event at the point in the animation where the recoil happens, but at runtime two actors using different guns might play that Transition and attach different event handlers to their respective AnimancerStates (which trigger different sounds, particle effects, and so on). When an actor plays the transition, the code looks like:

    Code (CSharp):
    1. public IEnumerator Execute(ClipState.Transition transition, ...)
    2. {
    3.    var state = animancer.Play(transition);
    4.    state.Events.SetCallback(0, () => AnimationEventHandler(...));
    5.    state.Events.OnEnd = () => AnimationEndHandler(...);
    6.    yield return state;
    7. }
    This works great as long as one actor plays the transition at a time. When two actors' firing animations overlap, my AnimationEventHandler method starts getting called twice for the actor that started second. My expectation was that the actors could share a ClipState.Transition and - as long as event handlers were set on the AnimancerStates created by playing it - they would operate independently from one another. That seems to not be the case though.
     
  49. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    In my own games I work around that issue by having each creature call
    scriptableObject = Instantiate(scriptableObject);
    on startup so they no longer share the same reference. It solves the problem but wastes a bunch of RAM for all the stuff that doesn't actually need to be unique per creature so I'm not particularly satisfied with that solution, I just haven't come up with anything better.

    Another possibility you might be able to work with is giving them all the same callbacks and using
    AnimancerEvent.CurrentState
    to access the triggering state during the event.
     
    Last edited: Apr 4, 2020
  50. onefoxstudio

    onefoxstudio

    Joined:
    Sep 28, 2016
    Posts:
    191
    I'm using mixer to play along with smooth transitions and stopping when an action occurs (like the Character is coming to a stop to play a climb animation).

    Is it a prope way to do it ? Or what's best practice here ?

    Thanks !

    BTW: The animancer preview window is Pink when you are using URP.



    Code (CSharp):
    1. using Animancer;
    2. using UnityEngine;
    3.  
    4. public sealed class LocomotionAnimation : MonoBehaviour
    5. {
    6.     [SerializeField] private AnimancerComponent _Animancer;
    7.     [SerializeField] private LinearMixerTransition _Mixer;
    8.     [SerializeField] private float transitionTime = 0.25f;
    9.  
    10.     private LinearMixerState _State;
    11.  
    12.     [SerializeField]
    13.     private ClipState.Transition _testAnimation;
    14.  
    15.     private void Awake()
    16.     {
    17.         if (_Animancer == null)
    18.             _Animancer = GetComponent<AnimancerComponent>();
    19.     }
    20.  
    21.     private void OnEnable()
    22.     {
    23.         _Animancer.Play(_Mixer, transitionTime);
    24.         _State = _Mixer.Transition.State;
    25.     }
    26.  
    27.     private void Update()
    28.     {
    29.         if (Input.GetKeyDown(KeyCode.E))
    30.         {
    31.             // Slowdown
    32.             Speed = 0f;
    33.             // Chain
    34.             _Animancer.Play(_testAnimation, 0.5f).Events.OnEnd = () => OnEnable();
    35.         }
    36.     }
    37.  
    38.     public float Speed
    39.     {
    40.         get { return _State.Parameter; }
    41.         set { _State.Parameter = value; }
    42.     }
    43.  
    44. }