- Home /
Procedurally generate AnimationClip at runtime
I need a way to generate new AnimationClip at run-time. But I found that when generate new animation clip, the "Stop Time" parameter in animation setting would be set at default of 1. Is there a way to set this at run-time not via editor.
Thanks for all your help.
Answer by yashpal · Feb 27, 2015 at 09:19 AM
hello @GoodyTong ,
1) create new animation clip. link
2) make animation Curve. link
Stop Time is directly set with last key position. so if you move last key position stop time also change with that.
3) to move keyFrame link
4) Set Animation Curve.
Hope it helps.
int index = animationCurve.Add$$anonymous$$ey(keyframe);
animationCurve.$$anonymous$$ove$$anonymous$$ey(index, keyframe);
animationClip.SetCurve("", typeof(Animator), propertyName, animationCurve);
I do exactly as you describe by move last keyframe in AnimationCurve but still length of the generated AnimationClip still at "1"
hello @GoodyTong,
This is The code where you can change the length of your animation.
void Start () {
Animation anim = GetComponent<Animation>();
AnimationCurve curve = AnimationCurve.Linear(0, 0, 2, 2); //You can change the animation length from here also.
AnimationClip clip = new AnimationClip();
$$anonymous$$eyframe keyNew = new $$anonymous$$eyframe (5, 10f);
curve.$$anonymous$$ove$$anonymous$$ey (curve.keys.Length-1,keyNew);
// curve.Add$$anonymous$$ey (5, 10f);
clip.SetCurve ("", typeof(Transform), "localPosition.x", curve);
anim.AddClip(clip, "walk");
anim.Play ("walk");
Debug.Log ("anim [walk].length : " + (anim ["walk"].length)); // This is gives animation langth.
}
Actually, this does not work (tested with Unity 5.5.2f1). However, changing the propertyName parameter in the SetCurve call to "m_LocalPosition.x" works:
clip.SetCurve("", typeof(Transform), "m_LocalPosition.x", curve);
Can somebody explain this strangeness?
"m_LocalPosition.x" is the serialization name of the x position of the built-in Transform component. Built-in components don't have fields in their managed class. The actual fields are stored in the native C++ class. That's where the "strange" serialization name comes from.
If you don't know how a certain property is named you can do:
create a new project and set the asset serialization mode to "force text" (Edit->ProjectSettings->Editor->Asset serialization).
create an empty gameobject and add an Animation component.
create an animation (clip) as asset in the project window and add it to the animations array of the animation component.
open the Animation window from the window menu
Now just add the properties you want to know the name of and add at least one keyframe.
When done make sure you hit "File->Save Project" to ensure the file is written properly to disk.
Now open the animation clip file in a proper text editor (notepad doesn't work since the file only uses linefeed characters as line breaks. Notepad++ would work just fine)
Scroll down until you find "m_EditorCurves". Each curve in that array has an "attribute" field which contains the serialization name of the property it animates
m_EditorCurves:
- curve:
attribute: m_LocalPosition.x
All of this is for the legacy Animation component, not its new replacement Animator. The new Animator component seems far more limited, eg SetCurve() isn't supported. How are we supposed to do this sort of thing without relying on old legacy components that could disappear at any time?
you might want to look at Playables, maybe?
"The Playables API allows for dynamic animation blending. This means that objects in the scenes could provide their own animations. For example, animations for weapons, chests, and traps could be dynamically added to the PlayableGraph and used for a certain duration.
The Playables API allows you to easily play a single animation without the overhead involved in creating and managing an AnimatorController asset.
The Playables API allows users to dynamically create blending graphs and control the blending weights directly frame by frame.
A PlayableGraph can be created at runtime, adding playable node as needed, based on conditions. Ins$$anonymous$$d of having a huge “one-size-fit-all” graph where nodes are enabled and disabled, the PlayableGraph can be tailored to fit the requirements of the current situation."
Answer by Hellium · Mar 20, 2019 at 10:06 AM
As pointed out by @RobAtApex, the Animation
component is now depreciated and should not be used for new projects.
However, the information given by @yashpal are still valid. The "only" things that change are the use of the Animator
component instead of the Animation
one.
First of all, you have to create an Animator controller asset in your project. In this controller, add an empty state that will be played automatically (name it as you want : Default
for instance)
Then, in code, you will create (at runtime), an animator controller override and you will specify the animation clip you have created.
using UnityEngine;
public class AnimatorBehaviourScript : MonoBehaviour
{
// Drag & drop the animator component
[SerializeField]
private Animator animator;
// Specify the name of the default state of the animator
[SerializeField]
private string stateName = "Default";
private AnimatorOverrideController animOverrideController;
private AnimationClip animationClip;
void Start ()
{
AnimationClip animationClip = CreateAnimationClip();
SetClip( animationClip, stateName );
}
private AnimationClip CreateAnimationClip()
{
// Create animation clip
// This is an example
AnimationCurve translateX = AnimationCurve.Linear(0.0f, 0.0f, 2.0f, 2.0f);
AnimationClip animationClip = new AnimationClip();
animationClip.SetCurve("", typeof(Transform), "m_localPosition.x", translateX);
}
private void SetClip( AnimationClip animationClip, string state )
{
AnimatorOverrideController animatorOverrideController = new AnimatorOverrideController();
animatorOverrideController.runtimeAnimatorController = animator.runtimeAnimatorController;
animatorOverrideController[state] = animationClip;
animator.runtimeAnimatorController = animatorOverrideController;
}
}
The only problem is that you can't use SetCurve at runtime, cf note from documentation
Note: SetCurve will only work at runtime for Legacy AnimationClips. For Non-Legacy AnimationClips it is an editor-only function.
Do you have any alternative to create animationClip at runtime ? thx
$$anonymous$$y bad, I didn't know this. Unfortunately, I don't know any other way to create an animationClip at runtime.
Answer by ShawnFeatherly · Apr 17, 2019 at 12:38 AM
There's ways other than building an AnimationClip to generate animation. Try building by inheriting these two classes:
PlayableBehaviour - the logic of how your animation will be generated.
PlayableAsset - Allows that logic to be put into Timeline.
There's a great rundown of how to use those two classes on https://blogs.unity3d.com/2018/09/05/extending-timeline-a-practical-guide/
Note, with this method you can't generate animation based on frames or seconds into a clip. Instead you can rely on the percentage you are into a clips duration.
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
double percent = playable.GetTime() / playable.GetDuration();
Your answer
Follow this Question
Related Questions
Animating: Object does not rotate as it should. 4 Answers
How do I Edit an Animation in the Animation Bar? 2 Answers
Animation lengths doesn't match 1 Answer
Animated objects rotation is flawed. 1 Answer
Animation Bugging out 2 Answers