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. AnemicPizza

    AnemicPizza

    Joined:
    Aug 17, 2017
    Posts:
    6
    Hello I'd like some input on the best practice to implement this.

    Goal: Multi-Hit Combo, rotation can change for each attack.
    Example: If attacking Top-Right direction on Combo-Hit 1, I can hold direction bottom-left, press Combo-Hit 2 and it'll auto turn the character while doing the 2nd hit in the combo in that direction.

    I got the combos working via the Weapons example, unsure on best practice to implement rotate on hit.
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I'm not sure exactly what you mean, but couldn't your attack state just store the target rotation and use Quaternion.RotateTowards in Update to rotate towards it?

    What are you actually trying to rotate and what potential issues are you concerned about?
     
  3. AnemicPizza

    AnemicPizza

    Joined:
    Aug 17, 2017
    Posts:
    6
    Wow fast response, essentially what I'm trying to rotate is the PlayerCharacter.

    I'd like to rotate the character to a new direction on each Combo State 1,2,3 etc.
    Example:
    I hold the movement direction to the "Right" and attack, so the player does their first attack to the "Right"
    while the first Attack is animating
    I'm holding "Left" in the movement direction
    I press the attack button again to enter the 2nd attack in the combo
    The Player will auto rotate to the "Left" and animate the 2nd attack animation.

    From Example 06 State Machines - Weapons
    - If spamming attack button, the combo works
    - But in order to change Player rotational direction, the Player can't be in an Attack Animation
    - Player rotation only changes Before or After an Attack Combo
    - Looking for some time window to rotate Player in between Combo Attacks

    Apologies if that's not clear.
    I'll take another look into it, should be simple, I'm still new to Animancer.
     
    Last edited: May 18, 2021
  4. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    The Weapons example handles its character's rotation in the LocomotionState.UpdateTurning method so you'll likely want something similar in your attack state, but instead of rotating towards the current Creature.Brain.MovementDirection every frame you'll probably want to give the brain an AttackDirection property which you set when the brain attempts to attack so you can rotate towards that instead.
     
    AnemicPizza likes this.
  5. AnemicPizza

    AnemicPizza

    Joined:
    Aug 17, 2017
    Posts:
    6
    Just wanted to update.
    Modified AttackState with a modified version of the UpdateTurning method from the LocomotionState.

    Thanks, I got my desired effect with exactly what you recommended. Also really appreciate Animancer, it's definitely making A LOT of things MUCH easier. Will be leaving a 5/5 review soon in the Unity Store.
     
    Kybernetik likes this.
  6. Sipel

    Sipel

    Joined:
    Jan 13, 2015
    Posts:
    4
    Hello,
    I'm converting my project to animancer and I was wondering if what I'm doing is a good practice or not.
    Essentially I have built a system that prioritizes some player actions and I want to avoid processing less prioritized actions. I've written a snippet to make the example more clear.
    What I wanted to know is if I have to check if the ClipState (_animancerState) is already playing (like the commented version), or if it's fine to just call Play without checking. I was wondering if this could create garbage, or more bugs in the future.
    Code (CSharp):
    1.  
    2. private void ApplyEvasion(){
    3.        // if (_animancerState == null || !_animancerState.IsPlaying)
    4.             //     _animancerState = (ClipState) _animancer.Play(_animancerTransition);
    5.        _animancerState = (ClipState) _animancer.Play(_animancerTransition);
    6.        return _animancerState.IsPlaying && (_animancerState.NormalizedTime <= 1 || _animancerState.IsLooping);
    7.  
    8. private void Update(){
    9.        if(EvasionInput && ApplyEvasion()){return;}
    10.        if(AttackInput && ApplyAttack()){return;}
    11. }
    12.  
    13. }
    14.  
     
  7. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Passing an AnimationClip or a transition into the Play method makes it do a dictionary lookup to find the state so it's not free, but it's pretty efficient. You might be able to come up with something slightly faster by comparing your stored state to the _animancer.States.Current, but I wouldn't expect any performance issues to come from that bit of code anyway.

    Also, checking _animancerState.IsPlaying right after calling Play is pointless because it will definitely be true.
     
    Sipel likes this.
  8. nobluff67

    nobluff67

    Joined:
    Nov 3, 2016
    Posts:
    338
    @Kybernetik I have the pro version, but am stuck deciding on which method to use (directional or linear) for NPC's.

    I have using animancer strictly for animations. I am also using puppetmaster, which I have working correctly, except that the blending doesn't work well with the animancer method I am using, hence the decision to go with directional or linear mixing for better blending between puppetmaster/animancer driven getup's and other animations driven purely by animancer (idle/walk).

    The NPC's at this stage have very basic animations (idle, walk fwd, run fwd), so it seems like linear will be fine, however if I add strafe, can linear still handle this or should I in this case move toward the directional mixer? (My main question)

    I have gone through the directional example but I find your coding practices quite advanced for my skill level, so am struggling with all your codea, is inherited from codeb, which is inherited from codec scenarios (spiderbot example). I know you do it for reusability, but I find it hard to follow, so I find that I am spending more time understanding how you code, rather than using the asset.
     
  9. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Directional would most likely be better. I wouldn't expect to get a very good result by trying to use a linear mixer to allow strafing in any direction.
    Not reusing code between examples would simplify some things, but also makes them harder to maintain. If I change something or fix a bug in one example, I'd then need to find every other example with an identical script to make the same change there and any inconsistencies that I miss can confuse users as well.

    In a game complex enough to involve directional blending, you'll very likely have to deal with things that are much more convoluted than a bit of inheritance. If there's a specific part you're struggling with I'd much rather you tell me so I can try to improve my explanations rather than just giving up and not trying to teach good programming practices at all.
     
    nobluff67 likes this.
  10. nobluff67

    nobluff67

    Joined:
    Nov 3, 2016
    Posts:
    338
    Directional it is, thanks for the clarification.

    if I clutter up the thread too much with questions/explanations, let me know and I’ll send questions via email.
     
  11. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    Hi, I'm just starting out with Animancer and so far I'm loving the flexibility it gives me as opposed to Mecanim.

    I'm running into the following issue though: I want to set up and control all my animations completely with Animancer, so I've only set up the Animator Controller as described in the manual, without any states in it.
    Now I have an Idle animation that I play with Animancer and it works fine. My Walking animation however results in parts of my model (child transforms) being moved to weird positions during the animation. This behaviour doesn't occur if I place an entry state in my Animator Controller with my Idle animation in it. Does anyone know why this is happening?
     
  12. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    @nobluff67 You can also use Github Issues which makes things easier for me to organise and keep track of.

    @theghostronaut I can't think of anything that would cause a problem like that off the top of my head. Can you post your code and some screenshots?
     
  13. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    I will get back to you, maybe it has something to do with how my model is layed out and possibly due to my usage of Pivot Modder to change pivot positions on the child transforms ... will have to investigate and get back to you. Thanks!
     
  14. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    Allright, I redid the entire setup for my character and didn't use Pivot Modder this time. Still the same behavious.

    Here's a recording of what happens when I switch from Idle state to Walking (simple call of _Animancer.Play(_Walking, 0.25f):


    As you can see, part of the model is being transformed to a different position while the animation is playing.
    If I turn off the Crossfade, this doesn't happen, but then the legs sometimes get stuck in the walking pose when returning to the Idle state, seen here:


    Any idea what could be happening here?

    Edit:
    I just noticed, if I check the "is Additive" button in the Animancer inspector settings at runtime, the transform offset also happens during the Idle animation:



    Edit2:

    Here are the animations playing normally in the editor, as they should at runtime:
     
    Last edited: May 21, 2021
  15. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    My first guess would be that the Native Animator Controller is interfering with it.

    I'm not sure what Rig type you're using, but if it's a Humanoid you won't be able to blend between the Animator Controller and Animancer as explained here (it can swap between them, but won't blend the transition properly).

    If you're using a Generic Rig, see if the same thing happens with just those animations in Animancer but no Animator Controller. If it does, see if it still happens if you play those animations in an Animator Controller without Animancer.
     
  16. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    Thanks for getting back to me so quickly.
    It's a generic rig and I don't have any states in my Animation Controller; I've set up a new, blank one because the Animancer component seems to require an Animator component? If I remove it, I get an error message.

    Anyways, when I play the animations in the Animator Controller directly, everything works.
     
  17. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Animancer requires an Animator component, but not an Animator Controller. Having it there with no states could well be the cause of the problem.
     
  18. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    Ah, my bad. I misread that part in the instructions. I need the Animator component, but I don't need to assign an actual Controller asset. Totally makes sense! Removing that seems to fix the issue. How stupid of me ;-) Thank you so much for the support.
     
  19. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I'll see if I can add a warning for that scenario in the next version.

    Would you mind checking what happens if you give it an Animator Controller that does have states but still play your animations with Animancer? I just want to make sure the issue was actually the fact that the Animator Controller was empty.
     
  20. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    It still happens even if there are states without animations in them present in the Controller. The only thing that "fixes" the issue is if I place my Idle animation into the starting state. Although I'm not sure what issues that might cause down the road.

    I have an additional question: I'm calling the _animancer.Play() method inside my player states, which are handled in Update. So when in a specific state, the method gets called every frame. Is it necessary to check if a state's animation is already playing and therefore not call the Play() method again? Or is Animancer already doing that behind the scenes? I don't see any issues with the animations, everything runs perfectly; but I was wondering if it would be better not to do it like that.

    Before I was using Animancer, I actually switched to each state animation with a Setter on the variable I used for the actual state change, by setting all animator controller parameters that didn't match the playerState.ToString() to false and the one that did match to true (the parameters had the exact same names as the player states). That way the animation would only get triggered once on the actual state change. I would prefer doing it like that with Animancer as well, but that would require me to get the corresponding animation clip matching a state. I don't want to use the Named Animancer Component, so I can't pass a string like I did before. Maybe there is a way around that to? I hope I'm making sense.
     
  21. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Would you mind sending your model, Animator Controller, and a few animations to animancer@kybernetik.com.au so I can take a look at it? I tried to replicate the issue with the Spider Bot model from the examples but it doesn't seem to have the same problem.
    Calling Play repeatedly is fine and I do it all the time in my own projects. It's basically just a dictionary lookup so it's not free, but is unlikely to be the source of any performance problem.
    I don't quite understand what you mean, but you can likely check what you want using state.Clip and/or animancer.States.Current.
     
  22. nobluff67

    nobluff67

    Joined:
    Nov 3, 2016
    Posts:
    338
    @Kybernetik

    Here is my first issue:

    In the below image I am initiating the run or walk animation, using:


    Code (CSharp):
    1.  _Move.State.Parameter = new Vector2(0,1);
    ani1.PNG

    I then stop the animations using:
    Code (CSharp):
    1. _Move.State.Stop();
    I do this in order to give controll to puppetmaster. The image below shows that the animations have stopped (I think?)

    ani1a.PNG

    I then run a getup animation through animancer.

    Code (CSharp):
    1. _Animancer.Play(_ClipFaceUp).Time = 0;
    . The image below shows that it works as expected:

    ani1b.PNG

    Once the character had regained control, and is ready for directional mixer. I reinitiate the walk animation:

    Code (CSharp):
    1. _Move.State.Parameter = new Vector2(0,1);
    . However the image below shows that the walk animation is not executing, it seems to just staying at the end of the getup animation.

    What step am I missing? Is this something that is explained in the spiderbot "wake" and "sleep" logic?

    ani1c.PNG

    EDIT: I think this was the step I was missing:

    Code (CSharp):
    1.     _WakeUp.Events.OnEnd = () => _Animancer.Play(MovementAnimation);
    2.  
    Seems to work well with this, now I just need to improve on the blending between the getup and movement animation.

    EDIT EDIT:

    improved on blending by adding parameter on the above code:

    _Animancer.Play(MovementAnimation,1f);
     
    Last edited: May 22, 2021
  23. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    Sure, give me some time to put that together and I will send it over.

    I have another question regarding controlling the speed of animations.
    I have a situation where I want to control the speed of my animation based on player input. With the regular Animation Controller, I had a multiplier parameter on the state that I set using the input like so:

    Code (CSharp):
    1. float input = Input.GetAxis("Horizontal");
    2. animator.SetFloat("_input", input);
    With this, when I entered the animation state, the animation would be frozen at first (when there was no axis input) and only played when there was positive input. How can I do the same with Animancer? I tried simply doing this:

    Code (CSharp):
    1. var state = _Animancer.Play(_Push, 0.25f);
    2. state.Speed *= input;
    But it doesn't seem to work; my speed just gets very slow. I also tried zero'ing the speed first, but that also doesn't work.

    I have multiple places in my code where I'm calling that specific animation; as I understand it, the states get reused? So, if I want my speed to always match the player input variable, do I need to do the above once, and every time the animation gets played again, the speed will be set accordingly? Or do I have to set the speed every time I call the Play function?
     
  24. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    @nobluff67 Yes, setting the mixer parameter doesn't actually force it to play so you just needed to call _Animancer.Play. Also, if MovementAnimation is a Transition then it will have a Fade Duration field which you can set in the Inspector instead of hard coding it like that.

    @theghostronaut If _Push is an AnimationClip then playing it won't reset the speed so you'll need to use
    state.Speed = input;
    (no need for *= because it will be 1 by default and nothing else is going to set it but you). Or if it's a Transition then you can enable the Speed field in the Inspector to set it to whatever base value you want every time it's played so you can keep using *= in code (and then you wouldn't need to hard code the fade duration either).
     
  25. theghostronaut

    theghostronaut

    Joined:
    Jul 27, 2018
    Posts:
    31
    Ah, thanks. That clears it up for me.

    So, since I want to set the speed of that animation to always match my player input, would this be the correct / best practice procedure:

    // 1. I create a global variable for my animation state in my script
    AnimancerState pushAnimationState = null;

    // 2. In my specific script where I handle and trigger the animation, I "initialise" the state to be able to set its speed later:
    Code (CSharp):
    1. private void HandleAnimation()
    2. {
    3. if (!animationStatesInitalised)
    4.         {
    5.             pushAnimationState = _Animancer.Play(_Push);
    6.            
    7.            // immediately stop the animation
    8.             _Animancer.Evaluate();
    9.            pushAnimationState.IsPlaying = false;
    10.  
    11.            // only do this once
    12.            animationStatesInitalised = true;
    13.         }
    14.  
    // 3. Then in the same function, I set the speed:
    Code (CSharp):
    1. pushAnimationState.Speed = pushInput;
    // 4. And now whenever I call
    Code (CSharp):
    1. _Animancer.Play(_Push)
    the speed will be set accordingly.

    This works, but I just want to make sure it's the proper way to handle this? I don't want to have to set the speed every time I call Play, as that would be pretty repetitive.

    (P.S. I'm initialising the state in a specific function rather than in Awake because there are other states that I'm handling in the same way, that require specific references that are only available once this function is called)
     
  26. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    If you don't actually want to play the state yet, you can use _Animancer.States.GetOrCreate(_Push);

    Otherwise, yeah that sounds reasonable.
     
  27. nobluff67

    nobluff67

    Joined:
    Nov 3, 2016
    Posts:
    338
    @Kybernetik

    Do I have the right concept (with animancer) in this example? Combat.png
    The above used with directional (as per spiderbot), and only active when NPC is in combat, or else deactivated.

    Then with my other movement animations in a linear mixer that are active when not in combat.
    1. Sprint Forward
    2. Walk Forward
    If I should be doing this another way, please advise.

    If above makes sense, can I still blend from directional into the linear, and back again? (e.g. from Sprint Forward/Walk forward in linear mixer, blending into the directional Walk Forward Aim.
     
  28. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    That would be fine. Each mixer is self-contained and doesn't know or care what other state you might be blending to or from. It's just up to you to get the logic right for when to tell it to play each one and how to control their parameters.
     
    nobluff67 likes this.
  29. VictorUlhagen

    VictorUlhagen

    Joined:
    Jan 21, 2016
    Posts:
    1
    Hey!
    Using Animancer Pro for a third person game. I'm having some trouble wrapping my head around the event system and how to handle multiple actors in the scene.

    In my starting case i want to reuse a mixer transition that handles my idle/walk/run for multiple actors. I want to have events in these animations, such as footstep triggers.

    What i have done:
    1. Created clip transitions assets for each substate(Idle, Walk, Run) that holds animancer events with name "Footstep"
    2. Created a mix transition asset that holds the mix of these three clip transitions
    3. Created a animation controller script that when asked to play a transition duplicates the events structure and then loops through all events in the transition and all of its children. I find the events that i expect to find.

    Here i start getting weird behaviour however.
    I expect to get calls to my registered handle function but i get nothing from the child transitions.
    If i create an event in the base mixer transition i get that event as expected, but now i get footsteps when im idling which isn't ideal.

    I thought it might be something related to "AutomaticallyClearEvents" but if i set that to false i dont get any different behaviour and if i try to register the events in the children each time i play the transition i get warnings about "possible bug detected", so it seems like the registration is still valid.

    Have i understood the event philosophy in animancer wrong or am i doing something that obviusly bad? :)

    This is the code for parsing the animancer transition events.
    HandleEvent just prints the id to log

    Code (CSharp):
    1.  
    2. private void ParseEvents(AnimancerState state, AnimancerTransition owner)
    3. {
    4.    foreach (AnimationControllerEvent e in events)
    5.    {
    6.       int index = state.Events.IndexOf(e.id);
    7.       if (index >= 0)
    8.       {
    9.          state.Events.SetCallback(index, () => { HandleEvent(e.id, state); });
    10.          LogSystem.Log(LogGroup.Animation, LogLevel.Info, "Registered event {0}:{1} in {2}", null, e.id, owner.name, name);
    11.       }
    12.    }
    13.  
    14.    for (int i = 0; i < state.ChildCount; i++)
    15.    {
    16.       ParseEvents(state.GetChild(i), owner, firstPlay);
    17.    }
    18. }
    19.  
     
    Last edited: May 28, 2021
  30. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    The easiest way to manage transition assets shared between multiple characters is the new UnShared Transition Assets system. It's still a bit experimental, so give it a go and let me know how well it works for you.

    And your problem with events not triggering is a bug which I've posted a fix for here.
     
  31. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Hey everyone, I just made a post about some Transition Inspector and Preview Improvements I've been working on for the next version of Animancer and I'd love to hear your Feedback. I'll keep posting new stuff in that thread, so you can Subscribe using the button in the sidebar if you want to receive notifications for new posts.
     
    Last edited: May 30, 2021
  32. jimmygladfelter

    jimmygladfelter

    Joined:
    May 3, 2020
    Posts:
    83
    Im just getting started using this and am trying to convert my existing project from its current animater controller.
    I would like to do it all in code. I am having trouble with a linear mixer animation speed changing...see below.

    upload_2021-5-30_20-22-37.png

    I think it has to do with my LinearMixerState's children having thresholds from 0 to 0.5 and me giving its parameter higher than that...like 1

    Any idea why this is happening and how to fix it so that it always plays speed at 1x without me having to clamp it based on threshold? If not I can just clamp it but I dont remember regular blend trees doing this but I could be wrong :)



    EDIT: I figured it out:
    Code (CSharp):
    1. linearMixerState.ExtrapolateSpeed = false;
     

    Attached Files:

    Last edited: May 31, 2021
  33. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    If you're using transitions to set up the mixers, you can disable the Extrapolate Speed toggle in the Inspector. You can also set mixer.ExtrapolateSpeed = false; in code.
     
    jimmygladfelter likes this.
  34. LukeDawn

    LukeDawn

    Joined:
    Nov 10, 2016
    Posts:
    403
    Has anyone tried using Animancer with Mirror networking?
     
  35. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    I know people have done it, but it's a matter of networking your scripts to have them control Animancer in the same way on each computer rather than directly synchronising the animation system like Animator Controllers can do. I explained more about it in this comment.
     
    LukeDawn and hopeful like this.
  36. LukeDawn

    LukeDawn

    Joined:
    Nov 10, 2016
    Posts:
    403
    @Kybernetik Thanks for that, it's pretty much what I had in mind already. Since I have a list of anims each with an id, I can just push the id to clients, and get animancer to do it's thing with that.
     
  37. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    On a animator event (unity one), is there a way to figure out the owning state of the AnimatorStateInfo?
     
  38. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    You can give your receiver method an AnimationEvent parameter, but keep in mind that it will allocate some garbage every time the event is triggered.
     
  39. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    oh sorry, I meant AnimationControllerState. In truth, I am trying to get the owning layer index of a AnimationEvent. I was thinking getting AnimationControllerState owner would be the first step.
     
  40. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    The best solution I was able to come up with (before I gave up and made Animancer Events) is what the AnimationEventReceiver in the Utilities folder uses. Basically, when you set its callback you also set the state and it uses the event's clip to make sure it actually came from that state before invoking your callback, but that obviously only works for ClipStates. I don't think there's anything in an Animation Event that could tell you which Animator Controller or ControllerState it came from.
     
  41. Spudly1701

    Spudly1701

    Joined:
    Aug 25, 2013
    Posts:
    36
    Hi all,

    So, I'm having a really weird issue with triggering the end event in my code.

    Code (CSharp):
    1. private void OnTriggerEnter(Collider other)
    2.     {
    3.         if (other.gameObject.CompareTag("Obstacle_Food") || other.gameObject.CompareTag("Obstacle_Points") || other.gameObject.CompareTag("Obstacle_SpecialFood"))
    4.         {
    5.             var stateLaylaBite = animancer.Layers[ActionLayer].Play(_Bite, FadeDuration);
    6.             stateLaylaBite.Speed = (animancer.Playable.Speed / 2) * 10f;
    7.             stateLaylaBite.Events.OnEnd = () => OnAnimationEnd();
    8.         }
    9.     }
    10.  
    11.     void OnAnimationEnd()
    12.     {
    13.         Debug.Log("LaylaBitAnimationFinished");
    14.         animancer.Play(_Idle, FadeDuration);
    15.  
    16.     }
    When looking at the console it appears as though the animation never actually 'ends' leaving me in an endless loop which stops any other animation on the object from playing.

    I've spent nearly two days trying to figure this out and I'm at a complete loss and it's driving me nuts.

    Would anyone have any ideas as to what I'm doing wrong?

    Thanks.
    Spud
     
  42. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Select the object and look at its Inspector to make sure the animation is actually reaching the end.

    You can also Right Click on the state and use the context menu to see what events it has assigned to make sure nothing else is clearing them.

    Logging might also be helpful:
    Code (CSharp):
    1. private void Update()
    2. {
    3.     var state = animancer.Layers[ActionLayer].CurrentState;
    4.     Debug.Log(state.GetDescription());
    5. }
     
  43. Spudly1701

    Spudly1701

    Joined:
    Aug 25, 2013
    Posts:
    36
    Wow, thanks for the swift reply.

    Hmmmm........okay, so in the inspector, the animation is playing to the end (timeline wise), but it doesn't seem to be registering that it has actually ended (isPlaying flag constantly on).

    Right clicking on the even only gives me the Unity animation properties.

    Tried the logging and it just constantly says that Bite is playing. (Pic attached)

    https://www.dropbox.com/s/7h1pocvctwgqi9u/animancer.jpg

    Spud
     
  44. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Is Playing will remain true until you actually stop it (usually by playing something else). Time will keep advancing too (as you can see it's 73x past the end of the animation in that screenshot).

    Right Clicking anywhere in that green bar showing the state's time should bring up its context menu, but I can see at the bottom of the image that the event is assigned.

    Click on the log message to see the full description of the state's details, it has multiple lines.
     
  45. Spudly1701

    Spudly1701

    Joined:
    Aug 25, 2013
    Posts:
    36
    Okay, when I trigger another animation, the isPlaying flag stays true. (The other animations do register in the inspector, but instantly stop).

    Here is the logging output. It seems as though there's no EndEvent actually registering?


    Bite (ClipState)
    Key: Bite (UnityEngine.AnimationClip)
    AssetPath: Assets/_Animations/Layla/Layla_Animated.fbx
    Playable: UnityEngine.Animations.AnimationClipPlayable
    Index: 0
    Speed: 5.14563
    Weight: 1
    InverseKinematics: None
    IsPlaying: True
    Time (Normalized): 265.5491 (335.4305)
    Length: 0.7916665
    IsLooping: False
    EndEvent.NormalizedTime: NaN
    EndEvent.Target: LaylaEatTrigger (LaylaEat)
    EndEvent.Method: Void <OnTriggerEnter>b__13_0()
    UnityEngine.Debug:Log (object)
    LaylaEat:Update () (at Assets/_Scripts/Controllers/LaylaEat.cs:55)
     
  46. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    Since you're using a fade duration, Is Playing will stay true on the previous state while it fades out until its Weight reaches 0.

    Based on that log it should definitely be triggering the End Event every frame and I can't think of anything else that would prevent it.

    If you can send a minimal reproduction project to animancer@kybernetik.com.au I'll be happy to take a look at it for you.
     
  47. GoldFireStudios

    GoldFireStudios

    Joined:
    Nov 21, 2018
    Posts:
    155
    We've got a custom interaction builder that we are implementing Animancer with to replace Macanim. So far everything has been great, but the transitions are tripping me up. Originally, I was using the following with a crossFade value to get smooth transitions:

    Code (CSharp):
    1. AnimancerState state = animancer.Layers[layerIndex].Play(currentEvent.animationState, crossfade, FadeMode.FromStart);
    I then faded out the layer on the OnEnd event. The problem is that this didn't replicate the behavior with Mecanim since the fade started at the end of the animation. So, I changed the animation clip reference to be a
    ClipState.Transition value and changed the code to:

    Code (CSharp):
    1. AnimancerState state = animancer.Layers[layerIndex].Play(currentEvent.animationState);
    What I want this to do is fade into the animation over 0.25s, which it does no problem. But then, I want it to fade out over the last 0.5s, which is the part I'm not clear about. I thought setting the end time would handle that, but according to the documentation, this simply changes when the animation ends rather than changing the duration of the fade.

    Since I'm not starting another animation after, just fading out this particular layer while another layer continues to play, how would I accomplish a 0.25s fade in and a 0.5s fade out where the transition happens with 0.5s remaining in the animation. Is the transition system not going to work for this use-case?

    Or, maybe I'm just stuck in the Mecanim way of thinking and approaching this wrong?
     
    Last edited: Jun 8, 2021
  48. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    The end time just determines when the end callback is triggered, it doesn't automatically do anything to the following fade if you happen to start one there.

    If you want to use the remaining duration of the current state as your fade duration you can do this:
    Code (CSharp):
    1. var state = animancer.Layers[layerIndex].CurrentState;
    2. var fadeDuration = AnimancerEvent.GetFadeOutDuration(state, 0.25f);
    3. state = animancer.Layers[layerIndex].Play(currentEvent.animationState, fadeDuration);
     
  49. GoldFireStudios

    GoldFireStudios

    Joined:
    Nov 21, 2018
    Posts:
    155
    Maybe I'm misunderstanding, but I'm not sure how that would resolve the problem. Doesn't the fade duration on the Play method just affect the fade in and not the fade out?

    To simplify what I was trying to explain, I've got the base layer playing the idle animation on the full body, for example. I then trigger an animation that runs on a layer masking just the arms. I want to fade into this animation, which works fine. But, I then want to fade out of this animation over the last 0.5s (or whatever time value) of the animation rather than fading out the layer after the animation has finished. I'm not trying to transition between two animations as I'm not triggering another animation on this layer, just fading out of it so that the base idle animation smoothly takes back over the arms.
     
  50. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,487
    You can just pass that fadeDuration into
    animancer.Layers[layerIndex].StartFade(0, fadeDuration);
    to fade the layer out.