Unity/Tip

Animation Preview Auto Play

코샵 2023. 9. 11. 13:31
반응형
더보기

필자는 Unity로 게임을 개발하고 있다. 현재 개발에 사용중인 오브젝트의 Animation은 300개가 넘어간다.

이전에는 PreView의 Play 버튼을 눌러 일일이 하나씩 재생시켜 확인을 하였는데 이제는 이또한 귀찮아졌다...

 

GPT 4 사용

우리의 멍청한 친구 GPT에게 "I want the preview to play automatically when an animation file is selected." 라고 질문을 했다.

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;

[InitializeOnLoad]
public class AutoPlayAnimationPreview
{
    static AutoPlayAnimationPreview()
    {
        Selection.selectionChanged += OnSelectionChanged;
    }

    static void OnSelectionChanged()
    {
        if (Selection.activeObject is AnimationClip)
        {
            var animationClip = Selection.activeObject as AnimationClip;
            if (AnimationUtility.GetAnimationClipSettings(animationClip).loopTime)
            {
                // If the animation is set to loop, play the animation automatically in the preview
                EditorApplication.ExecuteMenuItem("Window/Animation/Animation");
            }
        }
    }
}
#endif

코드를 하나 작성해줬는데 질문의 의도와는 다르게 작동하지 않는다.

 

구글링

구글링을 해보니 이와 같은 코드가 있어 사용해보았는데 정상적으로 작동한다

using System;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace EditorScripts
{

    [InitializeOnLoad]
    public static class AutoPlayAnimationPreview
    {

        private const BindingFlags PRIVATE_FIELD_BINDING_FLAGS = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
        private const BindingFlags PUBLIC_FIELD_BINDING_FLAGS = BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField;
        private const BindingFlags PUBLIC_PROPERTY_BINDING_FLAGS = BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty;

        private static Type animationClipEditorType;
        private static Type avatarPreviewType;
        private static Type timeControlType;

        private static Object selectedObject;
        private static bool shouldFindTimeControl;

        static AutoPlayAnimationPreview()
        {
            animationClipEditorType = Type.GetType("UnityEditor.AnimationClipEditor,UnityEditor");
            avatarPreviewType = Type.GetType("UnityEditor.AvatarPreview,UnityEditor");
            timeControlType = Type.GetType("UnityEditor.TimeControl,UnityEditor");
        }

        private static void Update()
        {
            if (Selection.activeObject != selectedObject)
            {
                selectedObject = Selection.activeObject;

                if (selectedObject is AnimationClip)
                {
                    shouldFindTimeControl = true;
                }
                else if (selectedObject is GameObject)
                {
                    var assetPath = AssetDatabase.GetAssetPath(selectedObject);

                    if (!string.IsNullOrWhiteSpace(assetPath))
                    {
                        foreach (var child in AssetDatabase.LoadAllAssetsAtPath(assetPath))
                        {
                            if (child is AnimationClip)
                            {
                                shouldFindTimeControl = true;
                                break;
                            }
                        }
                    }
                }

                return;
            }

            if (shouldFindTimeControl)
            {
                var animationClipEditor = Resources.FindObjectsOfTypeAll(animationClipEditorType).FirstOrDefault();
                if (animationClipEditor == null) return;

                var avatarPreview = animationClipEditorType.GetField("m_AvatarPreview", PRIVATE_FIELD_BINDING_FLAGS)?.GetValue(animationClipEditor);
                if (avatarPreview == null) return;

                var timeControl = avatarPreviewType.GetField("timeControl", PUBLIC_FIELD_BINDING_FLAGS)?.GetValue(avatarPreview);
                if (timeControl == null) return;

                shouldFindTimeControl = false;

                var playingProperty = timeControlType.GetProperty("playing", PUBLIC_PROPERTY_BINDING_FLAGS);
                if (playingProperty == null) return;

                playingProperty.SetValue(timeControl, true);
            }
        }

        [InitializeOnLoadMethod, UsedImplicitly]
        private static void SubscribeToUpdate()
        {
            EditorApplication.update += Update;
        }

    }
}

코드출처