unity EditorGuiLayout 根据其他值改变滑块属性
Unity EditorGuiLayout change slider properties depending on other values
我想为我的脚本制作自定义检查器脚本。我需要两个游戏对象和一个滑块。但是,滑块最大值取决于两个游戏对象之间的距离。我正在使用 EditorGUILayout(编辑器)。直到现在我尝试用 EditorGUI.BeginChangeCheck()
和 if 语句 if (EditorGUI.EndChangeCheck()){...}
来改变它。然而,这并没有真正起作用,滑块也没有出现。我正在 OnInspectorGUI()
方法中做所有事情。我是新手,所以我也不知道我还能做些什么。
代码如下:
public override void OnInspectorGUI()
{
UILineRenderer renderer = (UILineRenderer) target;
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Points");
renderer.startTR = (GameObject) EditorGUILayout.ObjectField(renderer.startTR, typeof(GameObject), true);
renderer.endTR = (GameObject)EditorGUILayout.ObjectField(renderer.endTR, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck())
{
if(renderer.startTR != null && renderer.endTR != null)
{
float val = Mathf.Abs(renderer.startTR.GetComponent<RectTransform>().anchoredPosition.x - renderer.endTR.GetComponent<RectTransform>().anchoredPosition.x);
renderer.radius = EditorGUILayout.Slider("Radius", renderer.radius, 0, val);
}
}
}
有没有办法保存创建的 EditorGUILayout 元素并在之后更改它的属性?如果没有,我该如何解决我的问题?预先感谢您的帮助!
你犯了一个巨大但典型的错误 ;)
您正在直接通过 target
访问和设置值。但这不会将对象和更改的字段标记为 dirty 这意味着
- 这些值未保存
- 更改不适用于 Undo/redo
- 预制件不会被正确覆盖
最严重的当然是第一个了;)
除非您确切地知道自己在做什么并手动将对象标记为脏的,否则您总是宁愿通过 SerializedObject
and SerializedProperty
s。
设置它需要更多的努力,但它会自动处理所有提到的事情:
SerializedProperty startTr;
SerializedProperty endTr;
SerializedProperty radius;
private void OnEnable ()
{
// Once link up the serialized properties whith their desired underlying fields
startTr = serializedObject.FindPropery(nameof(UILimeRenderer.startTr));
endTr = serializedObject.FindPropery(nameof(UILimeRenderer.endTr));
radius = serializedObject.FindPropery(nameof(UILimeRenderer.radius));
}
public override void OnInspectorGUI()
{
// Load current values into the serialized object
serializedObject.Update();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Points");
// Use the default drawer for these properties
// GUIContent.None for omitting the label
EditorGUILayout.PropertyField(startTR, GUIContent.None, true);
EditorGUILayout.PropertyField(endTR, GUIContent.None, true);
EditorGUILayout.EndHorizontal();
if(startTR.objectReferenceValue && endTR.objectReferenceValue)
{
var maxValue = Mathf.Abs(((GameObject)startTR.objectReferenceValue).GetComponent<RectTransform>().anchoredPosition.x - ((GameObject)endTR.objectReferenceValue).GetComponent<RectTransform>().anchoredPosition.x);
radius.floatValue = EditorGUILayout.Slider("Radius", radius.floatValue, 0, maxValue);
}
// Write back changed values. This handles all the mentioned dirty marking
serializedObject.ApplyModifiedProperties();
}
我还建议实际使用 RectTransform
字段而不是 GameObject
,然后去掉 GetComponent
.
我想为我的脚本制作自定义检查器脚本。我需要两个游戏对象和一个滑块。但是,滑块最大值取决于两个游戏对象之间的距离。我正在使用 EditorGUILayout(编辑器)。直到现在我尝试用 EditorGUI.BeginChangeCheck()
和 if 语句 if (EditorGUI.EndChangeCheck()){...}
来改变它。然而,这并没有真正起作用,滑块也没有出现。我正在 OnInspectorGUI()
方法中做所有事情。我是新手,所以我也不知道我还能做些什么。
代码如下:
public override void OnInspectorGUI()
{
UILineRenderer renderer = (UILineRenderer) target;
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Points");
renderer.startTR = (GameObject) EditorGUILayout.ObjectField(renderer.startTR, typeof(GameObject), true);
renderer.endTR = (GameObject)EditorGUILayout.ObjectField(renderer.endTR, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck())
{
if(renderer.startTR != null && renderer.endTR != null)
{
float val = Mathf.Abs(renderer.startTR.GetComponent<RectTransform>().anchoredPosition.x - renderer.endTR.GetComponent<RectTransform>().anchoredPosition.x);
renderer.radius = EditorGUILayout.Slider("Radius", renderer.radius, 0, val);
}
}
}
有没有办法保存创建的 EditorGUILayout 元素并在之后更改它的属性?如果没有,我该如何解决我的问题?预先感谢您的帮助!
你犯了一个巨大但典型的错误 ;)
您正在直接通过 target
访问和设置值。但这不会将对象和更改的字段标记为 dirty 这意味着
- 这些值未保存
- 更改不适用于 Undo/redo
- 预制件不会被正确覆盖
最严重的当然是第一个了;)
除非您确切地知道自己在做什么并手动将对象标记为脏的,否则您总是宁愿通过 SerializedObject
and SerializedProperty
s。
设置它需要更多的努力,但它会自动处理所有提到的事情:
SerializedProperty startTr;
SerializedProperty endTr;
SerializedProperty radius;
private void OnEnable ()
{
// Once link up the serialized properties whith their desired underlying fields
startTr = serializedObject.FindPropery(nameof(UILimeRenderer.startTr));
endTr = serializedObject.FindPropery(nameof(UILimeRenderer.endTr));
radius = serializedObject.FindPropery(nameof(UILimeRenderer.radius));
}
public override void OnInspectorGUI()
{
// Load current values into the serialized object
serializedObject.Update();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Points");
// Use the default drawer for these properties
// GUIContent.None for omitting the label
EditorGUILayout.PropertyField(startTR, GUIContent.None, true);
EditorGUILayout.PropertyField(endTR, GUIContent.None, true);
EditorGUILayout.EndHorizontal();
if(startTR.objectReferenceValue && endTR.objectReferenceValue)
{
var maxValue = Mathf.Abs(((GameObject)startTR.objectReferenceValue).GetComponent<RectTransform>().anchoredPosition.x - ((GameObject)endTR.objectReferenceValue).GetComponent<RectTransform>().anchoredPosition.x);
radius.floatValue = EditorGUILayout.Slider("Radius", radius.floatValue, 0, maxValue);
}
// Write back changed values. This handles all the mentioned dirty marking
serializedObject.ApplyModifiedProperties();
}
我还建议实际使用 RectTransform
字段而不是 GameObject
,然后去掉 GetComponent
.