Search Unity

Animancer - Less Animator Controller, More Animator Control

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

  1. sbsmith

    sbsmith

    Joined:
    Feb 7, 2013
    Posts:
    126
    I'm not sure if this is a bug or if I'm doing something wrong, but I've noticed that if I attach an avatar mask to a layer playing a PlayableAssetTransition containing a Timeline, the mask is not applied correctly. However, if I just use an AnimationClip, it is applied correctly. I prefer using timelines because my current workflow leverages custom marker tracks, and lining the markers up with the animation clips is just a convenient way to work.
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    That's likely a bug. Timeline wasn't designed to be used inside another Playable Graph. It mostly works, but there are things like this where it just doesn't and there probably isn't anything that can be done about it short of rewriting Timeline.
     
  3. sbsmith

    sbsmith

    Joined:
    Feb 7, 2013
    Posts:
    126
    Thanks. I'll just keep my workaround of using the timelines for design and then manually extracting the clips and playing it through Animancer.
     
  4. JaksonHunt17

    JaksonHunt17

    Joined:
    Apr 18, 2019
    Posts:
    2
    Hi Kybernetik, just purchased your asset pack recently and its great.

    In the documentation it mentions briefly using a keyed state machine to control animancer.

    I want to utilise it as i'm building a multiplayer game and would like to sync the states over the network

    I'm having trouble understanding how to implement this as the documentation doesn't go into to much detail.

    Is there a example i can use as a guide?
     
  5. Rusted_Games

    Rusted_Games

    Joined:
    Aug 29, 2010
    Posts:
    135
    Hello @JaksonHunt17 perhaps my post can help you get in the right track
    https://forum.unity.com/threads/ani...-animator-control.566452/page-24#post-7471148
     
    JaksonHunt17 likes this.
  6. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    @JaksonHunt17 The post linked by @Rusted_Games looks like it has everything you should need to get started. Let me know if you have any other questions.
     
    JaksonHunt17 likes this.
  7. JaksonHunt17

    JaksonHunt17

    Joined:
    Apr 18, 2019
    Posts:
    2
    Thankyou both for your help.

    I think i have a better grasped on implementation.

    Apologies if i am being daft, but does using this method then prohibit states from being monobehaviours?

    Thanks again
     
  8. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Code (CSharp):
    1. private NewIdleState _IdleState = new NewIdleState();
    Creating states with the new keyword like that means they can't be MonoBehaviours.

    But you don't have to create them like that. You could just as easily have NewIdleState as a MonoBehaviour class and make it a serialized field which you assign in the Inspector:
    Code (CSharp):
    1. [SerializeField] private NewIdleState _IdleState;
    Registering the states, entering them, and syncing the keys would all be the same.
     
    JaksonHunt17 likes this.
  9. senseless17

    senseless17

    Joined:
    Aug 17, 2022
    Posts:
    1
    Hi Kybernetik, thanks for the great asset.

    Im just having some trouble with the LinearMixerTransition,

    Essentialy im setting the LinearMixerTransition state Parameters to be equal to the players current vertical velocity.

    The problem is it seems the this value is also influencing the playback speed of the animations and causing undesired effects see following gif:

    https://giphy.com/gifs/e2K5Cap8yGyhamzAYt

    Is there anyway to disable this? (Here is current inspector view the LinearMixerTransition in question just incase needed)

    upload_2022-8-17_17-7-29.png
     
  10. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Untick Extrapolate Speed.
     
  11. Overlogical

    Overlogical

    Joined:
    Sep 12, 2020
    Posts:
    12
    Hi Kybernetik,

    I bought the Pro version of Animancer tried to get a grip on it over the last few days. Very impressive, also the documentation. While I understand the single explanations I fail to bring it together yet.

    I want to use a statemachine with a directional mixer with random weighted animations for each 'direction', so when the character is idle, it plays one of its idle states randomly but with a runtime configurable weight (for example change weights when he gets nervous to make him look around more often).

    More slightly different animations for the same thing would make it look more natural. It would be great, if the directional transition asset would allow arrays for each animation with weight parameters. Perhaps this is something you might consider implementing, as manipulating drawers might be to much for others as well (at least it is for me).

    If you have other demos or anyone from this forum would be willing to share some basic but complete movement demos especially for 3rd person or NPC 3d humaniod characters it would be great.
     
  12. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    The Nesting section explains how you can use a mixer as a child of another mixer and you can also assign a Transition Asset as an animation in a Mixer in the Inspector. So you could make a LinearMixerTransitionAsset and use it as the idle animation in your directional mixer.

    And the 3D Game Kit example has a fairly complex 3rd person character.

    I'd like to make a better 3rd person controller sometime, but that would require a bunch of animations with a free license that allows redistribution since I'm not an artist.
     
  13. LRG_ciaran

    LRG_ciaran

    Joined:
    Oct 15, 2021
    Posts:
    2
    Hey there!

    I'm having an issue with layering animations. I am playing a LocomotingAnimationA on layer 0 with no mask, then playing an animation on layer1 with an upper body mask. This works, but I don't want the animation on layer1 to get interrrupted if I call play on layer 0 with LocomotingAnimationB in the middle of the animation on Layer1. Specifically, I have an aim locomoting animation playing on layer 0, then I'm layering a reload animation on the upper body but letting go of reload and playing a regular locomoting animation on layer 0 which is interrupting my reload animation and auto fading out of it.
     
  14. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Playing an animation on layer 0 won't affect anything on layer 1. You must be doing something else to interrupt it.
     
  15. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    613
    Is there an API to play a clip (one time, non looping) and then play another clip after? (i.e. Idle -> Action -> Idle)
    This unit only has 2 animations (idle and action) so I didn't want to create a controller for it. I'm using the pro version

    Thanks
     
  16. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    A ClipTransitionSequence lets you set the first Clip and an array of Others which it will go through one by one. Or you could just play the Action and give it an End Event to play Idle (that's what a ClipTransitionSequence does internally).
     
    xjjon likes this.
  17. xjjon

    xjjon

    Joined:
    Apr 15, 2016
    Posts:
    613
    Thank you! That was exactly what I was looking for :cool:
     
  18. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    281
    Hello, I searched doc and forum but does not have my use case.
    If you want to have a repeated kicks which use just one kick animation, how to make it smoothly transit to itself ?
    To skip the animation when it reach a hit time, and if user want to kick again (by hitting attack button at time >=0.4, skip the recovery part), I will set state.NormalizedTime = 0f, you can guess that this will make the animation jump instead of fade, it's snappy.
    If I tell the animation to play (to itself) but do not set normalizedTime to 0, it will not play until it reach end time.
    I can think of a solution by clone the kick to make a slightly different kick and cycle between the two, just curious if Animancer have built-in solution for this problem.
     
  19. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    FadeMode.FromStart does exactly that, it creates a duplicate state if necessary so you don't have to worry about it.
     
  20. starfckr1

    starfckr1

    Joined:
    Apr 11, 2021
    Posts:
    25
    Hi! I have been using Animancer for a while now, and it been perfect so far. But i have run into one problem now which baffles me, and I am completely stuck.

    I am creating a 2D plattformer, and for some animations I want several layers of animations blending together (or, basically playing at the same time on the same character).

    I have seen all the examples from the documentation, but it only talks about layers on bones, whereas i only have sprite-animations that i want to play more than one of at the same time.

    I am declaring the layers when initializing my animation script, and setting IsAdditive to true.


    layer1 = _Animancer.Layers[0];
    layer2 = _Animancer.Layers[1];

    layer1.IsAdditive = true;
    layer2.IsAdditive = true;


    I also do GetOrCreateState() for all clips, on both layers, and I store the stateKey, layer, and other relevant information in a class, which is then run into a dictionary for easily getting the correct stateKey for clip X on layer Y.

    It seems that everything is working as intended. Both animations are running at the same time when viewing the Animancer component in the inspector, but only ONE of them is actually playing on screen.

    I tried to play around with weights, etc, but that has no effect at all (like setting both layers to 0.5 just result in nothing animating on screen) - so I am stumped here.. is this even possible?
     
  21. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Are your animations animating different SpriteRenderers? If so, I would expect them to work independently and this could be a bug somewhere. But if you only have one SpriteRenderer then it can only be showing one Sprite at a time so there's no way for it to blend. Alpha blending between sprites like layers in Photoshop would probably be possible to implement somehow, but there's no way for it to work out of the box with only a single SpriteRenderer. So if that's what you want, let me know and I'll have a go at it.

    Also, you likely don't need a dictionary of your own since Animancer already uses one internally. You can specify a key and clip in GetOrCreateState or set the Key of a state after creating it.
     
  22. starfckr1

    starfckr1

    Joined:
    Apr 11, 2021
    Posts:
    25
    Thank you for the quick reply! Before i start experimenting, do you have any thoughts on how i should go about implementing 2 spriterenders here?

    Since you cannot have 2 spriterenderes on the same gameobject I guess you would need two gameobjects, two sprite renderers, two animators and two AnimancerComponents, wherein they would only need one layer each i guess - and then play and control the animations independently of each other. Thoughts?

    The reason for my own dictionary is that I keep track of which layer is the active one and which is supplementary, and switch them around. I also have 1-4 clips per state, so i do some logic for getting the clip to play, and I need quite a bit of finegrained control for that - but you got me thinking I might be able to simplify this a bit.
     
  23. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Having multiple objects with their own SpriteRenderer, Animator, and AnimancerComponent should work.
    • Make a central component which keeps all the AnimancerComponents in a list then basically treat that as your list of layers.
    • Either expose the list publicly or give it a Play method which also takes a layer index.
    • You'll need to get the weight of the base layer in each AnimancerComponent every frame to set the corresponding SpriteRenderer's alpha.
    • If you use any other SpriteRenderer fields like Flip X / Y, you'll need to wrap those as well.
    If you don't mind sharing what you make, you could post it as a Github Issue and I'll suggest any changes I can think of. Otherwise, easy sprite blending seems like it could be a cool feature so I'll put it on my list of ideas to consider when I get some free time.
     
  24. starfckr1

    starfckr1

    Joined:
    Apr 11, 2021
    Posts:
    25
    I did a quick experiment with multiple spritrenderers, animators and animancercomponents now and it does work, but it also opens up a whole bunch of other issues that i would need to manually circumvent (because of other design choices on how i handle events during animations). There is a also quite a bit of logic needed to do manual weighting and fading out secondary animations, etc, towards the alpha on the sprites.

    Ended up abandoning this approach at the moment, but its something I would like to get into my final game at some point - so it would be awesome if this is something that could be incorporated into Animancer.

    Let me know if you need any input on the feature if you decide to go for it at some point :)
     
  25. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Good to know that the basic idea works at least. It would probably be best if you post a Feature Request explaining the problems you ran into in as much detail as possible so I don't end up building a system that you can't use anyway. Any ideas you have for how it could avoid those problems or how you'd want to interact with it would be helpful.
     
  26. Spikebor

    Spikebor

    Joined:
    May 30, 2019
    Posts:
    281
    Thanks for the prompt reply!
     
  27. sanchez_x

    sanchez_x

    Joined:
    Feb 9, 2019
    Posts:
    5
    We have a problem syncing the animation with our serverside (non Unity server) motions. The monster moves a distance in a given time in the client, and we should make the same distance in the same time on the server as well (using root motion). How can we get info about a run animation, how much it moves in the world in a loop cycle (if we can get this info, we can calculate how much it moves by milliseconds). We tried it with AverageVelocity/duration, but on some monster it works, on some of them not, and if we use scale, it completely screw things up. Any idea, how can we deal with this case?

    This how it looks currently:

    distance = CalcDistance(start_pos, dest_pos)
    motion_speed = AverageVelocity.z/duration
    move_duration = distance/motionspeed

    moveTimeInMs = move_duration * 1000


    What should be the correct formula?
     
  28. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    velocity = distance / time

    time = distance / velocity

    So I think you just want time = distance / AverageVelocity.z.
     
  29. sanchez_x

    sanchez_x

    Joined:
    Feb 9, 2019
    Posts:
    5
    Moving from A point to B point takes 1 second. The distance between them is 10m.
    So my velocity is 10/1 = 10m/s
    I move the character on the server in every 100 ms with 0.1m.
    This way it works, but the problem is, I have to test every monster/character in the editor manually, by moving 10m, to calculate how much time it was. If I do the same with AverageVelocity, on some monsters/characters kinda works (it's never exact), but on others doesn't, so something is affecting the velocity in the editor/client. The main problem is AverageVelocity is false, that's not the real world speed of the animation. I also found this forum: https://forum.unity.com/threads/how...humanoid-animations-with-root-motion.1312548/

    Which says there is a humanScale property which affects the animation and I tried to add that to the formula but it's still not correct. So is there any way to calculate it without testing manually every character in the game by moving them and manually writing down theirs time?
     
  30. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    I've never had to do anything like that, but I would have assumed that multiplying by humanScale should give you the speed for a given humanoid character.

    What do you get if you compare the same animation across several characters with different scales? Is the difference scaled more or less than their humanScale would indicate? Is the difference linear or inconsistent?

    Also, make sure you test without any physics components because friction and collisions could affect your results.
     
  31. sanchez_x

    sanchez_x

    Joined:
    Feb 9, 2019
    Posts:
    5
    It was totally inconsistent and the object doesn't had any rigidbody or collision. I gave up and I wrote a tool which reads the translation values from the .fbx file and this way I have the exact movement from every animation.
     
  32. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    When using a `ClipTransitionSequence`, what is the easiest way to skip/end the current animation and start the next one in the sequence? I'm not too worried about fade durations or what-have-you, just stop the current clip, start playing the next in the sequence. I did a search, but couldn't find anything that answered this question, sorry if this has been asked and answered already!
     
  33. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    • animancerComponent.States.Current.Clip
      will give you the currently playing clip.
    • Use a for loop to go through the sequence to find the index of that clip.
    • Then just play the next clip.
    I'm away from home at the moment so I can't test any proper code, but let me know if you have trouble figuring it out and I'll take another look when I get back tomorrow.
     
    Jos-Yule likes this.
  34. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    Nope that covers it, thanks!
     
  35. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Hey there. Ran into an trouble trying to make an object initialize to the first frame of the animation immediately after instantiation.
    The code below generates an error "Assertion failed on expression: 'm_DidAwake'" for the line with "Evaluate".

    Code (CSharp):
    1. using Animancer;
    2. using UnityEngine;
    3.  
    4. [RequireComponent(typeof(AnimancerComponent))]
    5. public class AnimancerPlayOnEnable : MonoBehaviour
    6. {
    7.     [SerializeField] private AnimationClip _animation;
    8.  
    9.     private AnimancerComponent _animancer;
    10.     private AnimancerComponent _AnimancerComponent => _animancer ?? (_animancer = GetComponent<AnimancerComponent>());
    11.  
    12.     private void OnEnable()
    13.     {
    14.         // play animation from the start
    15.         _AnimancerComponent.Play(_animation).NormalizedTime = 0;
    16.         // immediately apply the first frame
    17.         _AnimancerComponent.Evaluate();
    18.     }
    19. }
    error.png

    Since there seems to always be a 1-frame delay after playing before the animation is applied, are there other steps I can take to ensure that the animation state is immediately ready to be evaluated? Perhaps I'm going about this the wrong way?
     
  36. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Are you saying that you instantiate an object and tell it to play an animation, but it's still in its original pose for one frame before the animation actually starts? That was a bug in the Playables API way back in Unity 2017, but it was fixed and I haven't seen it since. Or are you just saying that you need to immediately evaluate the animation when it's instantiated for some other reason?

    Since the exception is coming from the PlayableGraph there probably isn't anything we can do about it directly, but I can think of a couple of workarounds to try:
    • Put a [DefaultExecutionOrder(1000)] attribute on the class so that it should initialize after the Animator does.
    • Otherwise, use Start instead of OnEnable because it runs a bit later (right before the first Update so hopefully the graph should be ready by then).
    • If even that doesn't help, another option (depending on your exact use case) might be to play the animation in Edit Mode before saving the prefab so that it's already in that pose.
     
  37. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Yes that is what I'm seeing. After instantiation, playing an animation will result in one frame of the initial pose. This was resolved in another case by using AnimancerComponent.Evaluate, but perhaps we didn't understand the actual issue at hand.

    If this was fixed long ago then I'm not sure why we are having this issue. I'll have to do some more testing in an isolated context.

    Thanks very much for the info and advice.
     
  38. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Just to follow up, I've done some testing in isolation and I am no longer seeing the frame delay or errors.

    Somehow our implementation is causing these issues. Our codebase is dense with legacy code and patterns like commands which could cause the frame delay or race conditions, along with nested animators & animancers, so I'll have to drill a little deeper to figure this one out. Thanks again.
     
  39. riizade

    riizade

    Joined:
    Apr 27, 2019
    Posts:
    3
    I am having issues nesting a DirectionalMixerState inside a ManualMixerState.

    Code (CSharp):
    1. // from elsewhere
    2. Animancer.AnimancerState baseAnimation = ... // this is a DirectionalMixerState
    3. Animancer.AnimancerState topAnimation = ... // this is a ClipState
    4.  
    5. // relevant portion
    6. this.blendedAnimation = new ManualMixerState();
    7. this.blendedAnimation.Initialize(2);
    8. this.blendedAnimation.SetChild(0, this.baseAnimation);
    9. this.blendedAnimation.SetChild(1, this.topAnimation);
    10. this.animancer.Play(this.blendedAnimation);
    The above code snippet results in
    Code (csharp):
    1.  
    2. ArgumentException: The Playable is invalid. It has either been Disposed or was never created.
    3. UnityEngine.Playables.PlayableHandle.SetSpeed (System.Double value) (at <4a31731933e0419ca5a995305014ad37>:0)
    4. ...
    5.  
    However, if I change `baseAnimation` to be a `ClipState`, it works as expected.
    Additionally, if I play the `DirectionalMIxerState` directly, it works as expected.

    Code (CSharp):
    1.  
    2. // working example 1
    3. Animancer.AnimancerState baseAnimation = ... // this is a ClipState
    4. Animancer.AnimancerState topAnimation = ... // also a ClipState
    5.  
    6. this.blendedAnimation = new ManualMixerState();
    7. this.blendedAnimation.Initialize(2);
    8. this.blendedAnimation.SetChild(0, this.baseAnimation);
    9. this.blendedAnimation.SetChild(1, this.topAnimation);
    10. this.animancer.Play(this.blendedAnimation);
    11.  
    12. // working example 2
    13. Animancer.AnimancerState baseAnimation = ... // this is a DirectionalMixerState
    14. Animancer.AnimancerState topAnimation = ... // this is a ClipState
    15.  
    16. this.animancer.Play(this.baseAnimation);
    17.  
    Interestingly, if I construct the mixer, then try to play _just_ the baseAnimation, that also fails, but with a different error

    Code (CSharp):
    1.  
    2. // from elsewhere
    3. Animancer.AnimancerState baseAnimation = ... // this is a DirectionalMixerState
    4. Animancer.AnimancerState topAnimation = ... // this is a ClipState
    5.  
    6. // relevant portion
    7. this.blendedAnimation = new ManualMixerState();
    8. this.blendedAnimation.Initialize(2);
    9. this.blendedAnimation.SetChild(0, this.baseAnimation);
    10. this.blendedAnimation.SetChild(1, this.topAnimation);
    11. this.animancer.Play(this.baseAnimation); // note I am playing the base animation, NOT the blended animation
    12.  
    produces the following error
    Code (csharp):
    1.  
    2. ArgumentNullException: Value cannot be null.
    3. Parameter name: The Playable is null.
    4. UnityEngine.Playables.PlayableGraph.ConnectInternal (UnityEngine.Playables.PlayableHandle source, System.Int32 sourceOutputPort, UnityEngine.Playables.PlayableHandle destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    5. ...
    6.  
    I'm pretty lost here. The documentation available at https://kybernetik.com.au/animancer/docs/manual/blending/mixers/creation/ is pretty straightforward, and I think I've created the ManualMixerState correctly, but clearly something is wrong.

    It seems like it might have something to do with the Root animancer playable of the DirectionalMixerState being null, but attempting to generate it with
    this.baseAnimation.Play();
    before adding it to the ManualMixerState, or after adding but before calling
    this.animancer.Play(this.blendedAnimation);
    both do not seem to resolve the issue.

    Can you help clarify my misunderstandings or help me understand what's going on?
     
  40. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Calling state.SetRoot(animancer) on each of the states and the mixer should avoid the problem, though your code looks fine so I'm not sure why it would be giving that error since calling animancer.Play should be doing that automatically. I'll take a look at it when I have time later today.

    Calling Play on an animation inside a mixer like that makes no sense, but it shouldn't cause an error. What's the full stack trace of that error?

    Also, are you using the latest version of Animancer (v7.3)?
     
  41. riizade

    riizade

    Joined:
    Apr 27, 2019
    Posts:
    3
    I am on the latest 7.3 (downloaded from itch.io last week or so).

    The full stack trace of the condition where I play an animation that has a ManualMixerState parent is as follows:
    Code (csharp):
    1.  
    2. ArgumentNullException: Value cannot be null.
    3. Parameter name: The Playable is null.
    4. UnityEngine.Playables.PlayableGraph.ConnectInternal (UnityEngine.Playables.PlayableHandle source, System.Int32 sourceOutputPort, UnityEngine.Playables.PlayableHandle destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    5. UnityEngine.Playables.PlayableGraph.Connect[U,V] (U source, System.Int32 sourceOutputPort, V destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    6. Animancer.AnimancerNode.ConnectToGraph () (at Assets/Plugins/Animancer/Internal/Core/AnimancerNode.cs:226)
    7. Animancer.AnimancerNode.ApplyConnectedState (Animancer.IPlayableWrapper parent) (at Assets/Plugins/Animancer/Internal/Core/AnimancerNode.cs:260)
    8. Animancer.AnimancerNode.CreatePlayable () (at Assets/Plugins/Animancer/Internal/Core/AnimancerNode.cs:77)
    9. Animancer.AnimancerState.CreatePlayable () (at Assets/Plugins/Animancer/Internal/Core/AnimancerState.cs:303)
    10. Animancer.AnimancerState.SetRoot (Animancer.AnimancerPlayable root) (at Assets/Plugins/Animancer/Internal/Core/AnimancerState.cs:75)
    11. Animancer.AnimancerLayer.AddChild (Animancer.AnimancerState state) (at Assets/Plugins/Animancer/Internal/Core/AnimancerLayer.cs:178)
    12. Animancer.AnimancerLayer.Play (Animancer.AnimancerState state) (at Assets/Plugins/Animancer/Internal/Core/AnimancerLayer.cs:435)
    13. Animancer.AnimancerPlayable.Play (Animancer.AnimancerState state) (at Assets/Plugins/Animancer/Internal/Core/AnimancerPlayable.cs:692)
    14. Animancer.AnimancerComponent.Play (Animancer.AnimancerState state) (at Assets/Plugins/Animancer/AnimancerComponent.cs:444)
    15. AnimationManager.UpdateBlendedAnimation () (at Assets/Code/Main/Animation/AnimationManager.cs:194)
    16. AnimationManager.SetBaseAnimation (Animancer.AnimancerState animation) (at Assets/Code/Main/Animation/AnimationManager.cs:153)
    17. PlayerAnimationManager.Start () (at Assets/Code/Main/Animation/PlayerAnimationManager.cs:38)
    18.  
    Calling
    SetRoot()
    requires an argument of type
    AnimancerPlayable
    , and I'm not sure how to go about procuring one.

    I've tried
    Code (CSharp):
    1.  
    2. this.baseAnimation.SetRoot(this.animancer.Playable);
    3. this.topAnimation.SetRoot(this.animancer.Playable);
    4. this.blendedAnimation.SetRoot(this.animancer.Playable);
    5.  
    which fails with
    Code (csharp):
    1.  
    2. ArgumentNullException: Value cannot be null.
    3. Parameter name: The Playable is null.
    4. UnityEngine.Playables.PlayableGraph.ConnectInternal (UnityEngine.Playables.PlayableHandle source, System.Int32 sourceOutputPort, UnityEngine.Playables.PlayableHandle destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    5. UnityEngine.Playables.PlayableGraph.Connect[U,V] (U source, System.Int32 sourceOutputPort, V destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    6. Animancer.AnimancerNode.ConnectToGraph () (at Assets/Plugins/Animancer/Internal/Core/AnimancerNode.cs:226)
    7. ...
    8.  
    as well as simply
    Code (CSharp):
    1.  
    2. this.blendedAnimation.SetRoot(this.animancer.Playable);
    3.  
    which fails with
    Code (csharp):
    1.  
    2. ArgumentException: The Playable is invalid. It has either been Disposed or was never created.
    3. UnityEngine.Playables.PlayableHandle.SetSpeed (System.Double value) (at <4a31731933e0419ca5a995305014ad37>:0)
    4. UnityEngine.Playables.PlayableExtensions.SetSpeed[U] (U playable, System.Double value) (at <4a31731933e0419ca5a995305014ad37>:0)
    5. Animancer.MixerState.ApplySynchronizeChildren (System.Boolean& needsMoreUpdates) (at Assets/Plugins/Animancer/Internal/Mixer States/MixerState.cs:923)
    6. ...
    7.  
    8.  
    I didn't really expect either approach to work, since I think there's a more appropriate
    AnimancerPlayable
    I should be setting.

    Code (csharp):
    1.  
    2. this.topAnimation.SetRoot(AnimancerPlayable.Create());
    3. this.blendedAnimation.SetRoot(AnimancerPlayable.Create());
    4. this.baseAnimation.SetRoot(AnimancerPlayable.Create());
    5.  
    gives

    Code (csharp):
    1.  
    2. ArgumentNullException: Value cannot be null.
    3. Parameter name: The Playable is null.
    4. UnityEngine.Playables.PlayableGraph.ConnectInternal (UnityEngine.Playables.PlayableHandle source, System.Int32 sourceOutputPort, UnityEngine.Playables.PlayableHandle destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    5. UnityEngine.Playables.PlayableGraph.Connect[U,V] (U source, System.Int32 sourceOutputPort, V destination, System.Int32 destinationInputPort) (at <4a31731933e0419ca5a995305014ad37>:0)
    6. Animancer.AnimancerNode.ConnectToGraph () (at Assets/Plugins/Animancer/Internal/Core/AnimancerNode.cs:226)
    7.  
    and

    Code (csharp):
    1.  
    2. this.topAnimation.SetRoot(AnimancerPlayable.Current);
    3. this.blendedAnimation.SetRoot(AnimancerPlayable.Current);
    4. this.baseAnimation.SetRoot(AnimancerPlayable.Current);
    5.  
    gives
    Code (csharp):
    1.  
    2. ArgumentException: The Playable is invalid. It has either been Disposed or was never created.
    3. UnityEngine.Playables.PlayableHandle.SetSpeed (System.Double value) (at <4a31731933e0419ca5a995305014ad37>:0)
    4. UnityEngine.Playables.PlayableExtensions.SetSpeed[U] (U playable, System.Double value) (at <4a31731933e0419ca5a995305014ad37>:0)
    5. Animancer.MixerState.ApplySynchronizeChildren (System.Boolean& needsMoreUpdates) (at Assets/Plugins/Animancer/Internal/Mixer States/MixerState.cs:923)
    6.  
    The error messages each print every frame, not just when I set the animations during object initialization.

    Where do I get an
    AnimancerPlayable
    ?
    Any idea what could be invalid about my
    DirectionalMixerState
    , given that it plays as expected when not parented to a
    ManualMixerState
    ? (The error also happens with other parents, such as
    LinearMixerState
    , too).
     
  42. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    animancer.Playable
    is correct and shouldn't be giving any errors.

    AnimancerPlayable.Create()
    would create an entirely new PlayableGraph for each one (in addition to the one the character makes normally). That wouldn't work at all, especially if you then try to connect states to a mixer in a different graph.

    AnimancerPlayable.Current
    is only set during an update, so you're effectively just calling SetRoot(null).

    If you can send me a minimal reproduction project (either in a private conversation here or email animancer@kybernetik.com.au), that would make it much easier for me to track down the issue when I get to it.
     
  43. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Looks like the things you're trying to do don't really make sense so I've added some more descriptive error messages:
    • If SetRoot was necessary, it would only need to be called on the parent mixer. Trying to call it on a child will now throw: Unable to set the Root of a state which has a Parent. Setting the Parent's Root will apply to its children recursively because they must always match.
    • And telling a layer (or the root AnimancerComponent or AnimancerPlayable) to play a state that's a child of a mixer makes no sense. That method stops all other states on the layer, so even if I made it avoid throwing that exception it would stop every state including the mixer (because the parent mixer isn't the state you told it to play), which could be done by just calling Stop. So attempting to do that will now throw: A layer can't Play a state which is the child of another state. The state's Parent must be either null or a layer and it will be moved to this layer.
    Why are you calling
    this.animancer.Play(this.blendedAnimation);
    ? What are you actually expecting it to do?
     
  44. devito02

    devito02

    Joined:
    Oct 20, 2019
    Posts:
    3
    HI, I don't think you have mentioned in another post as I searched throughout several keywords but found nothing.
    My issue Is that Im building a FSM system with ScriptableObject and IState which hold ClipTransitions and logic for carrying out that particular State. The Problem is that indeed SO can't hold reference to scene objects. All the method I have found online are really not efficient or straight up dangerous for what could go wrong. I have considered of course statebeheaviours but due to the nature of my project, which is SO-based using SO for FSM states would be really efficient, on the other hand things like playing an animation can only be done outside the state script (like inside the brain). Am I missing something is there an easier and more proper way than defining some new arbitrary onEnter function passing the necessaries parameters? How did you define a proper way of implementing states trough SO?
     
  45. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,699
    Hi @Kybernetik,
    How are you?
    I am curious, I have an Event, onAnimationEnd that is calling correctly, however with one issue. Despite the animation clip, not being set to Loop, the event is fired, endlessly..... Seemingly every frame.

    Besides using my own conditions to prevent multiple calls, is there a way I can avoid this?

    Thanks

    Code (csharp):
    1.  
    2.  
    3.     public void playClip(AnimationClip clip)
    4.     {
    5.  
    6.  
    7.  
    8.  
    9.         clipInUse = clip;
    10.         //animanc/er.Stop();
    11.         var state = animancer.Play(clip);
    12.         state.Speed = clipSpeed;
    13.         state.Events.OnEnd = OnAnimationEnd;
    14.        
    15.  
    16.  
    17.  
    18.  
    19.  
    20.  
    21.  
    22.     }
    23.  
     
  46. devito02

    devito02

    Joined:
    Oct 20, 2019
    Posts:
    3

    Also wanna add that I tried to instantiate the SO and then assigning them scene reference and it did, the state was entered but the logic didn't work until I switched to a state manually, and I mean the asset one , not the instantiated.one
     
  47. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    @devito02 I've never used my FSM system with ScriptableObjects, but you could try something like this:
    1. Make a StateMachine child class which references any scene objects you need.
    2. Use
      (YourStateMachineType)StateChange<YourBaseState>.StateMachine
      to get the current character's state machine during any On/Can Enter/Exit function.
    Code (CSharp):
    1. public class CharacterStateMachine : StateMachine<CharacterState>
    2. {
    3.     public readonly Character Character;
    4.  
    5.     public CharacterStateMachine(Character character)
    6.     {
    7.         Character = character;
    8.     }
    9. }
    10.  
    11. // Then during a state change:
    12. Character currentCharacter = ((CharacterStateMachine)StateChange<CharacterState>.StateMachine).Character;
    @renman3000 That behaviour is by design as explained here. If you don't want it, you could just use a regular Animancer Event instead of an End Event.
     
    renman3000 and devito02 like this.
  48. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    857
    I'm getting some gc allocations when using playing cliptransitions. Is this normal?

    I did a deep profile of some instances of it though I don't fully understand whats going on.
    Unity_ZQH9hLGczB.png

    Ive tested both using inspector events and events from code

    Unity_dc6Mf9i86e.png

    The code itself seems pretty pedestrian, the method below is what is wrapped in a profiler sample for the above screenshot.

    Code (CSharp):
    1.         public static void PlayAnimation(AnimancerComponent animancer, ClipTransition transition, bool painAnimationIsActive)
    2.         {
    3.             // Dont play pain animation if we are already playing one
    4.             if(painAnimationIsActive)
    5.                 return;
    6.             // Double check that we are not playing an animation already
    7.             if(!transition.State.IsActive)
    8.                 animancer.Play(transition);
    9.         }
     
  49. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Make sure you don't have the transition visible in the Inspector while you're profiling because the way the drawer works can unfortunately cause the transition to be re-allocated continuously which you wouldn't directly see in there, but a new transition would allocate a new event sequence when played so that could be what you're seeing.

    Otherwise, feel free to send a minimal reproduction project to animancer@kybernetik.com.au (or send me a private message here) and I'll take a look at it.
     
    thelebaron likes this.
  50. devito02

    devito02

    Joined:
    Oct 20, 2019
    Posts:
    3
    Woah thank you man, also wanna add that it's incredible the effort you are putting in animancer, I really get the feeling it's a incredibly solid asset and there's so much to uncover, and also your tutorial are borderline c# tutorial for how much you help someone understand the concept itself, thank you man
     
    Kybernetik and ratking like this.