如何创建自定义检查器guilayout.toggle?

时间:2019-02-14 18:39:44

标签: c# unity3d

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

[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        Control control = (Control)target;

        if (GUILayout.Toggle(control.isControl, "Control"))
        {
            control.ToControl();
        }
    }
}

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

public class Control : MonoBehaviour
{
    public Rigidbody rigidbody;
    public bool isControl = false;

    // Start is called before the first frame update
    void Start()
    {

    }

    public void ToControl()
    {
        if(isControl == false)
        {

        }
        else
        {
            Destroy(rigidbody);
        }
    }
}

我想要做的是guilayout.toggle或按钮,并且能够销毁并向控制对象上的游戏对象添加刚体。

如何创建将刚体添加回游戏对象?

如何使用isControl标志?这个想法是在编辑器脚本中使用guilayout.toggle。

我想在游戏运行时破坏或添加新的刚体!但是在检查器中使用guilayout.toggle或按钮。

1 个答案:

答案 0 :(得分:1)

实际上,您根本不需要检查脚本。只需添加重复检查布尔值,例如在LateUpdate中,使组件[ExecuteInEditoMode]

using UnityEngine;

[ExecuteInEditoMode]
public class Control : MonoBehaviour
{
    public Rigidbody rigidbody;
    public bool isControl;

    // repeatedly check the bool
    private void LateUpdate()
    {
        ToControl();
    }

    public void ToControl()
    {
        if (!isControl && rigidbody)
        {
            // in editmode use DestroyImmediate
            if (Application.isEditor && !Application.isPlaying)
            {
                DestroyImmediate(rigidbody);
            }
            else
            {
                Destroy(rigidbody);
            }

            rigidbody = null;
        }
        else if(isControl && !rigidbody)
        {
            rigidbody = gameObject.AddComponent<Rigidbody>();

            // adjust settings of rigidbody
        }
    }
}

通过这种方式LateUpdate在播放模式和编辑模式下都被调用,并且只会对isControl的值做出反应。


当然,一直都要调用此LateUpdate会产生开销,因此,如果要避免使用它,只能从编辑器中调用它。但是,由于您使用的是base.OnInspectorGUI();,因此您实际上并不需要额外的Toggle,因为您已经拥有默认检查器之一。

所以可以简单地做

using UnityEngine;

public class Control : MonoBehaviour
{
    public Rigidbody rigidbody;
    public bool isControl;

    public void ToControl()
    {
        if (!isControl && rigidbody)
        {
            if (Application.isEditor && !Application.isPlaying)
            {
                DestroyImmediate(rigidbody);
            }
            else
            {
                Destroy(rigidbody);
            }

            rigidbody = null;
        }
        else if(isControl && !rigidbody)
        {
            rigidbody = gameObject.AddComponent<Rigidbody>();
        }
    }
}

,并且只需在编辑器脚本中执行

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
    private Control control;

    // calle when the object gains focus
    private void OnEnable()
    {
        control = (Control)target;
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        if (!control.isControl && control.rigidbody)
        {
            control.ToControl();
            Repaint();
        }
        else if (control.isControl && !control.rigidbody)
        {
            control.ToControl();
            Repaint();
        }
    }
}

但是,您已经注意到这可能会影响撤消/重做的工作方式-在这种情况下,重置isControl的值,但不删除RigidBody组件,导致错误(请参见下文)


或者因为您询问了它,所以您可以添加ToggleField(由于base.OnInspectorGUI();还附带了ToggleField,因此您将获得两次)

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
    private Control control;

    // calle when the object gains focus
    private void OnEnable()
    {
        control = (Control)target;
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        control.isControl = EditorGUILayout.Toggle("additional isControl", control.isControl);

        if (!control.isControl && control.rigidbody)
        {
            control.ToControl();
            Repaint();
        }
        else if (control.isControl && !control.rigidbody)
        {
            control.ToControl();
            Repaint();
        }
    }
}

,您会注意到,使用additional isControl更改值的解决方案无法完全使用“撤消/重做”功能,并且会标记您的场景为“脏”,因此Unity可能不会保存这些更改!


因此如果,您确实希望在检查员脚本中包含自定义切换字段,那么我强烈建议您使用正确的SerializedProperty而不是直接对{{1}进行更改}(有时无法避免,就像添加组件一样):

target

这看起来更加复杂,实际上您有重复的代码,但是它提供了完全的撤消/重做支持,并将对象和场景标记为脏的,以便Unity保存更改。