Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Animancer - Less Animator Controller, More Animator Control

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

  1. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    every time I need to invoke a callback at the end of an animation I always get 2 warnings: End of animation not triggered and Sequence should not be modified. I eventually came up with a solution to prevent those warnings from showing up but what are your thoughts? Is there a more correct way to achieve this? Thanks


    Code (CSharp):
    1. public void PlayClipCallback(ClipTransition animation, Action callback) {
    2.             var state = _baseLayer.Play(animation, 0.1f);
    3.  
    4.             var newSequence = new AnimancerEvent.Sequence(state.Events);
    5.  
    6.             newSequence.OnEnd = () => {
    7.                 callback();
    8.                 state.Events.OnEnd = null;
    9.             };
    10.  
    11.             state.Events = newSequence;
    12.         }
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    That's a very inefficient way of doing it. Both warnings explain why they're happening and how to disable them, so if you're aware of the behaviour they're warning about and still want to do what you're doing, just disable the warnings.
     
  3. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    Sorry, I'm still a beginner. The solution above was provided by AI and has been the only solution so far that allows for an animation to play with a callback once and without warnings. Other solution I've tried were typing in exactly what you had written in the manual examples. This either results in the warnings or the callback being called endlessly. I read the warnings and understand I can disable them (which I have in past projects) but I just feel that the warnings are there for a reason. That something is not right. I want to use end event to signal a callback quite a bit in my project. I've read through the manual as best as a could. I'm just unsure how to write it with the goal of playing an animation, invoking a callback at the end of the animation, only calling it once, and no warnings. Thanks again
     
  4. ratking

    ratking

    Joined:
    Feb 24, 2010
    Posts:
    352
    Please do not write "I came up with" if actually ChatGPT wrote the code.
     
  5. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    huh? I wrote "The solution above was provided by AI" which credits the AI and "Other solution I've tried were typing in exactly what you had written in the manual examples" which indicates I've been reading through the documentation. Where did "I came up with" come from? Also I wrote "Sorry, I'm still a beginner" which also indicates I'm attempting to figure out a good solution at my current level by asking questions to the developer, reading the docs, researching in this forum, and sourcing out to AI.
     
  6. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    ratking is correct that you said:
    Without any mention of AI in that post. But that's not important.

    If you aren't using the event to end the animation and you don't want it to be triggered every frame, just use a regular event instead of the End Event:
    transition.Events.Add(1, callback)
    .

    As I explained in this post, you should generally assign the events for a transition only once on startup rather than every time you play it. That's why you're getting the "Sequence should not be modified" warning.
     
  7. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    I think I get it! Something like this?


    Code (CSharp):
    1. public class MeleeAbility : Ability {
    2.  
    3.         public MeleeAbility() {
    4.             _animation.Events.Add(1, ResetAbility);
    5.         }
    6.  
    7.         public override void Activate() {
    8.             _animationHandler.PlayClip(_animation);
    9.         }
    10.  
    11.         public void ResetAbility() {
    12.              Debug.Log("Reset Ability");
    13.         }
    14. }
    15.     }
     
  8. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Something like that, though the _animation field wouldn't be initialized yet in the constructor if it's a serialized field. If so, you would probably need to implement ISerializationCallbackReceiver.
     
  9. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    Trying to apply this to a damage animation and transition to DamagedState. I establish the callback in the constructor. When the character is damaged, HandleDamaged is called. This plays the damaged animation and sets the bool to allow the state change. OnAnimationEnd causes the state to transition back to locomotionState. This works. Problem now is if the character gets hits again while still in the middle of the damaged animation.

    1. How do I ensure the damaged animation plays from the start every time it is called
    2. How do I ensure OnAnimationEnd gets called on subsequent plays of damage animation. Right now, if the character gets hit more than once, then OnAnimationEnd does not fire

    Thanks!

    Code (CSharp):
    1. public class Controller(ClipTransition animation) {
    2. _animation = animation;
    3. _animation.Events.Add(_animation.Events.NormalizedEndTime, OnAnimationEnd);
    4.  
    5. public void ConfigureStatemachine() {
    6. Any(damagedState, new FuncPredicate(() => IsDamaged()));
    7. At(damagedState, locomotionState, new FuncPredicate(() => !IsDamaged()));
    8. }
    9.  
    10. private bool IsDamaged() => _isDamaged;
    11.  
    12. public void HandleDamaged() {
    13. _isDamaged = true;
    14. _animationHandler.PlayClip(_animation);
    15. }
    16.  
    17. private void OnAnimationEnd() {
    18. _isDamaged = false;
    19. }
    20.  
     
  10. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    1. FadeMode.FromStart. Since you're using a transition, you just need to enable its Start Time in the Inspector.
    2. That's the main reason why End Events get triggered every frame, so if you end up in a situation where you're already past the end time then at least the event will still get triggered. But if you fix it to properly restart the animation it shouldn't be an issue any more for your regular event.
     
  11. alphdevcode

    alphdevcode

    Joined:
    Nov 10, 2020
    Posts:
    9
    Hey, is there a way to set up a
    DirectionalMixerState
    in the inspector like you do with
    LinearMixerTransition
    ? I can't see it in the Inspector, even if I decorate it with the
    SerializeField
    attribute.

    Basically, what I'm looking for is the proper way to set up the equivalent to a 2D blend tree.

    Thanks in advance!
     
  12. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    MixerTransition2D
    is what you're looking for.
     
    alphdevcode likes this.
  13. s_marcell

    s_marcell

    Joined:
    Mar 22, 2018
    Posts:
    20
    Hi!
    Animancer lite sometimes gives me the warning message
    Fade Duration != 0 or 0.25
    while the code it's warning me about is
    worker.animancer.Play(worker.animations.Idle, 0.25f);
    Am I missing something?
     
  14. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    That should be fine. Could you please send a minimal reproduction project to animancer@kybernetik.com.au so I can take a look at it?
     
  15. giraffe1

    giraffe1

    Joined:
    Nov 1, 2014
    Posts:
    310
    Hi,

    I am trying to implement stop animations.

    Is there any suggestions on how to implement this so it blends better? Currently, sometimes it perfect and other times it does like a skip/foot slide. Please see video I made:



    This is how I implement it in my code. Very basic check to figure out if left foot is above or not and trigger 1 of 2 animations.

    Code (CSharp):
    1. public ClipTransition walkStopLU;
    2. public ClipTransition walkStopRU;
    3.  
    4. void PlayWalkStopLU() => animancer.Play(walkStopLU);
    5. void PlayWalkStopRU() => animancer.Play(walkStopRU);
    6.  
    7. bool IsLeftFootAbove() => animator.GetBoneTransform(HumanBodyBones.LeftToes).position.y > animator.GetBoneTransform(HumanBodyBones.RightToes).position.y;
    Code (CSharp):
    1. void OnStop()
    2. {
    3.     if (IsLeftFootAbove())
    4.         PlayWalkStopLU();
    5.     else
    6.         PlayWalkStopRU();
    7. }
     
  16. darkriver41

    darkriver41

    Joined:
    May 5, 2019
    Posts:
    7
    Maybe i am wrong, but this looks like a timing issue, meaning when your character stops moving, the walk cycle ends with, say, the left foot at a position a bit away from where it should be for the start of the left foot stop animation so maybe the blending makes it look like it is sliding, and i think that's why its random, sometimes sliding and sometimes looking good
     
    giraffe1 likes this.
  17. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Yeah, it looks like your mixer's walk cycle just isn't at a good place to transition into the slowing down animation. I've never implemented something like that before, but in theory you could put the slow down animations into a linear mixer where you feed in the movement mixer's
    NormalizedTime % 1
    as the Parameter so it can blend between the slow down animations as appropriate for any point in the walk cycle. I suspect you would need at least two more slow down animations to get good coverage of the possible values and you might also want to start the slow down a bit earlier so it has more time to work with.
     
    giraffe1 likes this.
  18. Renegade_Wolf

    Renegade_Wolf

    Joined:
    Jan 17, 2022
    Posts:
    49
    What's the best way to capture a moment of one animancer into another? I've tried grabbing a clip and a time, but am not sure how to stop the animation at that point without disabling the animancer component and as far as I can tell, doing that in the same frame prevents the animancer from animating entirely. Further, the rotation doesn't seem to get passed, although that's something I can probably work around - still, since I only want to mess with aesthetics, I'd rather use a way that doesn't involve rotating the object (if that method exists).

    Not a huge deal if not, just want to know the best way of handling this
     
  19. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Try something like this:
    Code (CSharp):
    1. animancerComponent.Playable.CopyFrom(otherAnimancerComponent);
    2. animancerComponent.Playable.PauseGraph();// Need to unpause if you ever want it to play normally again.
    3. animancerComponent.Evaluate();// Force one update with 0 delta time since it won't otherwise update while paused.
     
  20. Renegade_Wolf

    Renegade_Wolf

    Joined:
    Jan 17, 2022
    Posts:
    49
    Hmm, I don't seem to have Playable.CopyFrom()...
     
  21. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    I totally forgot I hadn't implemented that yet in the last release. If you send your Invoice Number to animancer@kybernetik.com.au I'll send you the updated package with that feature in it.
     
  22. giraffe1

    giraffe1

    Joined:
    Nov 1, 2014
    Posts:
    310
    Hi,

    This is my setup. Linear Mixed for controlling the speed. And the child 2d mixers hold the walk and run blends.

    Linear Mixer Transition Asset(Parent)
    ---------> Mixer Transition 2D Asset (Child)
    ---------> Mixer Transition 2D Asset (Child)

    How do I access the Parameters of the child mixers from code?
     
  23. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    giraffe1 likes this.
  24. PascalPieper

    PascalPieper

    Joined:
    Sep 14, 2018
    Posts:
    4
    Hi, thanks for this great Asset, I'm very much enjoying the workflow.
    I wanted to write an editor script that automatically moves the End Event to a specific time. Unfortunatly, when I change the End Event through code this change is not reflected in the Inspector and the Event is still in it's old spot. When I touch the slider, it snaps into the position that I specified. I've looked into the Propertydrawer, but wasn't able to make it work. Would you be so kind as to give me a hint how I could implement this?

    Many thanks!
     
  25. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Can you post your code (or email it to animancer@kybernetik.com.au)? It's hard to guess what you're doing wrong if I don't actually know what you're doing.
     
  26. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Hey everyone, it's time for a progress update on Animancer v8.0:
    • The Change Log is now up. Obviously I'll keep adding to it as I work, but all the major features are there.
    • This will be a paid update. Anyone who buys Animancer Pro after today will be able to upgrade for free. Anyone who bought it before that can upgrade with a 50% discount. The Upgrade Guide has more details.
    • Feedback is welcome, particularly regarding the changes to Animancer Events.
    • If anyone has an idea where I could go to get a trailer video made, please let me know. The current one isn't great and will need to be updated for the new features anyway, so I figure now is a good time to look into getting one made professionally.
     
    eventropy likes this.
  27. eventropy

    eventropy

    Joined:
    Oct 4, 2012
    Posts:
    258
    I read that Animancer is slightly faster than unity's current animation offerings. What about compared to an ECS based animation system like Rukhanka, for a scene with many different animated characters?
     
    Last edited: May 2, 2024
  28. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    I don't know how the performance compares to any ECS/DOTS system. Those systems are likely heavily focussed on performance so I would likely expect them to be faster, but since they aren't building on top of something like the Playables API it's hard to know how good their developers actually are at optimizing compared to Unity's.
     
    eventropy likes this.
  29. emcom-ai

    emcom-ai

    Joined:
    May 6, 2022
    Posts:
    10
    I'm going from playing a MixerTransition2DAsset.Unshared to playing a ClipTransition by just using the Play method of my base layer. I narrowed it down to the conditional at line 740-741 of AnimancerLayer. It hits the second condition here. I'm guessing the weight should not be 0 since going in the other direction, the transition fades fine and the weight is 1 at this line. Any thoughts as to what I might be doing wrong? Seems I'm not handling layers properly.
     
  30. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    The Index and Weight on that line are the layer's values, not the state's.

    The only time the base layer's Weight should ever be 0 on its own is before you've played anything at all so the only way it could get there after that is if you intentionally faded the base layer to 0. I'm not sure why you would be doing that, but if so you can just disable
    animancerComponent.Playable.SkipFirstFade
    to break the first condition on that line.
     
  31. emcom-ai

    emcom-ai

    Joined:
    May 6, 2022
    Posts:
    10
    I forgot to mention the issue I'm having is the animation snapping instead of fading but I think you figured that out. But I'm not doing anything special, just calling Play on the base layer for the transitions mentioned in my post. I've attached a video of the Animancer output for a simple "wander and look" behaviour where the agent walks to a random spot then plays a random looking animation. Going from the locomotion to the looking is where it snaps, but looking to locomotion fades fine. There is also the yellow warning symbols on the locomotion state which seems suspicious but I'm not sure how to determine what those mean.

     
  32. retired_unity_saga

    retired_unity_saga

    Joined:
    Sep 17, 2016
    Posts:
    296
    Hello, great asset

    small question:
    https://kybernetik.com.au/animancer/docs/examples/fine-control/solo-animation/

    shows this solo animation

    my objects in my game are a series of transform (no bones), and I just remembered I own this asset and it saves me the trouble of writing most of the animation myself

    but in the workflow, am I better suited to extending Solo Animation class, and just make a MultiAnimation:SoloAnimation type? or just remember to remove avatars and slap the animator on the root or base root of the series of transforms and code work as described in the quick play section of the documentation?
     
  33. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    @emcom-ai Would you be able to make a minimal reproduction project and send it to animancer@kybernetik.com.au so I can take a look at it? I can't see anything in the video that looks like it should be able to go through the second line of that if statement.

    @the_unity_saga The easiest thing to do would be to just use an AnimancerComponent. You might be able to get slightly better performance by inheriting from SoloAnimation and implementing support for multiple animations yourself if you don't need any of Animancer's features like fading or Animancer Events, but that would take a lot more effort.
     
    retired_unity_saga likes this.
  34. emcom-ai

    emcom-ai

    Joined:
    May 6, 2022
    Posts:
    10
    I figured it out. I'm using states and I was calling Stop() on the layer when exiting the state that does the locomotion. I added that at one point to fix something else but don't need it anymore. Thanks for taking a look. Are those yellow warning symbols anything I need to worry about?
     
  35. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
  36. emcom-ai

    emcom-ai

    Joined:
    May 6, 2022
    Posts:
    10
    Thank you. I now see what is causing that and it's an easy fix.
     
  37. ksamksamksam

    ksamksamksam

    Joined:
    Oct 27, 2020
    Posts:
    2
    Hi there,

    I have a question; I'm sorry if it's been asked before. When I use AnimancerLayer.Play(AnimationClip), I noticed that the layer continues to "play" even after the clip is over. If I want to play a different clip on the same layer I need to call Animancer.Stop() first. Is there a way to have the layer automatically stop playing when the clip is over?
     
  38. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Play will automatically stop the previous animation as demonstrated in all of the examples involving multiple animations. There are very few situations where you would need to manually call Stop.
     
  39. UNANA2048

    UNANA2048

    Joined:
    Aug 28, 2017
    Posts:
    1
    Hello.
    I understand that the Animancer Pro is currently on sale.
    I bought Animancer Pro before May 2024, but if I buy it again in this sale, will I get a free update to 8.0?
     
  40. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Yes.

    upload_2024-5-7_13-39-53.png

    I've updated the main Change Log page too because a few people have asked the same question.
     
    hopeful and UNANA2048 like this.
  41. ksamksamksam

    ksamksamksam

    Joined:
    Oct 27, 2020
    Posts:
    2
    Sorry, I misspoke. I actually meant when I am trying to play the same animation again.

    Edit to add: I also am interested in querying the state of a layer and whether it is currently playing an animation. But the layers seem to return "true" to "IsAnyStatePlaying" even if the animation is over.
     
    Last edited: May 9, 2024
  42. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    In that case, FadeMode.FromStart is what you're looking for.

    If you want to check if the current state's time, you can check if
    layer.CurrentState.NormalizedTime >= 1
    or you might want to use End Events.
     
  43. Berkaycs

    Berkaycs

    Joined:
    Jun 22, 2023
    Posts:
    3
    Hi, when I use the different layers & avatar-mask for the idle animations based on the various weapons, the player starts within the ground and does not stop even I don't move the controller. Here's the video ->
     
  44. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    Take a look at that warning in the Inspector. You have a masked layer controlling part of the body but nothing playing on the base layer to control the rest of the body.

    Then after that you have a bunch of movement animations on the base layer but no idle. If you want it to stop moving you need to tell it to play an idle animation like in the Basic Movement Example.
     
    Berkaycs likes this.
  45. BobekTrobek

    BobekTrobek

    Joined:
    Apr 28, 2022
    Posts:
    1
    Hello, I am trying to implement a sword combo system. To do that I need to check if the player is clicking while the first slash animation is transitioning to the idle animation. I just need a function that runs every frame while a certain animation is transitioning to a different animation. Is there something like this implemented in Animancer? If not is there a workaround for this problem? By the way I am using the lite version, and if I create the prototype I'll buy the full version because so far the asset has been really helpful.
     
  46. giraffe1

    giraffe1

    Joined:
    Nov 1, 2014
    Posts:
    310
    *********************** SOLVED **************************************
    I looked at your layers example. Using StartFade on the upperbody layer to stop shooting works well.

    Any ideas what I am doing wrong?




    Anim.png Controller.png

    Code (CSharp):
    1. using Animancer;
    2. using UnityEngine;
    3.  
    4. public class AnimationManager : MonoBehaviour
    5. {
    6.     private AnimancerComponent animancer;
    7.  
    8.     [SerializeField]
    9.     private AvatarMask upperBodyMask;
    10.  
    11.     private AnimancerLayer baseLayer;
    12.     private AnimancerLayer upperBodyLayer;
    13.  
    14.     void Awake()
    15.     {
    16.         animancer = GetComponentInChildren<AnimancerComponent>();
    17.         baseLayer = animancer.Layers[0];
    18.         upperBodyLayer = animancer.Layers[1];
    19.         upperBodyLayer.SetMask(upperBodyMask);
    20.     }
    21.  
    22.     public void PlayBase(ITransition transition) => baseLayer.Play(transition);
    23.     public void PlayUpperBody(ITransition transition) => upperBodyLayer.Play(transition);
    24.  
    25.     public void FadeOutUpperBody() => upperBodyLayer.StartFade(0f);
    26.  
    27.     public AnimancerLayer GetBaseLayer() => baseLayer;
    28.     public AnimancerLayer GetUpperBodyLayer() => upperBodyLayer;
    29. }
    Code (CSharp):
    1. using Animancer;
    2. using UnityEngine;
    3.  
    4. public class ShootAction : MonoBehaviour
    5. {
    6.     private AnimationManager animationManager;
    7.  
    8.     public ClipTransition shootClip;
    9.  
    10.     void Awake()
    11.     {
    12.         animationManager = GetComponent<AnimationManager>();
    13.         AnimancerLayer upperBodyLayer = animationManager.GetUpperBodyLayer();
    14.         upperBodyLayer.GetOrCreateState(shootClip);
    15.     }
    16.  
    17.     public void Execute(bool shoot)
    18.     {
    19.         if (shoot)
    20.         {
    21.             if (!this.enabled)
    22.             {
    23.                 this.enabled = true;
    24.                 animationManager.PlayUpperBody(shootClip);
    25.             }
    26.         }
    27.         else
    28.         {
    29.             if (this.enabled)
    30.             {
    31.                 shootClip.State.Stop();
    32.                 this.enabled = false;
    33.             }
    34.         }
    35.     }
    36. }



    Anim.png Controller.png
     
    Last edited: May 25, 2024
  47. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,707
    Just curious ... what were you doing wrong?
     
  48. giraffe1

    giraffe1

    Joined:
    Nov 1, 2014
    Posts:
    310
    line 38 in ShootAction.cs
    Code (CSharp):
    1. shootClip.State.Stop();
    should be

    Code (CSharp):
    1. animationManager.FadeOutUpperBody();
    Stopping the clip is not the correct way of handling animations when using layer masks to play animations. Fading out the layer weight is the proper way to do it.
     
    hopeful likes this.
  49. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,592
    @BobekTrobek The Weapons Example demonstrates how I'd approach that sort of thing. Or if you don't want to use a full state machine and don't want to just use a MonoBehaviour, you could implement an IUpdatable class.

    @giraffe1 That's the correct solution. I've added warnings about that to the Inspector in Animancer v8.0 to make it more obvious.
     
  50. giraffe1

    giraffe1

    Joined:
    Nov 1, 2014
    Posts:
    310
    I have another question.

    This is my blend tree for movement. Just curious how you would go about detecting if Rifle_SprintLoop is playing or being blended and what percent?

    Since, I am supplying the xy parameter to the mixer. I am just checking for y > 0.8 and it seems to be pretty reliable so far.

    Untitled.png
     
    Last edited: May 26, 2024