Using Unity EditorWindow to Create Animations from Spritesheet?

Viewed 476

Currently I am working on a 2D game in Unity. I am working on a EditorWindow to slice an imported spritesheet and create animations from these sprites.

Currently, I have the code to slice the spreadsheet functioning, detailed below for those interested in referencing:

public void Slice()
{
    var textures = Selection.GetFiltered<Texture2D>(SelectionMode.Assets);

    foreach (var texture in textures)
    {
        ProcessTexture(texture, pixelPerUnit, spriteSize, pivot, alignment);
    }
}

static void ProcessTexture(Texture2D texture, int pixelPerUnit, 
    Vector2Int spriteSize, Vector2 pivot, Alignment alignment)
{
    string path = AssetDatabase.GetAssetPath(texture);
    {
        TextureImporter textureImporter = 
            TextureImporter.GetAtPath(path) as TextureImporter;

        //Set characteristics for spritesheet
        textureImporter.textureType = TextureImporterType.Sprite;
        textureImporter.spriteImportMode = SpriteImportMode.Multiple;
        textureImporter.spritePixelsPerUnit = pixelPerUnit;
        textureImporter.filterMode = FilterMode.Point;
        textureImporter.textureCompression = TextureImporterCompression.Uncompressed;

        int colCount = texture.width / spriteSize.x;
        int rowCount = texture.height / spriteSize.y;

        //Create Spritesheet Metadata based on characteristics
        List<SpriteMetaData> metas = new List<SpriteMetaData>();
        for (int c = 0; c < colCount; c++)
        {
            for (int r = 0; r < rowCount; r++)
            {
                SpriteMetaData meta = new SpriteMetaData();
                meta.rect = new Rect(c * spriteSize.x, 
                    r * spriteSize.y, 
                    spriteSize.x, spriteSize.y);

                meta.name = (rowCount - r - 1) + "-" + c;
                meta.alignment = (int)alignment;
                meta.pivot = pivot;
                metas.Add(meta);
            }
        }
        //Apply the metadata to the spritesheet
        textureImporter.spritesheet = metas.ToArray();
        AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
    }
}

The portion that is currently giving me grief is converting this newly sliced spreadsheet into animations through script.

Currently I can create an empty animation clip in the directory of the spritesheet using the code snippet below:

string path = AssetDatabase.GetAssetPath(texture);
string newPath = Path.GetDirectoryName(path);

AnimationClip clip = new AnimationClip();
AssetDatabase.CreateAsset(clip, newPath + "\\" + spriteName ".anim");

I am having difficulty finding out how to add sprites to this newly created animation. I have looked into AnimationCurves and AnimationEvents but I cannot seem to find the step to link a sprite to the animation through the editor.

If anyone has experience or knowledge regarding the creation of unity animationclips through script, any insight would be greatly appreciated. If any more information is needed on my end, please let me know. This is my first time using this service. Thank you all for your help!

1 Answers

I am posting my resolution here in the event that anyone else would like to reference it! I ultimately ended up referencing the articles Create Animation Clip from Sprite[] (Programmatically) and How to get child sprites from a 'Multiple Sprite' Texture.

The resultant code for creating animations from a selected spritesheet through editor window is pasted below:

public void Animate()
{
    var textures = Selection.GetFiltered<Texture2D>(SelectionMode.Assets);

    foreach (var texture in textures)
    {
        GenerateAnimations(texture, spriteSize, spriteName);
    }
}

static void GenerateAnimations(Texture2D texture, Vector2Int spriteSize, string spriteNameGlobal)
{
    //Create an Array of all sprites in the selected texture
    string path = AssetDatabase.GetAssetPath(texture);
    Sprite[] allSprites = AssetDatabase.LoadAllAssetsAtPath(path).OfType<Sprite>().ToArray();
    string newPath = Path.GetDirectoryName(path);

    //Determine the number of rows & columns based on preset "spriteSize" Vector2
    int colCount = texture.width / spriteSize.x;
    int rowCount = texture.height / spriteSize.y;

    //Loop through each row of the spritesheet to make an animation
    for (int i = 0; i < rowCount; i++)
    {
        //Create a sprite subsection for a row of sprites
        Sprite[] batchSprites = new Sprite[colCount];
        for (int j = 0; j < batchSprites.Length; j++)
        {
            batchSprites[j] = allSprites[i * colCount + j];
        }

        //Create the base AnimationClip
        AnimationClip clip = new AnimationClip();
        clip.frameRate = 12f;

        //Create the CurveBinding
        EditorCurveBinding spriteBinding = new EditorCurveBinding();
        spriteBinding.type = typeof(SpriteRenderer);
        spriteBinding.path = "";
        spriteBinding.propertyName = "m_Sprite";

        //Create the KeyFrames
        ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[colCount];
        for (int j = 0; j < spriteKeyFrames.Length; j++)
        {
            spriteKeyFrames[j] = new ObjectReferenceKeyframe();
            spriteKeyFrames[j].time = j/clip.frameRate;
            spriteKeyFrames[j].value = batchSprites[j];
        }
        AnimationUtility.SetObjectReferenceCurve(clip, spriteBinding, spriteKeyFrames);

        //Set Loop Time to True
        AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clip);
        settings.loopTime = true;
        AnimationUtility.SetAnimationClipSettings(clip, settings);

        //Save the clip
        AssetDatabase.CreateAsset(clip, newPath + "\\" + spriteNameGlobal + i + ".anim");
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
}

In working with this code, there were some interesting issues that would pop up if not careful. A major one was not setting spriteBinding.propertyname to "m_Sprite". Be careful with this if you decide to modify this code.

I hope this proves useful! If anything was not clear, or there are further suggestions for clarity, please respond and I can try to to improve this response.

Related