【问题标题】:Prevent component from being added in the Editor防止在编辑器中添加组件
【发布时间】:2017-09-27 12:26:24
【问题描述】:

我正在寻找一种方法来禁用在 Unity 编辑器中附加我的 MonoBehaviour 组件的可能性。 所以我不希望我的组件出现在用户可见的任何地方。

原因是我从带有AddComponent<T>() 的脚本手动附加了这个组件。所以这更像是一个方便的问题,我只是不希望用户认为他必须手动添加我的组件才能让我的插件工作。 (如果他仍然这样做,那不会造成任何麻烦。再说一次,这只是方便)

精度

我正在编写一个库(dll 插件),所以我不能使用与我的组件不同的文件命名技巧,但这正是我正在寻找的效果。

我还尝试将我的类简单地设置为内部类,因为它确实是这样,程序集应该是唯一可以访问该组件的组件。但是,我担心即使使用内部类从 MonoBehaviour 继承也会使组件在编辑器中可用...

HideInInspector 属性似乎不适用于类。

我正在使用RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad) 从静态方法调用AddComponent,因此我不会依赖任何其他行为。

这是一个相当大的挑战,如果我们能找到答案,那就太奢侈了。 任何想法?非常感谢

【问题讨论】:

  • 它是运行时 AddComponent 还是 EditorScript?在运行时执行它可能是用户的性能问题 - 如果它不会导致任何问题,可能会让用户决定用户是否要手动添加它?
  • 是的,它在运行时,但只有一次,当第一个场景加载时。公平地说,我正在为服务编写一个库,所以如果他下载我的库,那已经是因为他希望我的行为在那里......
  • 我明白了!不幸的是,我没有你的问题的答案。你不能用[RequireComponent( typeof(YourScript) )]代替AddComponent吗?
  • 并非如此。我的组件是从 RuntimeInitializeOnLoadMethod 实例化的,所以我没有任何其他 MonoBehaviour 可以坚持

标签: c# unity3d mono


【解决方案1】:

一个非常简单的解决方案是让你的类成为某个所有者的内部类:

class NotAMonoBehaviour {
  class MyMonoBehaviour : MonoBehaviour {
    //etc.
  }
}

你可以很容易地添加类:

gameObject.AddComponent<NotAMonoBehaviour.MyMonoBehaviour>()

并且它不会出现在检查器的添加组件列表中。按照建议使用隐藏标志进行设置也会阻止它显示在检查器本身中,尽管不能完全依赖它,因为您可以在检查器中打开“调试”视图并仍然看到隐藏的组件。

【讨论】:

  • 我不敢相信这真的有效!伙计,这太棒了,非常感谢。
【解决方案2】:

所以我不希望我的组件出现在用户可见的任何地方。

下面的 sn-p 应该对编辑器(检查器和层次结构)隐藏您的脚本。

this.hideFlags = HideFlags.HideInHierarchy;
this.hideFlags = HideFlags.HideInInspector;

我正在寻找一种方法来禁用附加我的 Unity 编辑器中的 MonoBehaviour 组件

只要您的脚本继承自 MonoBehaviour,您就不能阻止人们将它附加到 GameObject。

不过,您可以这样做,以便当他们将其附加到游戏对象时,您会抛出一个错误,然后销毁该组件。将变量设置为 true。您可以从您的插件中使用一个函数从您的插件中将此变量设置为 true,这样您的脚本就不会被破坏。

示例代码:

public class MoveTowards : MonoBehaviour
{
    private bool callFromMyPlugin = false;

    //Call from your plugin to not destroy this script
    public void keepAlive()
    {
        callFromMyPlugin = true;
    }

    IEnumerator Start()
    {
        //Hides component from users
        hideFromUser();


        if (!callFromMyPlugin)
        {
            destroyThisComponent();
        }
        yield return null;

    }

    //Hides component in the Hierarchy and Inspector
    void hideFromUser()
    {
        this.hideFlags = HideFlags.HideInHierarchy;
        this.hideFlags = HideFlags.HideInInspector;

    }

    //Destroys this component
    void destroyThisComponent()
    {
        Debug.LogError("You are not allowed to add this component to a GameObject");
        DestroyImmediate(this);
        Debug.LogWarning("This component is now destroyed");
    }
}

当人们这样称呼它时:

GameObject testObj = new GameObject("Test");
MoveTowards script = testObj.AddComponent<MoveTowards>();

他们会得到下面的错误并且脚本会自行销毁:

现在,如果您从插件调用 create 它并调用 keepAlive 函数,脚本应该保留:

GameObject testObj = new GameObject("Test");
MoveTowards script = testObj.AddComponent<MoveTowards>();
script.keepAlive();

注意:

不是编辑器脚本,当您单击“播放”按钮时它可以工作,但您可以使用[ExecuteInEditMode] 使其在编辑器中执行。

【讨论】:

  • 这真是深思熟虑,非常感谢!它完成了我想要实现的目标:告诉用户他们不必自己添加它。如果它是最佳解决方案,我将在今天结束前将其标记为解决方案。再次感谢!
【解决方案3】:

就我而言,我使用 Monobehaviour.Reset() 方法来防止在编辑器中添加组件。

https://docs.unity3d.com/ScriptReference/MonoBehaviour.Reset.html

当用户点击检查器中的重置按钮时调用重置 上下文菜单或首次添加组件时。这 函数仅在编辑器模式下调用。重置最常用于 在检查器中提供良好的默认值。

    private void Reset()
    {
        if (this.GetType() == typeof(MyCustomClass))
        {
            DestroyImmediate( this );
        }
    }

【讨论】:

  • 一点也不击球!会试一试。谢谢!
  • 使用MonoBehaviour.Reset() 的好主意。我之前的解决方案涉及MonoBehaviour.Awake()ExecuteInEditMode
【解决方案4】:

由于您使用 AddComponent 添加它,因此您可能想要删除组件的 MonoBehaviour 部分。

假设您有在 Start 中创建子组件的主组件:

public class TopComp: MonoBehaviour
{
    void Start(){
        this.gameObject.AddComponent<SubComponent>();
    }
}

把它变成:

public class TopComp: MonoBehaviour
{
    private SubComponent sub = null;
    void Start(){
        this.sub = new SubComponent();
    }
}
public class SubComponent{ }

问题是您很可能想要使用所有 Unity 回调。将它们添加到 TopComponent 并显式调用 SubComponent。

public class TopComp: MonoBehaviour
{
    private SubComponent sub = null;
    void Start(){
        this.sub = new SubComponent();
    }
    void OnEnable(){ this.sub.OnEnable();} 
    void Update(){ this.Update();}
}
public class SubComponent{
    public void OnEnable(){}
    public void Update(){}
}

【讨论】:

【解决方案5】:

我有一个简单的解决方案,但我不能 100% 确定。它对组件的命名与 cs 文件名不同。

【讨论】:

  • Unity要求组件名与文件名一致。
猜你喜欢
  • 1970-01-01
  • 2017-06-04
  • 2020-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 2019-08-13
相关资源
最近更新 更多