My TransitionAsset Transition type is ClipTransition
Idle_Normal2.MaximumDuration
Itās not called Length
because other state types like Mixers and Controller States can have a variable length depending on their parameters, but for a ClipState
/ ClipTransition
itās just the Length
.
Whats that warning means? i just want to repeat a TransitionAsset clipTransition,is like a LOL hero atk can be interrupted and repeated,now it work right,but i wonder that warning,it warning just at the first time when Atk_Normal1 gona to be end
It means that whatever youāre doing in SetCurrentStates
isnāt telling Animancer to stop the current animation or play something, which often indicates an issue with your logic. If you have some other system that will play something later on in response to something that was set during the event, Animancer canāt detect that so you can just disable the warning.
problem solved, thanks a lot.
This plugin seems incredibly promising! Iām surprised it hasnāt gained more recognition on this forum. Iāve reached a point where Iām fed up with dealing with Animator FSM graphs and want to switch everything back to code. Iām definitely purchasing this plugin to escape the frustration of Animator graphs. Well done!"
ć«ć¤ć
animancer.States.GetOrCreate(transition)
will create the state without playing it so you can add the events.
i want to use Dynamic Layers
i know fade out layer,but how to fade in layer and set layer weight
i set StartFade parameter but it is not work,its weight is still 1 when PlayQ
like this Action Layer , i want to set layer weight is 0.5 before play Skill_Q1 Clipļ¼but it still 1 weight
Playing something on a layer will automatically fade it in to Weight 1 so you should get what you want if you start your fade after calling Play.
So we have our own kinematic character movement controller that uses FixedUpdate(). The problem we are running into is that because we accumulate root motion in OnAnimatorMove() (which happens on Update()) and apply it in our character movement controllerās FixedUpdate(), there are root motion translation discrepancies when we have frame rate variance. This is resolved when we set the Animatorās UpdateMode to AnimatePhysics, however that causes our animations to be jittery.
Is there anyway to get root motion information from an animation in FixedUpdate(), but have that animation play smoothly? My current plan is to attempt to apply this technique: Motion Interpolation Solution (to eliminate FixedUpdate() stutter). However, I wasnāt sure if doing something like this is even possible in Animancer, or if thereās another simpler way Iām not thinking about.
Animancerās updating is all handled by Unity in the same systems it uses for Animator Controllers so you should be able to do the same interpolation. Iāve never tried anything like that so Iād be interested to hear if you can get it working.
Darnā¦I was afraid youād say that lol. So what I think would be helpful to know is what methods allow me to move an animation while ensuring animation events get invoked, as well as ones that donāt?
Setting an AnimancerState.Time
skips events and root motion.
Calling AnimancerState.MoveTime
doesnāt, as long as you make sure not to call it more than once per frame due to a stupid design decision in the Playables API.
What does Animancer.Playable.Evaluate() do? Is that something I need to call in addition to MoveTime(), or instead of?
(post deleted by author)
So Iāve got something thatās working pretty well, however it breaks down whenever I set a LinearMixerTransitionās float Parameter. It appears to be somehow conflicting with the Time Iām setting in this component. Maybe you could help me figure out what I might be overlooking here?
using System.Collections.Generic;
using Animancer;
using UnityEngine;
public class AnimancerInterpolatorComponent : MonoBehaviour
{
// Struct containing cached animancer state data.
private readonly struct AnimancerStateData
{
public float Time { get; }
private AnimancerStateData(float time)
{
Time = time;
}
public static AnimancerStateData CreateFromState(AnimancerState state)
{
return new AnimancerStateData(state.Time);
}
public void ApplyToState(AnimancerState state)
{
state.Time = Time;
}
}
[SerializeField]
[HideInInspector]
private AnimancerComponent _animancer;
public bool RootMotionDeltasValid { get; private set; }
private AnimancerComponent Animancer
{
get => _animancer;
set => _animancer = value;
}
private Dictionary<AnimancerState, AnimancerStateData> CurrentAnimancerStateData { get; } = new();
private Dictionary<AnimancerState, AnimancerStateData> PreviousAnimancerStateData { get; } = new();
private void Awake()
{
// Prevent graph from updating on its own.
Animancer.Playable.PauseGraph();
}
private void FixedUpdate()
{
foreach (var state in Animancer.States)
{
if (state.Weight <= 0f)
{
continue;
}
if (!CurrentAnimancerStateData.TryGetValue(state, out var stateData))
{
stateData = AnimancerStateData.CreateFromState(state);
CurrentAnimancerStateData[state] = stateData;
PreviousAnimancerStateData[state] = stateData;
}
// When a state's speed is 0, we assume its time is being managed externally.
if (state.Speed != 0f)
{
stateData.ApplyToState(state);
}
}
Animancer.Playable.Evaluate();
// Tells the root motion redirector to only respect deltaPosition/deltaRotation values when this flag is set.
RootMotionDeltasValid = true;
Animancer.Playable.Evaluate(Time.fixedDeltaTime);
RootMotionDeltasValid = false;
foreach (var (state, stateData) in CurrentAnimancerStateData)
{
PreviousAnimancerStateData[state] = stateData;
}
foreach (var state in Animancer.States)
{
CurrentAnimancerStateData[state] = AnimancerStateData.CreateFromState(state);
}
}
private void LateUpdate()
{
// (Time.time - Time.fixedTime) is the "unprocessed" time according to documentation.
var interpolationAlpha = (Time.time - Time.fixedTime) / Time.fixedDeltaTime;
foreach (var (state, stateData) in CurrentAnimancerStateData)
{
if (state.Weight <= 0f
|| state.Speed == 0f
|| !PreviousAnimancerStateData.TryGetValue(state, out var previousStateData))
{
continue;
}
state.Time = Mathf.Lerp(previousStateData.Time, stateData.Time, interpolationAlpha);
}
Animancer.Playable.Evaluate();
}
#if UNITY_EDITOR
private void OnValidate()
{
if (TryGetComponent<AnimancerComponent>(out var animancer))
{
Animancer = animancer;
}
}
#endif
}
Your logic looks reasonable and time shouldnāt have any connection with a mixer parameter so Iām not sure what could be wrong.
If you want to send a minimal reproduction project to animancer@kybernetik.com.au Iād be happy to take a look at it.
So I solved that issue, now the last thing to resolve is that because Iām using Evaluate() 3 times, itās triggering AnimancerEvents multiple times. Do you have a recommended method for temporarily disabling AnimancerEvent invocation? I was thinking about nulling out the AnimancerStateās Events before calling Evaluate() then reassigning after, but wasnāt sure if you had a safer, less disruptive approach.
EDIT: Upon testing, nulling out the AnimancerStateās Events before calling Evaluate() did not seem to work