Apo*_*olo 4 c# unity-game-engine
我确信这个问题已经存在,但我找不到它,抱歉。
我正在尝试将对象的序列化字段与其其他组件同步。
假设我有一个字段“大小”,它会影响对象变换比例:
[SerializeField]
int _size;
Run Code Online (Sandbox Code Playgroud)
我正在寻找一个事件处理程序或允许我做的事情:
void onSerializedPropertyChange() {
transform.localScale = new Vector3(_size,_size,_size);
}
Run Code Online (Sandbox Code Playgroud)
有这样的方法吗?
最后,我们的想法是使用多个属性并在预览结果的同时调整对象属性。
Mat*_*wHD 10
根据序列化字段更新对象?
添加 OnChangedCall 元素时,您可以更新具有 SerializeField 的变量。
成员变量:
[SerializeField]
[OnChangedCall("onSerializedPropertyChange")]
private int _size;
Run Code Online (Sandbox Code Playgroud)
您现在应该能够将函数作为字符串添加到括号中,并且应该在更改时调用它。
调用的方法必须是公共的,否则会产生错误!
方法:
public void onSerializedPropertyChange() {
transform.localScale = new Vector3(_size,_size,_size);
}
Run Code Online (Sandbox Code Playgroud)
OnChangedCall 是一个自定义的 PropertyAttribute,需要继承它。
OnChangedCall 类:
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Reflection;
public class OnChangedCallAttribute : PropertyAttribute
{
public string methodName;
public OnChangedCallAttribute(string methodNameNoArguments)
{
methodName = methodNameNoArguments;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(OnChangedCallAttribute))]
public class OnChangedCallAttributePropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, property, label);
if(EditorGUI.EndChangeCheck())
{
OnChangedCallAttribute at = attribute as OnChangedCallAttribute;
MethodInfo method = property.serializedObject.targetObject.GetType().GetMethods().Where(m => m.Name == at.methodName).First();
if (method != null && method.GetParameters().Count() == 0)// Only instantiate methods with 0 parameters
method.Invoke(property.serializedObject.targetObject, null);
}
}
}
#endif
Run Code Online (Sandbox Code Playgroud)
这是我从 IndieGameDev 的答案中得到的 OnChangedCallAttributePropertyDrawer 版本。
主要变化是添加了以下行
property.serializedObject.ApplyModifiedProperties();
Run Code Online (Sandbox Code Playgroud)
这将确保 SerializedField 在调用函数之前更新,从而修复了当序列化字段更改时场景无法正确更新的错误。
OnChangedCallAttributePropertyDrawer :
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(OnChangedCallAttribute))]
public class OnChangedCallAttributePropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, property, label);
if (!EditorGUI.EndChangeCheck()) return;
var targetObject = property.serializedObject.targetObject;
var callAttribute = attribute as OnChangedCallAttribute;
var methodName = callAttribute?.methodName;
var classType = targetObject.GetType();
var methodInfo = classType.GetMethods().FirstOrDefault(info => info.Name == methodName);
// Update the serialized field
property.serializedObject.ApplyModifiedProperties();
// If we found a public function with the given name that takes no parameters, invoke it
if (methodInfo != null && !methodInfo.GetParameters().Any())
{
methodInfo.Invoke(targetObject, null);
}
else
{
// TODO: Create proper exception
Debug.LogError($"OnChangedCall error : No public function taking no " +
$"argument named {methodName} in class {classType.Name}");
}
}
}
#endif
Run Code Online (Sandbox Code Playgroud)
我只想为那些可能不知道的人分享一个小技巧,我不喜欢使用字符串引用函数,它通常很容易出错,而且您很可能不会从 IDE 获得帮助。
您可以改为使用 nameof(),这将允许您使用 IDE 自动完成功能,Rider 还将识别正在使用的函数。
[SerializeField]
[OnChangedCall(nameof(UpdateHeuristic))]
private AStar.Heuristic heuristic;
public void UpdateHeuristic()
{
_pathfinding?.SetHeuristic(heuristic);
}
Run Code Online (Sandbox Code Playgroud)
完整代码:
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Reflection;
public class OnChangedCallAttribute : PropertyAttribute
{
public string methodName;
public OnChangedCallAttribute(string methodNameNoArguments)
{
methodName = methodNameNoArguments;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(OnChangedCallAttribute))]
public class OnChangedCallAttributePropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, property, label);
if (!EditorGUI.EndChangeCheck()) return;
var targetObject = property.serializedObject.targetObject;
OnChangedCallAttribute callAttribute = attribute as OnChangedCallAttribute;
var methodName = callAttribute?.methodName;
var classType = targetObject.GetType();
var methodInfo = classType.GetMethods().FirstOrDefault(info => info.Name == methodName);
// Update the serialized field
property.serializedObject.ApplyModifiedProperties();
// If we found a public function with the given name that takes no parameters, invoke it
if (methodInfo != null && !methodInfo.GetParameters().Any())
{
methodInfo.Invoke(targetObject, null);
}
else
{
// TODO: Create proper exception
Debug.LogError($"OnChangedCall error : No public function taking no " +
$"argument named {methodName} in class {classType.Name}");
}
}
}
#endif
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7361 次 |
| 最近记录: |