[Unity 技巧] 如何自定义 Inspector 变量显示名称 (CustomLabel)

目录

[1. 概览](#1. 概览)

[2. 代码实现与详细注释](#2. 代码实现与详细注释)

[第一步:定义 Attribute](#第一步:定义 Attribute)

[第二步:实现 PropertyDrawer](#第二步:实现 PropertyDrawer)

第三步:实际应用测试 (Test.cs)

[3. 常见问题解析](#3. 常见问题解析)

[4. 实际效果​](#4. 实际效果)


在 Unity 开发中,为了保证代码规范,变量名通常使用英文**(如 playerHealth、isGameStarted)** 。但在 Inspector 面板中配置数值时,策划或美术人员可能更希望看到直观的中文标签**(如"玩家血量"、"游戏是否开始")。**

本文将介绍如何使用 Unity 的 PropertyAttributePropertyDrawer 功能,实现一个 **[CustomLabel]**特性,让我们既能保留规范的代码命名,又能拥有清晰的中文 Inspector 面板。

1. 概览

我们需要创建三个部分:

  1. Attribute(特性类): 用于在变量上打标签,存储我们需要显示的中文名称。

  2. Drawer(绘制类): 核心逻辑,告诉 Unity 编辑器当遇到这个标签时,该如何绘制界面。

  3. Usage(测试用例): 实际挂载使用的脚本。

2. 代码实现与详细注释

第一步:定义 Attribute

这个脚本定义了 [CustomLabel] 属性本身。它只负责存储数据(标签名称)。

文件名:CustomLabelAttribute.cs 存放位置:任意 Scripts 文件夹(不需要放在 Editor 文件夹)

可以参考我的目录

CustomLabelAttribute.cs 代码内容如下

cs 复制代码
using UnityEngine;

public class CustomLabelAttribute : PropertyAttribute
{
    public string label;

    public CustomLabelAttribute(string label)
    {
        this.label = label;
    }
}

第二步:实现 PropertyDrawer

这个脚本负责具体的绘制逻辑。通过反射机制,它能在 Inspector 渲染该属性时,截获并修改显示的 Label。

文件名:CustomLabelDrawer.cs 存放位置:必须放在 Editor 文件夹内

CustomLabelDrawer .cs 代码内容如下

cs 复制代码
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(CustomLabelAttribute))]
public class CustomLabelDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        CustomLabelAttribute customLabel = (CustomLabelAttribute)attribute;

        // --- 关键逻辑解析 ---
        // 检查当前属性的路径是否以 "]" 结尾。
        // 在 Unity 中,数组或 List 的元素路径通常是 "variableName.Array.data[0]" 这种格式。
        // 如果我们不加这个判断,当此 Attribute 应用于数组字段本身时,
        // Unity 可能会尝试将数组内部的 "Element 0", "Element 1" 也重命名为我们的 Label,
        // 导致所有元素都叫同一个名字,没法区分。
        // 加上这个判断,确保我们只修改字段本身的名称,而保留数组元素的索引名称。
        if (!property.propertyPath.EndsWith("]"))
        {
            label.text = customLabel.label;
        }

        // 标记属性绘制开始
        EditorGUI.BeginProperty(position, label, property);

        // 绘制属性字段
        // includeChildren: true 表示如果是结构体或类,会自动绘制其子字段
        EditorGUI.PropertyField(position, property, label, true);

        // 标记属性绘制结束
        EditorGUI.EndProperty();
    }

    // 重新计算属性高度
    // 这一步很重要,否则对于自定义类或数组,Inspector 可能会因为高度计算错误导致重叠
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUI.GetPropertyHeight(property, label, true);
    }
}

第三步:实际应用测试 (Test.cs)

这里展示了在普通字段、自定义类内部字段、结构体、以及数组上的表现。

cs 复制代码
using UnityEngine;
using System.Collections.Generic;
using System;

[Serializable]
public class PlayerInfo
{
    [CustomLabel("血量")]
    public int health = 100;
    public int mana = 50;
    public string playerName = "Hero";
    public float speed = 5.0f;
}

public class Test : MonoBehaviour
{
    [CustomLabel("玩家信息")]
    public PlayerInfo player;

    public List<PlayerInfo> enemies;

    public PlayerInfo[] playerinfos;

    [CustomLabel("分数")]
    public int score;

    [CustomLabel("结构体")]
    public MyStruct myStruct;
}

[Serializable]
public struct MyStruct
{
    [CustomLabel("年龄")]
    public int age;
    [CustomLabel("性别")]
    public int sex;
    [CustomLabel("名字")]
    public string name;
    public string occupation;
}

3. 常见问题解析

为什么要判断 !property.propertyPath.EndsWith("]")

在 Unity 的序列化系统中:

1.普通变量路径:score

2.数组/列表变量本身路径:enemies、playerinfos

3.数组/列表内的元素路径:enemies.Array.data[0]、playerinfos.Array.data[0]

当你写下 **[CustomLabel("我的列表")] public int[] myList;**时:

1.Unity 绘制列表头,路径是 myList 。判断通过,名字变成**"我的列表"**。

2.如果不加那个判断,有些复杂的绘制情况下,Unity 可能会把 Attribute 的作用域延续到子元素上,导致你看到的列表变成了:

我的列表

我的列表 (本该是 Element 0)

我的列表 (本该是 Element 1)

3.加上 **EndsWith("]")**的判断,就显式地过滤掉了所有数组元素,保证了索引显示的正确性。

4. 实际效果

相关推荐
Sator13 小时前
Unity开发中常用的随机方法扩展
unity
dzj20213 小时前
Unity中使用LLMUnity遇到的问题(五)——主要脚本的继承关系+用DuckDB对知识库升级的思考
unity·向量数据库·向量搜索·duckdb·llmunity
地狱为王7 小时前
Unity使用Spleeter分离人声和伴奏
unity·游戏引擎·spleeter
在路上看风景10 小时前
26. Texture和Sprite
unity
lllljz12 小时前
Blender导出模型到Unity或UE5引擎材质丢失模型出错
unity·ue5·游戏引擎·blender·材质
_乐无13 小时前
Unity 发布 Android 安卓端所有文件可读写
android·unity·游戏引擎
JIes__1 天前
Unity(二)——核心系统
unity·游戏引擎
独处东汉1 天前
freertos开发空气检测仪之按键输入事件管理系统设计与实现
人工智能·stm32·单片机·嵌入式硬件·unity
Howrun7771 天前
虚幻引擎_C++_游戏开始菜单
游戏·游戏引擎·虚幻