做UI的时候,序列化的属性,代码写好后,每次都需要手动拖动相应的GameObject到Inspector上。通过下面的方法,我们可以实现自动赋值,省去手动拖动的体力劳动。
效果如下,序列化的属性的 变量名 跟 子物体的名称保持一致,比如下图中的 _weapon 和 _bag .
实现如下:
创建脚本 AutohookAttribute.cs
// NOTE DONT put in an editor folder!
using UnityEngine;
public class AutohookAttribute : PropertyAttribute
{
}
创建Editor文件夹,并在里面创建 AutohookPropertyDrawer.cs
// NOTE put in a Editor folder
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(AutohookAttribute))]
public class AutohookPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var component = FindAutohookTarget(property);
if (component != null)
{
// if (property.objectReferenceValue == null)
property.objectReferenceValue = component;
}
EditorGUI.PropertyField(position, property, label);
}
/// <summary>
/// Takes a SerializedProperty and finds a local component that can be slotted into it.
/// Local in this context means its a component attached to the same GameObject.
/// This could easily be changed to use GetComponentInParent/GetComponentInChildren
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private Component FindAutohookTarget(SerializedProperty property)
{
var root = property.serializedObject;
if (root.targetObject is Component)
{
// first, lets find the type of component were trying to autohook...
var type = GetTypeFromProperty(property);
// ...then use GetComponent(type) to see if there is one on our object.
var component = (Component)root.targetObject;
// var gb = (GameObject) root.targetObject;
// Debug.LogError(component.transform(type));
var components = component.GetComponentsInChildren(type);
foreach (var item in components)
{
//确保GameObject不要有重名的
if (item.gameObject.name == property.name)
{
return item.gameObject.GetComponent(type);
}
}
}
else
{
Debug.Log("OH NO handle fails here better pls");
}
return null;
}
/// <summary>
/// Uses reflection to get the type from a serialized property
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private static System.Type GetTypeFromProperty(SerializedProperty property)
{
// first, lets get the Type of component this serialized property is part of...
var parentComponentType = property.serializedObject.targetObject.GetType();
// ... then, using reflection well get the raw field info of the property this
// SerializedProperty represents...
var fieldInfo = parentComponentType.GetField(property.propertyPath);
// ... using that we can return the raw .net type!
return fieldInfo.FieldType;
}
}
测试脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
[Autohook]
public Transform _weapon;
[Autohook]
public Transform _bag;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
参考:https://gist.github.com/LotteMakesStuff/d6a9a4944fc667e557083108606b7d22