Как я могу создать собственный инспектор guilayout.toggle? - PullRequest
0 голосов
/ 14 февраля 2019
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 или кнопку, чтобы иметь возможность уничтожить и добавить Rigidbody к объекту игры, на котором будет включен сценарий управления.

Как создать обратно добавить Rigidbody к игровому объекту?

И как мне использовать флаг isControl?Идея состоит в том, чтобы использовать guilayout.toggle в скрипте редактора.

Я хочу уничтожить или добавить новое твердое тело во время игры!Но с помощью guilayout.toggle или кнопки в инспекторе.

1 Ответ

0 голосов
/ 15 февраля 2019

На самом деле вам не понадобится сценарий инспектора для этого вообще.Просто добавьте повторную проверку на bool, например, в 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();
        }
    }
}

НО , вы уже заметите, что это может повлиять на работу Undo / Redo - в этом случае, например, будет сброшено значение isControl, ноне удаляйте вдоль компонента RigidBody, приводящего к ошибкам (см. подробнее ниже)


Или, так как вы спросили об этом, вы можете добавить ToggleField (в настоящее время он будет у вас дважды, так как один также поставляется с base.OnInspectorGUI();)

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, не имеет возможности полностью использовать Undo / Redo и будет NOT пометьте вашу сцену как «грязную», чтобы Unity не могла сохранить эти изменения!


Так что если вы действительно хотите иметь свое собственное поле переключения в скрипте инспектора, я бы настоятельно рекомендовалправильно использовать SerializedProperty с вместо непосредственного внесения изменений в target (иногда этого нельзя избежать, как при добавлении компонента):

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

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

        // link serialized property
        _isControl = serializedObject.FindProperty("isControl");
        rigidbody = serializedObject.FindProperty("rigidbody");
    }

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

        // load current values into the serialized copy
        serializedObject.Update();

        if (!_isControl.boolValue && rigidbody.objectReferenceValue)
        {
            DestroyImmediate(rigidbody.objectReferenceValue);
            rigidbody.objectReferenceValue = null;
        }
        else if (_isControl.boolValue && !rigidbody.objectReferenceValue)
        {
            var rb = control.gameObject.AddComponent<Rigidbody>();
            rigidbody.objectReferenceValue = rb;
        }

        // write back changed serialized values to the actual values
        serializedObject.ApplyModifiedProperties();
    }
}

Это выглядит сложнееи фактически у вас есть дублированный код, но он дает вам полную поддержку Undo / Redo и помечает ваши объекты и сцены как грязные, так что Unity сохраняет изменения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...