Hello there,
I am working in a concert simulation from a while, and I am having trouble with avatar masks and timeline.
Here is my organization:
-In the animator, I have a base layer with a walk blendtree, that receives the direction of movement, and adjusts the animation properly.
-Also in the animator, I have an avatar mask to add a PlayingGuitar animation. This works fine, and makes the character walk while playing the guitar. Nothing to see here.
The intended result is: My characters moves and plays the guitar, and when the timeline reaches the clip, the torso and the head start to move as the clip says (while playing the guitar and moving).
The real result is that the torso and head plays the clip, but the rest of the body, instead of following the animator rules (a.k.a, playing the guitar and walking), just freezes in a strange position:
Is this a problem of the avatar mask? Animation import? Or is that animator blendtrees are not blendeable with timeline?
Ok, after a little bit of searching, I found that Avatar masks on Timeline don’t work properly with Animator, probably due to a bug:
If that’s the case, and Timeline clips cannot be used without killing th animator underneath, what could be the best alternative? My idea is to put the override animations in the Animator, link them to a parameter to control when each animation should play, and use an animation track on the timeline to animate a custom script that changes the parameters.
Another option is to use signal emitters to tell the animator to play the animations at the correct time.
Both options are workarounds I am not comfortable with, but seems that Timeline overrides completely all Animator works, and I cannot find so much information about Timeline Masks.
Any suggestion will be appreciated.
Edit: after more thoughts, I have another option. I can create a Custom Timeline Track that directly activates a given animator parameter on start. That will save me a custom script in each object.
Bump! I have similar issue. I have upper body attack animations and I want to use Mechanim for locomotion and blend it with attacks. Reason why I want to use timelines is because that way I can easily author also wepon anims, patricles, effects and so on. Also from code can easily check if timeline has been fully played which is very finnyicky to do with Mechanim.
It would be so good to put Animator component as anim clip in timeline or to have a blend anim clips.
I manage to do it kind of elegantly using custom tracks that changes animator parameters. Its a bit of pain, because you have to code three scripts, built the animator, and you cannot preview the animation on timeline, but once you have it, the workflow is kind of straightforward.
If you are unfamiliar with timeline coding, I recommend you this tutorial
The code I use:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Timeline;
[TrackColor(0, 0, 255)]
[TrackBindingType(typeof(Animator))]
[TrackClipType(typeof(AnimatorParameterClip))]
public class AnimatorParameterTrack : TrackAsset
{
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
[System.Serializable]
public class AnimatorParameterClip : PlayableAsset, ITimelineClipAsset
{
[SerializeField]
private AnimatorParameterBehaviour template = new AnimatorParameterBehaviour();
public ClipCaps clipCaps
{
get { return ClipCaps.None; }
}
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
{
return ScriptPlayable<AnimatorParameterBehaviour>.Create(graph, template);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
[System.Serializable]
public class AnimatorParameterBehaviour : PlayableBehaviour
{
[SerializeField]
private int animationIndex = 0;
Animator anim;
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
anim = playerData as Animator;
if (anim == null)
return;
anim.SetInteger("animationIndex", animationIndex);
}
public override void OnBehaviourPause(Playable playable, FrameData info)
{
if (anim == null)
return;
anim.SetInteger("animationIndex", 0);
}
}
Obviously, instead of anim.SetInteger, you should put whatever you need.