Unity 动画创建序列帧 代码生成AnimationClip

用Odin创建一个窗口,拖入Sprite生成AnimationClip

几个坑点:

  1. AnimationClip有个SetCurve方法可以设置曲线,AnimationCurve参数是float类型,在这里插入图片描述
    动画片段录制的是Sprite属性,没有曲线,需要创建binding;

  2. 创建EditorCurveBinding类型的binding可以设置value是Object类型的值:

    • type:动画对象身上的组件;
    • propertyName:组件上录制的参数,例如图中的Image.Sprite;获取的是私有成员"m_Sprite";
    • 获取公有成员"sprite"会Missing; 在这里插入图片描述
  3. 对动画片段编辑需用到AnimationUtility类,用SetObjectReferenceCurve设置动画曲线或ObjectReferenceKeyframe数组;

  4. 动画片段设置用AnimationClipSettings类,AnimationUtility.GetAnimationClipSettings获取,AnimationUtility.SetObjectReferenceCurve设置;

完整代码:

#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using DG.DemiEditor;
using UnityEditor;
using UnityEngine;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector;
using Sirenix.Utilities.Editor;
using Sirenix.Utilities;
using UnityEngine.UI;

namespace Editor.Tools
{
    public class TextureTool : OdinEditorWindow
    {
        [ReadOnly] [LabelText("角色")] public string avatarName = "";
        [LabelText("每几帧一个图")] public int frame = 5;
        [LabelText("动画名称")] public string animName = "New anim";
        
        //todo 帧率设置
        // private float _frameRate = Common.FrameRate;
        private float _frameRate = 30;
        [MenuItem("Tools/Sprite2Anim")]
        private static void OpenWindow()
        {
            var window = GetWindow<TextureTool>();
            window.position = GUIHelper.GetEditorWindowRect().AlignCenter(600, 600);
            window.titleContent = new GUIContent("Create Sprite Anim");
        }
        [InlineEditor(InlineEditorModes.LargePreview)]
        [ListDrawerSettings(OnTitleBarGUI = "DrawRefreshButton")]
        [OnValueChanged("SetDefaultName")]
        public List<Sprite> sprites;

        public void SetDefaultName(List<Sprite> sprites)
        {
            if (sprites.Count == 0)
            {
                avatarName = "";
                animName = "";
                return;
            }
            string[] tmpStrs = sprites[0].name.Split(new[] {"_"}, StringSplitOptions.RemoveEmptyEntries);
            if (tmpStrs.Length <= 1) animName = tmpStrs[0];
            else
            {
                avatarName = tmpStrs[0];
                animName = tmpStrs[0] + "_" + tmpStrs[1];
            }
        }
        public void DrawRefreshButton()
        {
            if(SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh))
                sprites.Clear();
        }
        
        [HorizontalGroup("Button")][Button(ButtonSizes.Gigantic, Name = "创建动画"), GUIColor(0, 1, 0)]
        public void CreateAnimationClip()
        {
            if (sprites.Count == 0)
            {
                Debug.LogError("未选中贴图");
                return;
            }

            string assetLocation = AssetUtilities.GetAssetLocation(sprites[0]);

            AnimationClip clip = new AnimationClip();
            EditorCurveBinding curveBinding = new EditorCurveBinding();
            curveBinding.type = typeof(Image);
            curveBinding.path = "";
            curveBinding.propertyName = "m_Sprite";
            ObjectReferenceKeyframe[] keyframes = new ObjectReferenceKeyframe[sprites.Count];
            for (int i = 0; i < sprites.Count; i++)
            {
                keyframes[i] = new ObjectReferenceKeyframe();
                keyframes[i].time = i * frame / _frameRate;
                keyframes[i].value = sprites[i];
            }
            
            clip.frameRate = _frameRate;
            AnimationClipSettings clipSettings = AnimationUtility.GetAnimationClipSettings(clip);
            clipSettings.loopTime = true;
            AnimationUtility.SetAnimationClipSettings(clip, clipSettings);

            AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyframes);
            
            if (!avatarName.IsNullOrEmpty())
            {
                assetLocation += "/" + avatarName + "_anim";
                Directory.CreateDirectory(assetLocation);
            }
            
            AssetDatabase.CreateAsset(clip, assetLocation + "/" + animName + ".anim");
            AssetDatabase.SaveAssets();
        }
    }
}
#endif
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是在 Unity创建一个带有序列动画的物体的示例代码: ```csharp // 创建一个新的 GameObject GameObject newObject = new GameObject("MyObject"); // 添加 SpriteRenderer 组件 SpriteRenderer spriteRenderer = newObject.AddComponent<SpriteRenderer>(); // 添加 Animator 组件 Animator animator = newObject.AddComponent<Animator>(); // 加载 Sprite 序列帧 Sprite[] sprites = new Sprite[10]; for(int i = 0; i < sprites.Length; i++) { string spritePath = "Sprites/Winter/Winter" + (i + 1); sprites[i] = Resources.Load<Sprite>(spritePath); } // 创建 AnimationClip AnimationClip clip = new AnimationClip(); clip.name = "MyClip"; clip.frameRate = 10; // 设置帧率 // 创建动画曲线 ObjectReferenceKeyframe[] frames = new ObjectReferenceKeyframe[sprites.Length]; for(int i = 0; i < sprites.Length; i++) { frames[i] = new ObjectReferenceKeyframe(); frames[i].time = i / clip.frameRate; frames[i].value = sprites[i]; } // 添加帧动画曲线 EditorCurveBinding spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = ""; spriteBinding.propertyName = "m_Sprite"; AnimationUtility.SetObjectReferenceCurve(clip, spriteBinding, frames); // 将 AnimationClip 添加到 AnimatorController RuntimeAnimatorController animatorController = new AnimatorController(); animatorController.AddMotion(clip); // 设置 Animator 的 runtimeAnimatorController animator.runtimeAnimatorController = animatorController; ``` 在这个代码中,我们创建了一个新的 GameObject,并向它添加了 SpriteRenderer 和 Animator 组件。然后,我们使用 `Resources.Load()` 函数加载了一个名为 "Sprites/Winter/Winter1" 的序列动画。接着,我们使用 AnimationClip 和帧动画曲线来创建动画,并将其添加到 AnimatorController 中。最后,我们将 AnimatorController 赋给了 GameObject 的 Animator 组件。 请注意,在使用 `Resources.Load()` 函数加载资源时,请确保您已将资源添加到项目的 `Resources` 文件夹中,并在资源路径中包含 `Resources` 文件夹的名称。例如,在示例代码中,我们将序列动画放在了 `Assets/Resources/Sprites/Winter` 文件夹中,因此我们的资源路径是 "Sprites/Winter/Winter1"、"Sprites/Winter/Winter2" 等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值