1. 程式人生 > >Unity--PropertyAttribute和PropertyDrawer結合進行配置引用

Unity--PropertyAttribute和PropertyDrawer結合進行配置引用

應用場景,類中引用配置表中的技能id,程式碼如下圖

public class PropertyTest : MonoBehaviour
{
    public string prefabPath = "";
    //配置表中的技能id
    public int skillId = 0;
}

Inspector中的顯示如下圖

技能配置表如下圖

id為技能id,prefabPath為技能的特效路徑,以英雄名為字首,description為技能描述

Inspector中的SkillId的值為技能表中的id,需要手動填,不直觀,容易填錯,

下面的實現方式會去掉手動填id,而且顯示上更清晰直觀

先看下最終Inspector中顯示的效果,顯示的是英雄名稱/技能描述,操作流程是從列表中點選就好

具體實現程式碼如下

using System;
using UnityEngine;


public enum ReferenceType : int
{
    Prefab,
    SkillId
}

[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
public sealed class Reference : PropertyAttribute
{
    public ReferenceType RefType { get; private set; }
    public Reference(ReferenceType refType)
    {
        RefType = refType;
    }
}

public class PropertyTest : MonoBehaviour
{
    public string prefabPath = "";
    //配置表中的技能id
    [Reference(ReferenceType.SkillId)]
    public int skillId = 0;
}
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class SkillData
{
    public int id;
    public string prefabPath = "";
    public string description = "";
}

[CustomPropertyDrawer(typeof(Reference))]
public class ResReferenceDrawer : PropertyDrawer
{
    private static List<SkillData> skillConfigList = new List<SkillData>();
    private static List<int> ids = new List<int>();//id列表
    private static List<string> descriptions = new List<string>();//描述列表,Inspector顯示用
    [InitializeOnLoadMethod]
    //初始化測試資料
    static void InitTestData()
    {
        //測試資料begin
        skillConfigList.Clear();
        skillConfigList.Add(new SkillData{ id = 100, prefabPath = "xiaoqiao/a.prefab", description = "綻放之舞" });
        skillConfigList.Add(new SkillData{ id = 101, prefabPath = "xiaoqiao/b.prefab", description = "甜蜜戀風" });
        skillConfigList.Add(new SkillData { id = 102, prefabPath = "xiaoqiao/c.prefab", description = "星華繚亂" });
        skillConfigList.Add(new SkillData { id = 200, prefabPath = "houyi/a.prefab", description = "炙熱之風" });
        skillConfigList.Add(new SkillData { id = 201, prefabPath = "houyi/b.prefab", description = "燎原箭雨" });
        skillConfigList.Add(new SkillData { id = 202, prefabPath = "houyi/c.prefab", description = "懲戒射擊" });
        //測試資料end

        //一個id對應一個描述
        ids.Clear();
        descriptions.Clear();

        var em = skillConfigList.GetEnumerator();
        SkillData sc = null;
        while (em.MoveNext())
        {
            sc = em.Current;
            ids.Add(sc.id);
            var strs = sc.prefabPath.Split('/');
            //以英雄名稱為字首進行分類,EditorGUI.Popup為以斜槓符號/進行分層級顯示,有多少個斜槓就分多少層級
            var des = strs[0] + "/" + sc.description;
            descriptions.Add(des);
        }
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var reference = (Reference)attribute;
        switch (reference.RefType)
        {
            case ReferenceType.Prefab:
                HandlePrefabReference(position, property, label);
                break;

            case ReferenceType.SkillId:
                HandleSkillIdReference(position, property, label);
                break;
        }
    }

    private void HandleSkillIdReference (Rect position, SerializedProperty property, GUIContent label)
    {
        if (SerializedPropertyType.Integer != property.propertyType)
        {
            EditorGUI.PropertyField(position, property);
            return;
        }

        EditorGUI.BeginChangeCheck();
        //得到描述在列表中的下標
        var value = EditorGUI.Popup(position, property.displayName, Math.Max(0, ids.IndexOf(property.intValue)), descriptions.ToArray());
        if (EditorGUI.EndChangeCheck())
        {
            //根據下標從id列表中找出技能id進行賦值
            property.intValue = ids[value];
            Debug.Log(ids[value]);
        }
    }

    private void HandlePrefabReference (Rect position, SerializedProperty property, GUIContent label)
    {
        if (SerializedPropertyType.String != property.propertyType)
        {
            EditorGUI.PropertyField(position, property);
            return;
        }

        //根據路徑得到一個型別為GameObject的物件
        var prefab = (GameObject)AssetDatabase.LoadAssetAtPath(property.stringValue, typeof(GameObject));
        //ObjectField會在Inspector面板中顯示一個框,後面帶一個小按鈕,點選後彈出面板選擇prefab
        var obj = (GameObject)EditorGUI.ObjectField(position, property.displayName, prefab, typeof(GameObject), false);
        //得到prefab的路徑
        string newPath = AssetDatabase.GetAssetPath(obj);
        //設定路徑
        property.stringValue = newPath;
        Debug.Log(newPath);
    }
}