微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在另一个组件上定义自定义属性时,如何将组件添加到游戏对象?

如何解决在另一个组件上定义自定义属性时,如何将组件添加到游戏对象?

如果我必须总结我的问题,我会说我想创建一个类似于 Unity 中的 requiredComponent 属性属性

我有一个名为 ContainsDataToBeSaved

属性
[AttributeUsage(AttributeTargets.Class)]
public class ContainsDataToBeSaved : PropertyAttribute 
{
}

我还有另一个组件。

[ContainsDataToBeSaved]
public class Tester : MonoBehavIoUr
{

}

这个 Tester 组件附加到一个游戏对象。我想在 SaveLoadComponent 属性附加到游戏对象时自动附加另一个名为 ContainsDatetoBeSaved 的组件。这不能在运行时发生,它必须在编辑器中发生。

我可以通过在测试脚本的顶部添加 [requiredComponent(typeof(SaveLoadComponent))] 轻松实现这一点,但这不是我想要做的。

所以我会回答一些问题。为什么不使用 RequireComponent 属性?我正在尝试制作一个易于使用的保存系统。我的目标是,当您附加属性 ContainsDataToBeSaved 并使用我创建的另一个自定义属性标记任何字段时,它会自动保存该字段并在运行时加载它。这个保存系统确实依赖于另一个组件,即 SaveLoadComponent。我发现每当有人使用保存系统时,他们都会忘记添加组件。如果该属性可以添加组件,则会更容易。 我的目标是使这个系统易于使用,并且不允许出现“人为错误”。我探索了其他途径,例如创建一个基类来处理 SaveLoadComponent 所做的一切。但我敢肯定,有些开发人员可能会忘记从该类继承。如果开发人员忘记将组件附加到游戏对象,他们也可以忘记添加 RequireComponent 属性。目标是可以附加属性,其余的将被处理。

解决方法

正如评论中所说,首先 PropertyAttribute 顾名思义不应该用在 class 上,而只能用在其中的字段和属性上。

您应该只从 Attribute 继承,然后通常将后缀 Attribute 添加到名称中,如

[AttributeUsage(AttributeTargets.Class)]
public class ContainsDataToBeSavedAttribute : Attribute { }

然后进一步提到,对于属性,很清楚何时检查和使用属性(通常用于检查器中的装饰器抽屉或用于 De/Serialization),但不清楚您要检查的确切时刻并应用类的属性。

我认为最接近您想要实现的目标是以下内容,但是,它需要覆盖从 MonoBehaviour 继承的任何内容的检查器

[CustomEditor(typeof(MonoBehaviour))]
public class ContainsDataToBeSavedEditor : Editor
{
    MonoBehaviour _monoBehaviour;
    Type _type;
    Type _requireType = typeof(ContainsDataToBeSaved);

    // Called when this instance Inspector is loaded
    private void OnEnable()
    {
        _monoBehaviour = (MonoBehaviour) target;
        _type = target.GetType();

        CheckAndApplyAttribute();
    }

    // To check continously
    // NOTE: as this is quite expensive I would not do this
    //public override void OnInspectorGUI ()
    //{
    //    DrawDefaultInspector();
    //
    //    CheckAndApplyAttribute();
    //}

    private void CheckAndApplyAttribute()
    {
        // Try to get the attribute on given target  
        if (Attribute.IsDefined(_type,_requireType))
        {
            // So the attribute is present on the given target class

            // Check if your component is attached
            if(!(_monoBehaviour.TryGetComponent<SaveLoadComponent>(out _))
            {
                // Otherwise add it vis the Undo class enabling marking as dirty
                // and thereby saving and correct handling of Undo/Redo
                Undo.AddComponent<SaveLoadComponent>(_monoBehaviour.gameObject);
            }
        }
    }
}

因为这非常昂贵,所以你应该避免这样做,例如在 OnInspectorGUI 或类似的东西中,每个事件在检查器中被多次调用。

请注意,这仍然不能完全复制 RequireComponent 的行为,因为后者还确保您无法删除相应的依赖项。

所以问题仍然存在:为什么不简单地使用 RequireComponent


注意:在智能手机上打字,但我希望思路清晰

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。