首页 > 解决方案 > 使用 Unity EditorWindow 从 Spritesheet 创建动画?

问题描述

目前我正在 Unity 中开发一款 2D 游戏。我正在使用 EditorWindow 对导入的 spritesheet 进行切片并从这些 sprite 中创建动画。

目前,我有代码来分割电子表格的功能,下面为那些有兴趣参考的人详细介绍:

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);
    }
}

目前让我悲伤的部分是通过脚本将这个新切片的电子表格转换为动画。

目前我可以使用下面的代码片段在 spritesheet 的目录中创建一个空的动画剪辑:

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

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

我很难找出如何将精灵添加到这个新创建的动画中。我查看了AnimationCurvesAnimationEvents,但似乎找不到通过编辑器将精灵链接到动画的步骤。

如果有人对通过脚本创建统一动画剪辑有经验或知识,任何见解将不胜感激。如果我需要更多信息,请告诉我。这是我第一次使用这项服务。谢谢大家的帮助!

标签: c#unity3dunity3d-2dtoolsunity3d-editor

解决方案


如果其他人想参考它,我会在这里发布我的决议!我最终参考了文章Create Animation Clip from Sprite[] (Programmatically)How to get child sprites from a 'Multiple Sprite' Texture

通过编辑器窗口从选定的精灵表创建动画的结果代码粘贴在下面:

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();
    }
}

在使用此代码时,如果不小心,会出现一些有趣的问题。一个主要的问题是没有将 spriteBinding.propertyname 设置为“m_Sprite”。如果您决定修改此代码,请注意这一点。

我希望这被证明是有用的!如果有任何不清楚的地方,或者有进一步的明确建议,请回复,我可以尝试改进此回复。


推荐阅读