我可以使用抽象基础 class 作为 Unity 编辑器元素吗?

Can I use an abstract base class as a Unity Editor element?

我正在尝试为 Unity GameObject 创建一个组件,我们称它为 MediaController。我希望它能够管理不同媒体 (audio/video) 的时间 (play/pause/etc)。我用基本的 properties/fields/methods 创建了一个抽象 class PlayableMedia 并创建了 2 个 classes,PlayableVideoPlayableAudio,它们根据我们的继承和实现需要。

目的是拥有一个 PlayableMedia 的单一列表,它可以 audio/video 不可知,允许在特定应用程序时间轻松(即)media.Play() 调用,而不管类型如何。 .但是我的字段 public List<PlayableMedia> MediaList; 没有出现在编辑器中并且没有错误。

所以最终我的问题如标题所述:是否可以使用 PlayableMedia class 作为字段类型?

根据我的经验,我怀疑 "no",但我发现 "yes" 或 "yes, sort of" 的链接似乎指向 to custom editors/inspectors/drawers,但我在这些方面的经验为 0,无法实施(见下文)。

[System.Serializable]
public class RegisteredMedia
{
    public float StartTime;
    public PlayableMedia Media;
}

[CustomPropertyDrawer(typeof(RegisteredMedia))]
class RegisteredMediaDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);

        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Playable Media"));

        var indent = EditorGUI.indentLevel;
        EditorGUI.indentLevel = 0;

        Rect rectStartTime = new Rect(position.x, position.y, 30, position.height);
        Rect rectMedia = new Rect(position.x + 35, position.y, 50, position.height);

        EditorGUI.PropertyField(rectStartTime, property.FindPropertyRelative("StartTime"), GUIContent.none);
        EditorGUI.PropertyField(rectMedia, property.FindPropertyRelative("Media"), GUIContent.none);

        EditorGUI.indentLevel = indent;

        EditorGUI.EndProperty();
    }
}

public class MediaController : MonoBehaviour
{
    public List<RegisteredMedia> MediaList = new List<RegisteredMedia>();

    \[...] rest of implementation
}

谁能帮帮我?要么确认这是不可能的,要么帮助我实现它?

此外,如果可以使用自定义 editors/inspectors/drawers 来完成,有人可以帮我在 List<RegisteredMedia> 中获取单个项目以显示为 Start Time ____ Playable Media [=====](其中 PlayableMedia将是 GameObject 并附加了适当的组件)?

请小心使用 "property" 这个词。 In C# it means something very specific

is it possible to use the PlayableMedia class as the type of a property?

我认为你在这里问错了问题。与其想出一个新的实施方案,不如考虑一下为什么您当前的实施方案可能无法正常工作?

首先,我给大家举个例子:

public abstract class Car : MonoBehaviour { }

public class Jeep : Car { }

public class Ferrari : Car { }

public class CarHolder : MonoBehaviour
{
    public List<Car> Cars;
}

在此示例中,我可以使用 CarHolder 组件创建一个游戏对象,并且能够附加 Jeep 和 Ferrari 对象。请务必注意,我定义的每个 monoBehavior class 都位于其自己的文件中,并且文件名与 class 名称匹配。这就是 Unity 的工作原理。

所以要回答我想你问的问题(假设我们用 "field" 替换 "property"),确实可以使用抽象 class 类型并让它们显示出来在检查器中。我怀疑您需要将 classes 分成单独的文件。

从 2019.3 版本开始,通过 [SerializeReference] 属性 https://docs.unity3d.com/ScriptReference/SerializeReference.html

例如

using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public abstract class AbstractExample {
    public int foo;
}

// [Serializable] not needed here
public class ConcreteExample : AbstractExample {
}

public class Consumer : MonoBehaviour {
    [SerializeReference]
    public List<AbstractExample> examples = new() { new ConcreteExample() };

    // both the list and the concrete instance visible in the editor
    // and editable without any additional editor extensions

    // note that you can't effectively add new items to the list via editor
    // since that way you create a faulty abstract-ish instances instead
    // (no actual way for the editor to know what subtype do you want)

    // if you're OK with having the base class being not explicitly abstract
    // and can provide a sensible constructor for it, just drop the abstract
    // you'll still have full polymorphism support etc. with SerializeReference
}