Search Unity

Animancer - Less Animator Controller, More Animator Control

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

  1. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    What do you mean by "recover"? 99% of the time, you just want to play something else. Or if you just want to know when it ends without getting called every frame you could just use a regular Animancer Event instead of an End Event, i.e. state.Events.Add(1, callback).
     
  2. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,433
    Ideally I would just want the object to go back to its before-Play state. I grudgingly accept freezing on last animated frame.

    In the end, I just wait/poll for IsActive to go false and clean up my other stuff.
     
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    There isn't anything that captures the state of an object before you play an animation so you can't just revert to it unless you implement a system to do that yourself.

    state.NormalizedTime >= 1
    will tell you if its time has passed the end if that helps.
     
  4. cmapua

    cmapua

    Joined:
    Apr 15, 2014
    Posts:
    1
    Hi, I'm trying to use AnimatedFloat to get custom curve values in animations for IK weights, but I'm getting this error:

    Code (csharp):
    1. InvalidOperationException: The PropertyStreamHandle cannot be resolved.
    2. UnityEngine.Animations.PropertyStreamHandle.CheckIsValidAndResolve (UnityEngine.Animations.AnimationStream& stream) (at <d7780361fb3a49319b9ac6c58e81f7de>:0)
    3. UnityEngine.Animations.PropertyStreamHandle.GetFloat (UnityEngine.Animations.AnimationStream stream) (at <d7780361fb3a49319b9ac6c58e81f7de>:0)
    4. Animancer.AnimatedFloat+Job.ProcessAnimation (UnityEngine.Animations.AnimationStream stream) (at Assets/Plugins/Animancer/Utilities/Animation Jobs/AnimatedFloat.cs:62)
    5. UnityEngine.Animations.ProcessAnimationJobStruct`1[T].Execute (T& data, System.IntPtr animationStreamPtr, System.IntPtr methodIndex, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at <d7780361fb3a49319b9ac6c58e81f7de>:0)
    I made sure the property name was correct and followed the IK documentation, is there any setup I'm missing?
     
  5. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Try going to the Uneven Ground example and replacing the animation clip and property name it uses with yours. If it works in that example, then there must be something else wrong with your setup. Or if it doesn't work there, then you might not have the property name correct.

    Note that the property name shown in the Animation window might not be correct (it adds spaces between words). I can't actually think of anywhere in Unity that would show the real property name, but you can always open the animation file in a text editor.
     
  6. luuuuyang

    luuuuyang

    Joined:
    Aug 30, 2022
    Posts:
    5
    Hi! I have a problem that has been bothering me for a few days.
    How can I add Event to ClipTransition in editor mode by code instead of double click the timeline?
    I tried ClipTransition.Events.Add(), but it didn't work. Event doesn't seem to be serialized, and I can't see Event being added from the inspector window.
    Looking forward to reply, thanks!
     
  7. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    transition.SerializedEvents.Callbacks, NormalizedTimes, and Names.

    The those arrays are used to build the transition.Events at runtime so modifying that won't be applied back to the serialized data (and can't be because the runtime callbacks aren't serializable).

    Also, to add persistent listeners to a UnityEvent (the Callbacks) you'll need to use the functions in UnityEditor.Events.UnityEventTools.
     
  8. luuuuyang

    luuuuyang

    Joined:
    Aug 30, 2022
    Posts:
    5
    Thanks for the reply!
    That is to say, if I want to create Events on ClipTransition based on a series of time points in the configuration file, I can only double-click the timeline and adjust the time on the inspector?
     
  9. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    No, you can do it in script via transition.SerializedEvents. What I meant is that your original attempt didn't work because modifying the transition.Events won't be read back into the transition.SerializedEvents.
     
  10. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    934
    Can we Integrate animancer Pro with FinalIK?
     
  11. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    As far as I know, Final IK has no direct dependency on animations so it doesn't know or care what animation system you use (if any).
     
  12. Cleverlie

    Cleverlie

    Joined:
    Dec 23, 2013
    Posts:
    219
    hi @Kybernetik I'm having a question about the possibility to cover a use case with your plugin before proceding to buy it, could you help me understand if this use case would be possible or easily doable with Animancer?

    I have a mount (a horse) that has different animations like horse-idle, horse-run, horse-jump etc.
    At the same time I have the human rider model with its own animations that correspond to each of those previously mentioned, rider-idle, rider-run etc.

    horse-<action> and rider-<action> are animations made to be put together and in sync.

    So what I need is to keep both the rider and the mount animations in sync, I've been doing this with the Unity animator with a piece of code like this:

    Code (CSharp):
    1. public class AnimatorSyncronizer : MonoBehaviour
    2. {
    3.     [SerializeField] Animator master;
    4.     [SerializeField] Animator[] slaves;
    5.  
    6.     // Update is called once per frame
    7.     void Update()
    8.     {
    9.         for (int i = 0; i < slaves.Length; i++)
    10.         {
    11.             var masterState = master.GetCurrentAnimatorStateInfo(0);
    12.             var masterStateTime = masterState.normalizedTime;
    13.             var masterStateName = masterState.fullPathHash;
    14.             var slaveState = slaves[i].GetCurrentAnimatorStateInfo(0);
    15.             var slaveStateTime = slaveState.normalizedTime;
    16.             var slaveStateName = slaveState.fullPathHash;
    17.  
    18.             if (slaveStateName != masterStateName || Mathf.Abs(masterStateTime - slaveStateTime) > 0.01f)
    19.             {
    20.                 slaves[i].Play(masterStateName, -1, masterStateTime);
    21.             }
    22.         }
    23.     }
    24. }
    which is pretty horrible, but couldn't find other way for such a basic (and probably widely needed) use case.

    So far so good, the problem starts when I need to crossfade animations, I have no Idea how to keep crossfaded animations in sync with the default animator since probably I'll have to do something like not only getting the current animator state info but also the next one, and keep track of that in the master and the slaves, and also call slaves.Crossfade() instead of Play(). It's getting rather complex for such a simple scenario.

    If your plugin solves this situation more elegantly, I think I'm all in to buy it.

    thanks in advance!
     
  13. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Animancer lets you directly get and set the NormalizedTime and Weight of each state so what you want is definitely possible. Another advantage is that Animancer never plays anything on its own so if you call master.Play and slave.Play at the same time, you won't have to worry about it playing anything else unless you tell it to, so all you need to sync is the NormalizedTimes (and maybe Weights, though that might not be necessary if you always give them the same fade duration).

    The TimeSynchronizationGroup script demonstrated in the Directional Character example is not quite what you need, but should give you an idea of how it could be done. Basically just:
    Code (CSharp):
    1. var normalizedTime = master.States.Current.NormalizedTime;
    2. for (int i = 0; i < slaves.Length; i++)
    3.     slaves[i].States.Current.NormalizedTime = normalizedTime;
    Setting the NormalizedTime will prevent the slaves from triggering any events that frame so if you need events, you can call MoveTime on them instead.

    That obviously means it will stop synchronizing the previous states when you start a fade, but that might be fine because they won't have much time to get out of sync as they fade out. Otherwise, whenever you play anything you could add the previous master and slave states to a List<AnimancerState> so you can keep synchronizing them until they reach 0 Weight. And if you need to account for the possibility of having multiple consecutive fades, you could just keep a List of Lists. Animancer's ObjectPool class would also let you easily Acquire and Release those lists so you don't create any unnecessary garbage that could affect performance.

    I highly recommend trying out Animancer Lite before you buy. Setting the time of animations is a Pro-Only feature so it will warn you that it won't work in runtime builds with Lite, but once you have a proof of concept working in the Unity Editor you can seamlessly upgrade to Pro.
     
    Cleverlie likes this.
  14. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Wow, I'm frustrated. I used to be a huge Animancer fan, but I'm trying now to update an older project to the current version, and it's been nothing but one obstacle after another. It seems like every API we use has disappeared or changed, with no clear upgrade guide as far as I can find.

    I've already wasted many hours digging around in the docs, and now I'm running into things that don't even work as documented, so I guess I'll just start asking questions.

    1. What's the right way to replace a child state in a ManualMixerState now? We used to do:
    Code (CSharp):
    1.             mixer.CreateState(curStateIndex, curClip);
    2.             mixer.States[curStateIndex].Speed = 0;
    ...but mixer.States no longer exists, and the mixer.CreateState line now produces the runtime error:

    I think mixer.States[curStateIndex] is now mixer.GetChild(curStateIndex), but I'm stuck on this other error. The docs claim there is a Remove method which removes a child state — maybe we need to call that now before creating a new one? But apparently that method doesn't actually exist:

    So. What's the new way to create a new child state, stuff it into a ManualMixerState (replacing the previous one at that index), and set its speed to 0?
     
  15. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    In Animancer v7.3 there's mixer.CreateChild and ChildStates. And that Remove method doesn't exist yet, it's new in Animancer v7.4 and I evidently forgot to exclude the API pages when I added the banner linking to that page to everything. I've reverted the API pages to v7.3 for now, sorry for the mixup.

    If you want a Remove method in v7.3, you can add this to MixerState.cs:

    Code (CSharp):
    1. public void RemoveChild(int index, bool destroy)
    2. {
    3.     var child = ChildStates[index];
    4.     if (child == null)
    5.         return;
    6.  
    7.     if (destroy)
    8.         child.Destroy();
    9.  
    10.     child.SetParent(null, -1);
    11. }
    The reason you can't just create over the top of an existing child any more is because it was never clear whether you wanted to destroy the old child or not so it would either lead to leaking memory or potentially destroying a state you still wanted to use.

    But on that note, Animancer v7.4 has more changes to the Mixer API outlined here so if you'd like to check it out and give feedback, just send your Invoice Number to animancer@kybernetik.com.au (or PM me here). Those changes primarily come from frequent complaints about how fiddly mixers are to set up in code with the need to set their size beforehand and assign each index explicitly, so the new system just lets you treat them like a list. Feedback from someone like you who actually uses mixers in a real project would be particularly helpful.
     
    hopeful likes this.
  16. Cleverlie

    Cleverlie

    Joined:
    Dec 23, 2013
    Posts:
    219
    great answer! will try with the lite version and let you know my findings, is there a date to end the current discount price on you asset?
    and thanks for the detailed answer!
     
  17. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    The New Year Sale should go until January 5th.
     
  18. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Hey everyone, I'm happy to announce the release of my new asset: FlexiMotion is a high performance procedural animation system which simulates physics for flexible objects such as hair, clothing, tails, and tentacles.

    FlexiMotion.gif

    results.png

    I've given FlexiMotion a 50% off release discount and with it finally out, I'll be back to working on Animancer v7.4 which I aim to have done by the end of January. So far, everyone seems to like the new cloning behaviour and mixer initialization syntax, but I'm still open to any last minute feedback.
     
    florianBrn, ratking, Ruchir and 2 others like this.
  19. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    I'm super confused. I am calling

    var state = Animancer.Play(Asset.Clip);

    then calling the same code again later, while the clip is still running. I want it to rewind and start from the beginning in this scenario, so I do

    state.Time = 0f

    However, instead, the animation state continues playing from where it was in the animation, then begins a partial second animation, then cuts off abruptly in the center of the 2nd replay.
     
  20. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    If you're setting Time = 0 and it's not rewinding, then either your code isn't being run or it's controlling the wrong state. Try putting in some debug logs and watching the Inspector to see if you can narrow down what's happening.

    And if the animation cuts off, that means something else is stopping it.
     
  21. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    You were right, thank you >_<
     
  22. Setmaster

    Setmaster

    Joined:
    Sep 2, 2013
    Posts:
    239
    Any chance of a discord for animancer?
     
  23. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    I've tried using Discord for support in the past, but found that the ability to fire off a quick question and the expectation of an instant response leads people to ask questions before properly thinking through their problem or trying to read the documentation. There are also people who want to chat with me like a friend after I help them, but I simply don't have the time or inclination to deal with any of that.

    My preference for support is Github Issues because they allow a new thread to be started for each topic which can then be closed when the question is answered rather than sticking everything in this mega thread, but for whatever reason most people seem to prefer posting here.
     
    Last edited: Jan 15, 2023
    Jos-Yule and Setmaster like this.
  24. wubuzi

    wubuzi

    Joined:
    Jan 19, 2022
    Posts:
    9
    How to change MixerTransition2D animations in c# code???

    It seems documentation are not telling this!

    Code (CSharp):
    1. public MixerState<Vector2> blendState;
    2. public MixerTransition2D blend;
    3.  
    4. var state = animancer.States.GetOrCreate(blend);
    5. blendState = (MixerState<Vector2>)state;
    6.  
    7.  
    8. //How to change mix animations???
    9.  
     
  25. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    You can modify the
    blend.Animations
    array.

    If you want to change the animations after you create the mixer state, I've made some changes in the upcoming Animancer v7.4 which make that much easier.
     
  26. wubuzi

    wubuzi

    Joined:
    Jan 19, 2022
    Posts:
    9
    For now, I don't know how to modify
    blend.Animations
    , because it the type of Object, My animation is type of ClipTransition, I don't know how to add my animations in blend.Animations.

    Now I just use state to modify the animations.
    Code (CSharp):
    1. public MixerState<Vector2> blendState;
    2. public MixerTransition2D blend;
    3.  
    4. var state = animancer.States.GetOrCreate(blend);
    5.         blendState = (MixerState<Vector2>)state;
    6.  
    7.         blendState.Initialize(4);
    8.         for (int i = 0; i < 4; i++)
    9.         {
    10.             blendState.CreateChild(i, list[i], vecList[i]);
    11.         }
     
  27. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    280
    hello @Kybernetik I'm pulling my hairs out right now.
    I can't understand why my debug and Animancer's debug are different.
    This is the code to control each segment of a centipede.

    So the target is I want each segment to play idle / run / air based on their current status using raycast against terrain. The raycast has nothing wrong, just the animation status is wrong.

    Code (CSharp):
    1.         //each segment play anim on a layer with id and mask
    2.         [System.Serializable]
    3.         public class Segment:IDebuggable {
    4.             public Transform _transform;
    5.             public int layerId;
    6.             public AvatarMask mask;
    7.  
    8.             public string name => _transform.name;
    9.            
    10.             public GroundCheckModule groundCheckModule { get; private set; }
    11.             public VelocityModule velocityModule { get; private set; }
    12.  
    13.             public bool onGround => groundCheckModule.OnGround;
    14.             public float spd => velocityModule.speed;
    15.  
    16.             public string getDebugString => string.Format("{0}| {1}| spd {2} | anim {3} | {4} | animSpd {5} | animLayer {6}", _transform.name, onGround ? "onGround".ColorMe(Color.yellow) : "in air".ColorMe(Color.cyan), spd.RoundDecimal(),playingClip?playingClip.name:"-",state!=null?state.NormalizedTime.RoundDecimal():"-",state!=null?state.Speed:"-",layer.DebugName);
    17.  
    18.             AnimancerLayer layer;
    19.             Animancer.AnimancerState state=>layer.CurrentState;
    20.             float animSpd = 1f;
    21.             public AnimationClip playingClip => state != null ? state.Clip : null;
    22.  
    23.             public void Init(Animancer.AnimancerComponent animancer) {
    24.                 groundCheckModule = _transform.GetComponent<GroundCheckModule>();
    25.                 velocityModule = _transform.GetComponent<VelocityModule>();
    26.  
    27.                 layer = animancer.Layers[layerId];
    28.                 layer.SetMask(mask);
    29.                 layer.SetDebugName(string.Format("Segment {0}", layerId));
    30.             }
    31.  
    32.             public void Play(AnimationAction act) {
    33.                 if (state!=null && state.Clip == act.clip) return;
    34.                 //if(state!=null)state.StartFade(0f);
    35.                 if (state != null) state.Stop();
    36.                 layer.Play(act.clip, 0.15f);
    37.                 state.Speed = animSpd;
    38.             }
    39.  
    40.             public void SetAnimSpd(float spd) {
    41.                 state.Speed = animSpd = spd;
    42.             }
    43.             public float normalizedTime {
    44.                 get => state.NormalizedTime;
    45.                 set => state.NormalizedTime = value;
    46.             }
    47.  
    48.             public void Validate() {
    49.             }
    50.  
    51.             public void Update() {
    52.             }
    53.         }
    This is my debug window. the Segment name is correct, therefore I expect the debug value should be different per segment, like the normalized time. But they are all the same. And they're all playing same anim.

    upload_2023-1-18_13-5-50.png

    Even weirder, the animancer debug window is completely different, it says only Segment 5 is playing anim run, and all other is not playing.

    upload_2023-1-18_13-6-57.png

    I hope to have some tips to use animation layer to control each segment (legs only) on a centipede body.
    Thank you!
     
  28. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    280
    To summarize the issue: debug 7 layers, each layer is correct because they're shown in correct name, but the other status of each layer.currentState is shown to be the same state. Same speed, same anim, same normalized Time. And Animancer debug shows only one layer is playing animation.
     
  29. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    @wubuzi You can put AnimationClips inside an Object[] because AnimationClip inherits from Object. If you want to put a ClipTransition in there you could use a Clip Transition Asset (because they inherit from ScriptableObject which inherits from Object).

    Initializing the state manually is fine too, but then there's likely no point in using a transition.

    @Spikebor When you play a clip, if there's already an existing state it will just play that instead of creating a new one, and if that state is on a different layer it will move it to the new layer. So you're seeing the same values on all of them because they're all referencing the same state.

    You can avoid that by manually creating a new state for each layer, but that's actually a fairly common problem so I've changed the behaviour in the upcoming Animancer v7.4 to make it create a new state if the existing one isn't on the right layer. If you'd like to try it out early, just send me your Invoice Number (in a PM here or email animancer@kybernetik.com.au). Otherwise, I hope to have it ready to release in the next week or so.
     
    Last edited: Jan 18, 2023
  30. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    280
    Thank you! I have sort out the issue by your guide, all good now!
    Code (CSharp):
    1. state = animancer.States.Create(this,_defaulClip);
    2.  
     
  31. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    Hello, I'm working through your examples for a FSM. I'm having difficulties getting the player to Idle and Move based on animations that live on weapons that are picked up. I think the problem is that normally the Character class can be found via
    Code (CSharp):
    1. #if UNITY_EDITOR
    2.         protected override void OnValidate() {
    3.             base.OnValidate();
    4.  
    5.             gameObject.GetComponentInParentOrChildren(ref _character);
    6.         }
    7.     #endif
    because when unarmed those Character States exists on the character. But because weapons in the environment are not on the same gameObject as the player, it can't access Character. I'm pretty sure that's it unless you have some other insight. What am I missing? Thanks!
     
  32. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    That method will do nothing if the weapons don't have a Character in their parents or children.

    If you're dynamically adding states, you'll have to assign their Character references as part of your equipping function.
     
  33. wubuzi

    wubuzi

    Joined:
    Jan 19, 2022
    Posts:
    9
    How to play mirror animation by Animacer?? I can't find this on Documention.

    Beat'em up animation needed, play mirror animation when character direction on right.
     
  34. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    As noted in the Features table, you need to make a second copy of the animation so you can mirror it in the import settings. Unfortunately, the Playables API doesn't have a feature to mirror animations at runtime.
     
  35. wubuzi

    wubuzi

    Joined:
    Jan 19, 2022
    Posts:
    9
    Oh no.............
     
  36. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    is that something you show how to do in your documentation? I can't seem to figure out how to do it. After picking up the weapon I can get it into my Inventory class as ItemInHand. The Inventory exists on the same object as the Character. Does this information give you an idea how to assign Character reference with the dynamically added states? Thanks again
     
  37. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    In your base state class, you need a public way of setting the Character. If you already have a public Character property, you could just make it a ref return:
    public ref Character Character => ref _Character;


    Then you can give your Weapon script a method to set the character on all its states:
    Code (CSharp):
    1. public void SetCharacter(Character character)
    2. {
    3.     _Idle.Character = character;
    4.     _Move.Character = character;
    5.     // Etc.
    6. }
    Then you just need to call that when you equip the weapon.
     
  38. anthonyu4

    anthonyu4

    Joined:
    May 20, 2018
    Posts:
    3
    I'm probably missing something, and I know it's possible to integrate Animancer with a 3rd party character controller, but how exactly would I go about doing that? Since the character controller I use takes care of pretty much all player and camera movement, I only really need to synchronize the animation with it and so far that's been a lot harder than I thought it'd be, especially with jumping/falling and sprinting.
     
  39. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Good news everyone, Animancer v7.4 is now available. It adds the often requested ability to clone mixer states, solves a common problem people run into when attempting to play the same animation on multiple layers, and simplifies the way you can initialize mixers in code, among many other smaller changes which are listed in the Change Log.

    @anthonyu4 The new version also makes it a lot easier to integrate an existing Animator Controller setup and I've also revamped the Animator Controllers page to be more straightforward about how to do that. Let me know if you have any more specific questions about it.
     
    hopeful, florianBrn and ratking like this.
  40. One_Learning_Man

    One_Learning_Man

    Joined:
    Sep 30, 2021
    Posts:
    81
    "Simplified playing the same animation on multiple layers" - Wow, this one caught my eye and seems to be extremely beneficial for my project. Nice job with the new updates.
     
  41. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
  42. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    Using the Animancer FSM. When in MoveState, the player play's a walking animation. In the Inventory class, there is a HandleEquipment method which plays equipping/unequipping animations on the Action layer. Goal is to use layers to have walking separate from equipping. It appears the equipping animation don't actually play through, but rather flash right to the last frame of the animation and then stay there. The player is still able to walk around and animate the legs but the top half is stuck in the last frame of the equip animation. Thanks!

    Code (CSharp):
    1. public class MoveState : CharacterState {
    2.      
    3.         [SerializeField] private LinearMixerTransition _animation;
    4.  
    5.         private void OnEnable() {
    6.             gameObject.GetComponentInParentOrChildren(ref _character);
    7.             Character.Animancer.Layers[0].GetOrCreateState(_animation);
    8.             Character.AnimHandler.PlayBase(_animation, false);
    9.         }
    Code (CSharp):
    1. public class Inventory : SerializedMonoBehaviour {
    2.  
    3. public void HandleEquipment(Item requestedItem) {
    4.  
    5.             _actionLayer = _character.Animancer.Layers[1];
    6.             _actionLayer.SetMask(_character.AnimHandler.ActionMask);
    7.  
    8.             _character.Animancer.Playable.KeepChildrenConnected = true;
    9.             _character.Animancer.Layers[1].GetOrCreateState(requestedItem.UnequipAnimation);
    10.  
    11.             if (requestedItem.IsArmed())  {
    12.                 requestedItem.UnequipAnimation.Events.OnEnd = OnEquipEnd;
    13.                 _character.AnimHandler.PlayAction(requestedItem.UnequipAnimation);
    14.             }
    15.  
    16. private void OnEquipEnd() {
    17.             // _character.AnimHandler.FadeOutAction();
    18.             // by adding the above line, the unequip animation does not play at all
    19. }
    20.  
     
  43. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    • You aren't setting the time anywhere there so unless you're doing it somewhere else, the only other thing that would do it is if you have the transition's Start Time set to the end of the animation.
    • Why are you calling GetOrCreateState? Both times you're playing that animation right afterwards anyway, which will automatically create the state.
    • SetMask and KeepChildrenConnected should only be called once on startup. There's no point in repeating them every time you equip something.
     
  44. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    The only part of what you wrote that I'm confused by is "You aren't setting the time anywhere there". What do you mean by that? Can you show me a syntax example of what you are referring to? Sorry I get confused easily, thanks again!
     
  45. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    ok I believe I have it worked out. My unequip animation is just the same as the equip animation but in reverse so I had to put start time to be 1. Now it's playing correctly. The only problem now is that I can see the legs(base) kinda stutter for just a few frameswhen doing the unequip animation(action) which leads me to believe the base is still being affected??

    Code (CSharp):
    1. public class MoveState : CharacterState {
    2.      
    3.         [SerializeField] private LinearMixerTransition _animation;
    4.      
    5.         private void OnEnable() {
    6.             gameObject.GetComponentInParentOrChildren(ref _character);
    7.          
    8.             Character.AnimHandler.PlayBase(_animation, false);
    Code (CSharp):
    1. public class Inventory : SerializedMonoBehaviour {
    2.         private void Start() {
    3.        _actionLayer = _character.Animancer.Layers[1];
    4.        _actionLayer.SetMask(_character.AnimHandler.ActionMask);
    5.  
    6.        _character.Animancer.Playable.KeepChildrenConnected = true;
    7.        }
    8.  
    9.      
    10.        public void HandleEquipment(Item requestedItem) {
    11.           requestedItem.OnUnequip += HandleUnequip;
    12.           requestedItem.OnEquip += HandleEquip;
    13.  
    14.           if (requestedItem.IsArmed()) {
    15.              ItemInHand = null;
    16.              requestedItem.UnequipAnimation.Events.OnEnd = OnEquipEnd;
    17.              _character.AnimHandler.PlayAction(requestedItem.UnequipAnimation);
    18.           }
    19.           else {
    20.              requestedItem.EquipAnimation.Events.OnEnd = OnEquipEnd;
    21.              _character.AnimHandler.PlayAction(requestedItem.EquipAnimation);
    22.           }
    23. }
    24.  
    25.  
     
  46. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    That's correct, or you can simply untick the Start Time toggle and it will pick the start time based on its Speed as explained in its tooltip.

    Your code looks a lot better now and I can't see anything there which would cause stuttering. Try pausing the editor to step through frame by frame or slowing down time with the TimeScale component and watching the Inspector to see if you can determine what's actually happening. Otherwise, if you can make a minimal reproduction project and send it to animancer@kybernetik.com.au I'll be happy to take a look at it.

    Also, if you're going to be potentially equipping and unequipping each weapon more than once, make sure you -= those OnEquip and OnUnequip events so they don't just keep accumulating new listeners.
     
  47. brokenspiralstudios

    brokenspiralstudios

    Joined:
    Oct 20, 2021
    Posts:
    45
    ok great, I just sent you an email with my project. Thanks so much for your time!
     
  48. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    280
    @Kybernetik Do you recommend any IK solution + Animancer ?
    Animation Rigging + Animancer workflow is terrible. Having to make state for every single animation first hand, a big no no. It's like remove the flexible benefit of Animancer just to work with Animation Rigging.
     
  49. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Final IK is the only popular IK system I know of and I've never had any reports of people having trouble using it with Animancer. As far as I know, it doesn't care what animation system you're using.
     
  50. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    280
    thanks I'll check it out.