0
\$\begingroup\$

I'm trying to fill my animation component automatically with clips which are dropped into a sister component. For nice UX I want the animation component just to sit there - artists shouldn't mess with it (HideFlags.NotEditable).

But I also don't want to fill the animation component during runtime if I can avoid it.

But there I run into a problem. Here's a little test code. Checking the toggle will add a test clip to the animation component's clip list, unchecking the toggle will remove it again:

[RequireComponent(typeof(Animation))]
public class OnValidateTest : MonoBehaviour
{
    public AnimationClip TestClip;

    public bool Toggle;

    private void OnValidate()
    {
        Debug.Log("OnValidate");

        Animation animationComponent = GetComponent<Animation>();
        // Reset clip list in Animation component, also eliminating empty clips (only clean way I found)
        UnityEditor.AnimationUtility.SetAnimationClips(animationComponent, new AnimationClip[0]);

        if (Toggle)
        {
            animationComponent.AddClip(TestClip, "test");
        }
    }
}

The problem now:

  • It works in the scene view
  • It works in prefab mode
  • But when trying to edit the asset by clicking on the prefab asset in the project tab I'll run into trouble

Problem 1: OnValidate will be called infinitely. (constant asset updating)
Problem 2: Clip assignment will fail and the inspector will display "type mismatch" in the array - (like I tried to assign an instance instead of an asset??)

Here's also a video showing the behavior.

Is what I want achievable ?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

I wouldn't recommend OnValidate for adding editor controls. Instead, you can use a CustomEditor to add a button to your component's Inspector display (I think you could even make one for the Animation component!) or make an EditorWindow with buttons for manipulating objects.

Or, even simpler, use Button from NaughtyAttributes:

using NaughtyAttributes;
using UnityEngine;

public class AnimTest : MonoBehaviour
{
#if UNITY_EDITOR
    public AnimationClip TestClip;

    [Button]
    void ClearClips()
    {
        Animation animationComponent = GetComponent<Animation>();
        // We need to call Undo to ensure our changes are saved.
        UnityEditor.Undo.RecordObject(animationComponent, "ClearClips");
        // Reset clip list in Animation component, also eliminating empty clips (only clean way I found)
        UnityEditor.AnimationUtility.SetAnimationClips(animationComponent, new AnimationClip[0]);
    }
    [Button]
    void AddClip()
    {
        ClearClips();
        Animation animationComponent = GetComponent<Animation>();
        // Since we're using Animation to play instead of Animator, we must
        // mark as legacy. Otherwise we get a warning like: "The AnimationClip
        // 'animation' used by the Animation component 'GameObject' must be
        // marked as Legacy."
        UnityEditor.Undo.RecordObject(TestClip, "mark as legacy");
        TestClip.legacy = true;
        UnityEditor.EditorUtility.SetDirty(TestClip); // for some reason RecordObject isn't always enough.
        animationComponent.AddClip(TestClip, "test");
    }

#endif // UNITY_EDITOR
}

Problem 2: Clip assignment will fail and the inspector will display "type mismatch" in the array - (like I tried to assign an instance instead of an asset??)

You're probably getting a warning like: "The AnimationClip 'animation' used by the Animation component 'GameObject' must be marked as Legacy."

You need to set the legacy flag to use AnimClips with Animation. (But maybe you should look into using Animator.)

\$\endgroup\$
2
  • \$\begingroup\$ Unfortunately doing it manually still won't solve the "type mismatch" problem: youtu.be/urSFPPeeKK4 With that one solved I could probably also solve problem 1 by checking if an update is actually required. \$\endgroup\$
    – Samhayne
    Commented Jul 15, 2021 at 23:21
  • \$\begingroup\$ It’s not the legacy flag. The flag is checked. As I described, the problem occurs only when editing the prefab directly by clicking on the asset in the project view (see video from original post). In the scene view and in prefab mode everything works fine. \$\endgroup\$
    – Samhayne
    Commented Jul 16, 2021 at 7:52
1
\$\begingroup\$

Alright. This works.

[RequireComponent(typeof(Animation))]
public class OnValidateTest : MonoBehaviour
{
    public AnimationClip TestClip;

    public bool Toggle;

    private void OnValidate()
    {
        Debug.Log("OnValidate");

        Animation animationComponent = GetComponent<Animation>();

        if (Toggle)
        {
            //animationComponent.AddClip(TestClip, "test");
            if (!animationComponent[TestClip.name])
            {
                UnityEditor.AnimationUtility.SetAnimationClips(animationComponent, new AnimationClip[1]{TestClip});
            }
        }
        else
        {
            if (animationComponent.GetClipCount() != 0)
            {
                // Reset clip list in Animation component, also eliminating empty clips (only clean way I found)
                UnityEditor.AnimationUtility.SetAnimationClips(animationComponent, new AnimationClip[0]);
            }
        }
    }
}
  1. Checks if a change is actually required will avoid the infinite asset update loop.
  2. Using UnityEditor.AnimationUtility.SetAnimationClips() instead of animation.AddClip() will make the "type mismatch" problem go away, when trying to directly edit the asset from the project view.
\$\endgroup\$
1
  • \$\begingroup\$ Addendum: I later found out that the animationComponent has to be destroyed and recreated with each OnValidate(). Couldn't uncover the reason why - but otherwise the resulting entries in the clip list will be a weird mix of the former clip list and the new one. As Unity won't allow destruction of components directly in OnValidate() you need to decouple the destruction or better the whole update method from OnValidate(). (I'd recommend using UnityEditor.EditorApplication.delayCall += at some sensible point). But with that change it's solid now. \$\endgroup\$
    – Samhayne
    Commented Aug 2, 2021 at 12:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .