Есть скрипт, который работает в режиме [ExecuteAlways]. В основном это функции, вызываемые в Start () и OnValidate () для обновления положения объектов на основе изменений в редакторе. Это все отлично работает.
Когда объект добавляется как дочерний объект к сценарию в окне Hierarchy, я хочу вызвать UpdateRing () и интегрировать его в кольцо. Установка OnHierarchyChange () с UpdateRing (), похоже, ничего не делает. В других вопросах OnHierarchyChange () помещается в файл редактора, но я не знаю, как я могу поместить OnHierarchyChange () в файл редактора и вызвать UpdateRing () ... или, если это то, что я должен сделать ...
Код GameObject:
using UnityEngine;
using System;
using System.ComponentModel;
[Serializable]
[ExecuteAlways]
public class ObjectsRing : MonoBehaviour
{
//public float radius = { get { return m_Radius; } set { m_Radius = value; } }
[Range(0f, 100f)]
public float radius = 10;
[Range(0f,360f)]
public float beginAngle = 0f;
[Range(0f,360f)]
public float endAngle = 360f;
public bool flip = false;
public enum orientationList {[Description("X-up")] Xup, [Description("Y-up")] Yup, [Description("Z-up")] Zup};
public orientationList orientation;
// Start is called before the first frame update
void Start()
{
UpdateRing();
}
// OnValidate is called when fields are changed in an Editor
void OnValidate()
{
UpdateRing();
}
// OnHierarchyChange is called when changes are made in the Hierarchy pane.
void OnHierarchyChange()
{
UpdateRing();
}
private void UpdateRing()
{
//Input error handling
if (endAngle < beginAngle)
{
float tempAngle = beginAngle;
beginAngle = endAngle;
endAngle = tempAngle;
}
// Attach mesh, rotate object and add material
float objectAngle = (endAngle - beginAngle) / (transform.childCount);
float rotation = beginAngle;
for (int cnt = 0; cnt < transform.childCount; cnt++)
{
// Translate and rotate each object
transform.GetChild(cnt).GetComponent<Transform>().localPosition = new Vector3(radius, 0, 0);
// transform.GetChild(cnt).GetComponent<Transform>().rotation = Quaternion.Euler(0, rotation, 0);
rotation = beginAngle + cnt * objectAngle;
transform.GetChild(cnt).RotateAround(transform.position, new Vector3(0,1,0), rotation);
transform.GetChild(cnt).LookAt(transform.position);
if (flip)
{
transform.GetChild(cnt).Rotate(new Vector3(0,180,0));
}
switch (orientation)
{
case orientationList.Xup:
{
transform.GetChild(cnt).Rotate(new Vector3(0,0,0));
break;
}
case orientationList.Yup:
{
transform.GetChild(cnt).Rotate(new Vector3(90,0,0));
break;
}
case orientationList.Zup:
{
transform.GetChild(cnt).Rotate(new Vector3(0,0,90));
break;
}
}
}
}
}
Код редактора:
using UnityEditor;
[CustomEditor(typeof(ObjectsRing)), CanEditMultipleObjects]
public class ObjectsRingEditor : Editor
{
private SerializedProperty radiusProperty;
private SerializedProperty beginAngleProperty;
private SerializedProperty endAngleProperty;
private SerializedProperty flipProperty;
private SerializedProperty orientationProperty;
public void OnEnable()
{
radiusProperty = serializedObject.FindProperty("radius");
beginAngleProperty = serializedObject.FindProperty("beginAngle");
endAngleProperty = serializedObject.FindProperty("endAngle");
flipProperty = serializedObject.FindProperty("flip");
orientationProperty = serializedObject.FindProperty("orientation");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
radiusProperty.floatValue = EditorGUILayout.Slider ("Radius", radiusProperty.floatValue, 0, 100);
beginAngleProperty.floatValue = EditorGUILayout.Slider ("Begin Angle", beginAngleProperty.floatValue, 0, 360);
endAngleProperty.floatValue = EditorGUILayout.Slider ("End Angle", endAngleProperty.floatValue, 0, 360);
flipProperty.boolValue = EditorGUILayout.Toggle ("Flip", flipProperty.boolValue);
orientationProperty.enumValueIndex = EditorGUILayout.Popup ("Orientation", orientationProperty.enumValueIndex, orientationProperty.enumDisplayNames);
serializedObject.ApplyModifiedProperties();
EditorApplication.update.Invoke();
}
}
3 ответа
Как уже упоминалось в других ответах, OnHierarchyChange
представляет собой сообщение { {X1}} и будет вызываться только Unity в классе этого типа, а не в MonoBehaviour
.
Однако решение на самом деле довольно простое!
Если вы помечаете свой класс [ExecuteAllways]
или [ExecuteInEditMode]
метод в MonoBehaviour
классах вызывается, если что-либо в изменениях сцены просто {{ X3 } } !
Update
вызывается только когда что-то в сцене изменилось.
Изменение чего-либо в иерархии подразумевает, что также что-то в сцене изменяется.
Таким образом, вы можете просто поставить его I Update
и только для того, чтобы предотвратить его запуск в приложении сборки
#if UNITY_EDITOR
private void Update()
{
UpdateRing();
}
#endif
Препроцессор #if UNITY_EDIROR
будет следить за тем, чтобы эта часть была удалена в сборке, чтобы избежать затрат на Update
полный вызов.
Если вам нужен Update
для чего-то другого, вы можете также сделать
private void Update()
{
#if UNITY_EDITOR
UpdateRing();
#endif
...
}
Или также
private void Update()
{
if(Application.isEditor)
{
UpdateRing();
}
...
}
Sidenotes
На самом деле для чего нужен пользовательский скрипт
Editor
? Я не вижу добавления чего-либо, что не было бы нарисовано в Инспекторе по умолчанию в любом случае ...[Serializable]
является избыточным для класса типаMonoBehaviour
.
< Сильный > Помещенный ...
void OnHierarchyChanged()
{
UpdateRing();
}
void Update()
{
EditorApplication.hierarchyChanged += OnHierarchyChanged;
}
... в классе ObjectRing, и он немедленно обновляет информацию об изменениях в иерархии, независимо от выбора.
Не уверен, что это лучший способ ... но это работает.
OnHierarchyChange
принадлежит к классу EditorWindow
и как такое будет работать только в сценариях, полученных из EditorWindow
.
Используя скрипт Monobehaviour
, вы просто создаете новый метод с именем OnHierarchyChange
в своем скрипте, который не связан с сообщением Unity EditorWindow.OnHierarchyChange
.
Взгляните на: https://docs.unity3d.com/ScriptReference/EditorApplication-hierarchyChanged .html
Мне удалось немного изменить пример кода, чтобы он выполнялся в атрибуте Monobehaviour
с [ExecuteAlways]
.
using UnityEditor;
using UnityEngine;
[ExecuteAlways]
public class HierarchyMonitor : MonoBehaviour
{
static HierarchyMonitor()
{
EditorApplication.hierarchyChanged += OnHierarchyChanged;
}
static void OnHierarchyChanged()
{
Debug.Log("Heirarchy Has changed");
//do you ring update here
}
}
В качестве альтернативы вы можете изменить код вашего редактора на EditorWindow
и использовать EditorWindow.OnHeirarchyChange
, но тогда вам потребуется открытое окно, чтобы оно могло выполняться.
Похожие вопросы
Новые вопросы
c#
C # (произносится как «резкий») - это высокоуровневый, статически типизированный язык программирования с несколькими парадигмами, разработанный Microsoft. Код C # обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, включая, среди прочего, .NET Framework, .NET Core и Xamarin. Используйте этот тег для вопросов о коде, написанном на C # или в формальной спецификации C #.