【问题标题】:Can I use an abstract base class as a Unity Editor element?我可以使用抽象基类作为 Unity Editor 元素吗?
【发布时间】:2018-12-06 19:48:02
【问题描述】:

我正在尝试为 Unity GameObject 创建一个组件,我们称之为 MediaController。我希望它能够管理不同媒体(音频/视频)的时间(播放/暂停/等)。我创建了一个具有基本属性/字段/方法的抽象类PlayableMedia,并创建了两个类,PlayableVideoPlayableAudio,它们根据我们的需要继承和实现。

目的是有一个单一的PlayableMedia 列表,它可能与音频/视频无关,允许在特定应用时间进行简单(即)media.Play() 调用,无论类型如何......但我的字段public List<PlayableMedia> MediaList; 是没有出现在编辑器中,也没有错误。

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

根据我的经验,我怀疑“不”,但我发现链接说“是”或“是的,有点”似乎指向 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
}

谁能帮帮我?要么确认这是不可能的,或者如果是的话,请帮助我实施?

另外,如果可以使用自定义编辑器/检查器/抽屉来完成,有人可以帮我在List&lt;RegisteredMedia&gt; 中获取单个项目以显示为Start Time ____ Playable Media [=====](其中PlayableMedia 将是GameObject 与正确的组件连接)?

【问题讨论】:

    标签: c# unity3d unity-editor


    【解决方案1】:

    小心使用“财产”一词。 In C# it means something very specific

    是否可以使用 PlayableMedia 类作为属性的类型?

    我认为你在这里问错了问题。与其提出新的实施方案,不如考虑一下为什么您当前的实施方案可能不起作用?

    首先,我给你举个例子:

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

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

    因此,要回答我认为您要问的问题(假设我们将“属性”替换为“字段”),确实可以使用抽象类类型并将它们显示在检查器中。我怀疑您需要将您的类分成单独的文件。

    【讨论】:

    • 1 你说的完全正确,我混淆了条款,我很抱歉;我混淆了我的实现,我在其他地方做道具哈哈。 2 Whelp,多亏了你,我才找到了我的问题,我现在真的很讨厌自己。数小时试图解决这个问题,查看自定义编辑器/检查器/抽屉以(正如您指出的那样)解决我没有真正遇到的问题......而我的抽象 PlayableMedia 类只需要 : MonoBehaviour3 是的,它们都在单独的文件中,为了简洁起见,我只是在此处合并代码:)。
    • 不要为这些错误感到沮丧。更重要的是要首先了解您为什么会犯错误,然后是为什么您无法识别它。从现在开始,您应该能够意识到,如果事物没有显示为组件,可能是因为它们不是单一行为。我已经犯了几十次这个错误,但我现在可以很快诊断出问题。你犯的每一个错误然后合理化都会让你成为一个更好的程序员。
    • 哦,我知道了,但感谢您的支持!我是一个非常有经验的程序员,只是缺乏 Unity 编程经验。我很沮丧,因为我已经制作了好几次自定义组件并且之前总是记得MonoBehaviour,所以我现在只是在踢自己哈哈。请放心,这将是我下次不工作时的第一次“检查”哈哈。至于为什么这次我忘记了,我同时忙于几个项目,我可能只是滑倒了/马虎了。但再次感谢您的帮助,非常感谢! :D
    • 如果类没有从MonoBehaviourScriptableObject 继承呢?我有一个抽象类Module,每个继承的类都有不同的参数(包括一些需要自己的模块),我希望能够显示一个下拉列表(由枚举确定),显示所有“类型” ' 的模块并为它们显示适当的属性抽屉。
    • 我认为从可编写脚本的对象或 Monobehavior 继承是不可能的。你可以让你的抽象类继承自其中一个。或者,您可以编写一个包含所需引用的类以及“模块”,并且该类可以在更改时将其引用传递给模块。虽然很笨拙。
    【解决方案2】:

    从 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
    }
    

    【讨论】:

    • 你能举个例子吗?
    • @Mr_Thorynque 示例添加
    猜你喜欢
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多