Lack of scripting functionality for creating 2D animation clips by code

I was having some doubts either to post this in the 2D or the Animation forum because my problems are related to both of them at the same time, but decided to write it here because they serve no purpose for 3D animation (except for the 2nd listed below).

So, I’m creating a plugin that will extract 2D bone animation data from a text file and create the animations inside unity as .anim so that I can use the new 2D Mecanim integration.

I’ll list the problems I’ve faced until now. For some of them I found a workaround. They’re all related to creating an animation clip via scripting.

1-> Procedurally created Animation Clip cannot be used in Animator Controller

After creating the animation clip in my script, when I attempted to use it in an Animator Controller I’d receive a warning message telling me that the animation clip could not be used because it contained no Muscle Definition and that I should change the Importer Settings to fix that.

Well, as far as I know, there’s no such thing for 2D animation clips and also there’s no animation Importer Settings if I’m creating it by code, right? But one of the new 2D features allow you to create a 2D animation clip that works on Animator Controller by dragging a couple of sprites to the “Hierarchy” panel. But there is no way, at least I have not found it, to set the muscle definition for an animation clip by code.

WORKAROUND: I’ve created an 2D animation clip the “drag’n’drop” way and cleared its curves, resulting in an “empty animation” asset. The settings needed for the Animation Controller (muscle definition, …?) are not lost this way. Then, for each animation that I need to create, I duplicate this “empty animation” and put my own curves on it. By doing that I’m able to create an animation clip via scripting and use it in the Animator Controller. Not the prettiest thing, I know, but it works, at least…

2-> Artifacts with the rotation curves

This is not really a lack of scripting functions but the lack of their documentation. I had some problems with rotation artifacts, but it has already been solved (http://forum.unity3d.com/threads/212198-Problem-with-rotation-artifacts-when-creating-animation-clip-procedurally) using the AnimationClip.EnsureQuaternionContinuity function.

3-> How to set a keyframe to change the sprite of a SpriteRenderer at a given time.

For what I’ve seen, the only data that you can input to an AnimationClip is AnimationCurves. The AnimationCurve is made of Keyframes and these are made of two floats, time and value. How could I set a keyframe so that at 3 seconds, the SpriteRenderer would change a sprite from “eyeOpen” to “eyeClose” if all I can do is set a float for a given time? This is a functionality that is available through the “Animation Window”, but I can’t find a way to do it via scripting.

To sumarize it all, I’m very happy with the new 2D features. They’re awesome and all, but I’m a little bit frustrated that there are so many features available through “drag’n’drop” in the editor that cannot be reproduced in scripts. Perhaps I’m doing it all wrong and this the “legacy” way of doing animation by code but this is the only way I was able to do it.

Thanks for reading and please let me know if you’ve faced this or similar problems and how you solved them.

1 Like

Okay, I found a class (AnimationUtility) that helped me to fix all of the things that I cited. As the documentation on this subject is not the best, I’ll try and explain what I did to fix it all.

1-> Procedurally created Animation Clip cannot be used in Animator Controller

AnimationClip animClip = new AnimationClip();
// Setting it as generic allows you to use the animation clip in the animation controller
AnimationUtility.SetAnimationType(animClip, ModelImporterAnimationType.Generic);

2-> Artifacts with the rotation curves

AnimationClip animClip = new AnimationClip();      

// Add rotation curves to it
//...
//...

animClip.EnsureQuaternionContinuity();

3-> How to set a keyframe to change the sprite of a SpriteRenderer at a given time

The AnimationUtility allows you to add a different keyframe, the ObjectReferenceKeyframe. Example code:

AnimationClip animClip = new AnimationClip();

// First you need to create e Editor Curve Binding
EditorCurveBinding curveBinding = new EditorCurveBinding();

// I want to change the sprites of the sprite renderer, so I put the typeof(SpriteRenderer) as the binding type.
curveBinding.type = typeof(SpriteRenderer);
// Regular path to the gameobject that will be changed (empty string means root)
curveBinding.path = "";
// This is the property name to change the sprite of a sprite renderer
curveBinding.propertyName = "m_Sprite";

// An array to hold the object keyframes
ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[10];

for (int i = 0; i < 10; i++)
{
     keyFrames[i] = new ObjectReferenceKeyframe();
     // set the time
     keyFrames[i].time = timeForKey(i);
     // set reference for the sprite you want
     keyFrames[i].value = spriteForKey(i);

}

AnimationUtility.SetObjectReferenceCurve(animClip, curveBinding, keyFrames);

I thought about deleting this post, but there’s so few documentation on how to do this that I decided to keep it. Hope this helps someone.

9 Likes

Great Job! Many many thanks to you! It really helps me a lot!
Thanks!

thanks for the infos , don’t delete your post ^^, I am sure it will be very helpful for those on the same situation

I write script according your method. but the animation not work.

I put this script in start method in a MonoBehaviour. and the game object has a SpriteRenderer component.

and I create some sprites from atlas and put them into a " List frames" . I also added a Animation

component in the game object.

EditorCurveBinding curveBinding = new EditorCurveBinding();
curveBinding.type = typeof(SpriteRenderer);
curveBinding.path = “”;
curveBinding.propertyName = “m_Sprite”;
ObjectReferenceKeyframe[ ] keyFrames = new ObjectReferenceKeyframe[frames.Count];
for (int i = 0; i < frames.Count; i++)
{
keyFrames = new ObjectReferenceKeyframe();
_ keyFrames*.time = i;_
keyFrames_.value = frames;
}
AnimationClip ac = new AnimationClip ();
ac.name = “go”;
AnimationUtility.SetObjectReferenceCurve(ac, curveBinding, keyFrames);
animation.AddClip (ac, “go”);
animation.clip = ac;
animation.Play (ac.name);*

but it does not work? and no errors occured. no one sprite displayed. How should I modify this script? very thanks._

@ttzl sorry for taking this long to answer your question.

The method I described only works in the Editor mode, not during runtine. EditorCurveBinding is inside the UnityEditor namespace. I assume you’re trying to use during runtime because you said that you put this code inside a Start method of a MonoBehaviour.

If you need to create them in runtime, I don’t really know how that could be done, but if you only wish to create the animation procedurally and this can be made prior to the execution of the game, i.e. in the editor, the method should work for all I know.

Try putting your code in a Custom Editor Script.

Feel free to ask me any other question.

1 Like

Caspilar, thank you very much. I really try to it use during runtime. Then I will try it in edit mode. thank you!

Hello Unity Community, im currently having a similar problem and tried to use the provided information.
Just one thing, are the “timeForKey” and “spriteForKey” variables or functions?
I get a dosnt exist in the current context error.

@Guadi

An ObjectKeyframeReference is made of a float representing the time and a reference object.

They are both functions and the code I wrote was more of a pseudocode, only to indicate that the functionality exists. You should implement them to suit your needs. One possible implementation is the following

int timeForKey(int i)
{
      // Here you put the code that will return the time 
      // for the ith keyframe

      // Example: the time of each frame will be its index
      return i;
}

Sprite spriteForKey(int i)
{
    // Here you put the code that will return the sprite that you want
    // for the ith keyframe

    // Example: assuming you have a sprite array "_sprites" populated with all the sprites for each keyframe
    // in order 
    return _sprites[i];
}

But this is really just a simple example and most likely won’t be what you need. Should get you started though

Caspilar, thanks for examples. I’s huge headake for me to make curve works.
firstly i’ve made everything through clip.SetCurve(…) and i’ve got a lot of issues, like curve are correct, but with wrong properties in editor (smooth break and so on).
just tried to make it through CurveBinding, and got more stable result.

also i see following static methods

    public static EditorCurveBinding FloatCurve(string inPath, System.Type inType, string inPropertyName)
    {
      return new EditorCurveBinding()
      {
        path = inPath,
        type = inType,
        propertyName = inPropertyName,
        m_isPPtrCurve = 0
      };
    }

    public static EditorCurveBinding PPtrCurve(string inPath, System.Type inType, string inPropertyName)
    {
      return new EditorCurveBinding()
      {
        path = inPath,
        type = inType,
        propertyName = inPropertyName,
        m_isPPtrCurve = 1
      };
    }
  }

probably it’s more easiest to work with them.
Also i’m not sure about isPPtrCurve parameter, but i think that if isPPtrCurve=1 it’s for sprite switching, otherwise for curving.

OMG, stumbled upon this, and you literally saved me today! THANK YOU!

someone can help to understand this please

i have do

Hi there kilik128.

There’s no need for you to use the EditorCurveBinding for Rotation curves, the process is much simpler. You can set up the rotation curve the regular way, using the AnimationClip.SetCurve. Please check the following link: Unity - Scripting API: AnimationClip.SetCurve

The link explains how to set up curves for Transform values such as position and rotation. Be aware that the rotation may not be set using euler angles, they must be set as quaternions, and therefore you must define one curve for each of the 4 members of the quaternion x,y,z,w.

Same Trouble For animated Blendshape
someone get any idea

Thanks Caspilar! You saved me hours :smiley:

*_</em></em> <em><em><em>*for (int i = 0; i < frames.Count; i++) { keyFrames[i] = new ObjectReferenceKeyframe(); keyFrames[i].time = 1.0f; keyFrames[i].value = frames; }*</em></em></em> <em><em>_*

@Caspilar ,

I have a Animator Controller Already working for my character, but i’m trying to make an editor Script to multiply the values of the animations curve … ex: i want him to bounce more , so i ill get all curves with localPosition.y and Multiple by some value …

Do you know how to get and edit animations from Animator Controller ?

if this is not possible , i will get all animations thats inside the character with AnimationUtility.getAnimationClips()… And Create new AnimationClips with new values … but how to replace this new animations clips to the animatorController ? and keep the controller Working …

Thanks

Exhumating the topic since I’m doing the exact same as mentioned in this thread, except that whenever I play the animation in the animator, the same sprite is rendered for all key frames. (in Editor and in-game)
In order to make Unity recognized that the key frames have different sprites, is to manually drag one frame 1mm any direction, then back to its position. Then all a sudden the animation works fine :face_with_spiral_eyes: (The animation can be detached and reattached to any Animator it will work fine from this point).
cf. AnimationClip code-created - key Frames identical

I hope the initial post creator have some ideas for me.

Thanks in advance.

You’re replying to a post made 7 years ago to a user who had this as their last post (it took me a few moments to see that). This was when 2D wasn’t even much of a thing then and had no dedicated animation system.

Please, if you have something specific to add then please make a new post, it’s free. Don’t necro threads.

There’s also a dedicated Animation sub-forum here if you have general animation things to discuss.

Thanks.

1 Like

I have indeed created a new thread for this.

It is not really a necro, since 7 years there were no improvements in this space, and the mentioned code is the only way to achieve animation generically.

Please could you help me moving my thread above to the right sub-forum Animation ?