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