Prevent component from being added in the Editor

2019-05-16 09:44发布

I am looking of a way to disable the possibility of attaching my MonoBehaviour component in the Unity Editor. So I don't want my component to appear anywhere visible by the user.

The reason is that I attach this component manually from a script with AddComponent<T>(). So this is more a convenience question, I just don't want the user to think he has to add my component manually in order for my plugin to work. (if he does anyway, that doesn't cause any trouble. Again, this is just convenience)

Precisions

I am writing a library (dll plugin), so I cannot use the trick of naming the file differently from my component, but that is exactly the effect I'm looking for.

I also tried to simply put my class as internal because that's really what it is, the assembly should be the only one to have access to this component. However, I'm afraid inheriting from MonoBehaviour even with an internal class makes the component available in the editor...

The HideInInspector attribute doesn't seem to work on a class.

I am calling AddComponent from a static method with RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad) so I won't have any other behaviour to rely on.

Quite a challenge, if we find an answer, that would be luxury. Any idea? Thank you very much

标签: c# unity3d mono
4条回答
We Are One
2楼-- · 2019-05-16 10:12

So I don't want my component to appear anywhere visible by the user.

The snippet below should hide your script from the Editor (Inspector and Hierarchy).

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

I am looking of a way to disable the possibility of attaching my MonoBehaviour component in the Unity Editor

As long as your script inherits from MonoBehaviour, you can't prevent people attaching it to a GameObject.

Although, you can make it so that when they attach it their GameObject, you throw an error and then destroy that component. Have a variable you set to true. You can can a function from your plugin to set this variable to true from your plugin so that your script will not destroy.

Example code:

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");
    }
}

When people call it like this:

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

They will get the error below and the script will destroy itself:

enter image description here

Now, if you call create it from your plugin and call the keepAlive function, the script should stay:

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

Note:

This is not an Editor script and it made to work when you click the "Play" button but you can use [ExecuteInEditMode] to make it execute in the Editor.

查看更多
倾城 Initia
3楼-- · 2019-05-16 10:17

A very simple solution is to make your class an inner class of some owner:

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

You can add the class easily enough:

gameObject.AddComponent<NotAMonoBehaviour.MyMonoBehaviour>()

And it will not show up in the inspector's Add Component list. Setting using the hide flags as suggested will also stop it from showing up in the inspector itself, although that can't be relied upon entirely, as you can open the Debug view in the inspector and still see hidden components.

查看更多
等我变得足够好
4楼-- · 2019-05-16 10:24

Since you are adding it with AddComponent, maybe you want to remove the MonoBehaviour part of your component.

Consider you have that main component that creates the sub component in Start:

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

turn that into:

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

The problem is that you most likely wanted to use all the Unity callbacks. Add them to the TopComponent and call the SubComponent explicitly.

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楼-- · 2019-05-16 10:33

For my case, I use Monobehaviour.Reset() method to prevent addcomponent in Editor.

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

Reset is called when the user hits the Reset button in the Inspector's context menu or when adding the component the first time. This function is only called in editor mode. Reset is most commonly used to give good default values in the inspector.

    private void Reset()
    {
        if (this.GetType() == typeof(MyCustomClass))
        {
            DestroyImmediate( this );
        }
    }
查看更多
登录 后发表回答