Unity编辑器功能及拓展(3) —[Attribute]特性

  在 Unity 中,[Attribute]格式的特性是用于扩展编辑器功能、控制序列化行为和调整 Inspector 显示,进行编辑器拓展的核心工具。

一.基础编辑器拓展

1.基础序列化控制

1.[SerializeField]  强制显示私有变量到Inspector

2.[HideInInspector]  隐藏该字段在Inspector中的显示

3.[NonSerialized] 阻止该字段被序列化

4.[Serializable] 对类内类使用

2.Inspector布局优化

1.[Header(“Title”)] 为该字段添加标题

2.[Tooltip("Description")] 鼠标悬停显示提示文本

3.[Space(int)] 插入垂直距离,修改字段显示垂直间距

4.[TexArea] 动态拓展多行文本输入框

5.[Multiline(int)] 多行文本输入框

3.数值约束

1.[Range(min,max)] float类型变量使用,滑动条约束

2.[Min(minValue)] 设置最小值

4.警告提示

1.[Obsolete(“已弃用的提示”)]:警告该标志字段,已弃用

示例代码

 [SerializeField, Range(0, 1)] float ID;[HideInInspector] public int index;public Student student;[TextArea][Space(5)][SerializeField]string description;[Obsolete("弃用的错误的数值")]int wrongNum;int trueNum;private void ObsoleteTest(){wrongNum++;}[Serializable]
public class Student
{[Header("年龄"), Tooltip("以阴历为准"), Min(0)]public int age;
}

二.高级编辑器拓展

1.脚本标记

1.[ExecuteInEditorMode]:该脚本在编辑器模式下运行

2.[RequireComponment(typeof(TypeName ))]:挂载本脚本时将自动添加目标组件

3.[DisallowMultipleComponent]:禁止同一物体重复挂载本脚本

4.[CustomEditor(typeof(TypeName))]:本脚本对目标类型脚本进行编辑器面板下的拓展

第四种较为特殊,在这里详细介绍

[CustomEditor(typeof(TypeName))]

使用该特性,需要编写一个实例脚本及一个对其进行拓展的继承Editor的脚本。

实例脚本Test

示例代码

using UnityEngine;[ExecuteInEditMode]//编辑模式下任意操作引起帧运行
[DisallowMultipleComponent]//禁止重复挂载
[RequireComponent(typeof(Rigidbody))]
public class Test : MonoBehaviour
{public int ID;public string Name;public bool isDead;public GameObject weapon;public Texture texture;public E_testEnum testEnum;public float processSlider;public Player player;void Update(){//  Debug.Log("操作了一下");}public void TestDebug(){Debug.Log("Test!");}
}public enum E_testEnum
{test1, test2, test3
}

编辑器脚本TestEditor

     我们需要重写实现Editor中的OnInspectorGUI()方法,在脚本组件面板上绘制信息。

当OnInspectorGUI()函数中无功能代码时,发现Test脚本无法正常显示信息(见下图)

此时,可以使用DrawDefaultInspector()来进行默认字段的正常绘制。

 public override void OnInspectorGUI(){DrawDefaultInspector();}

接下来我们来自定义绘制一下所有字段。

示例代码

using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{//获得需要编辑显示的组件private Test testComponent;//当关联组件所在对象被选中或组件被添加时调用private void OnEnable(){testComponent = (Test)target;//在当前的外挂脚本中获得需要被拓展的test组件对象}//当关联组件所在对象被取消选中或组件爱你被移除时调用private void OnDisable(){testComponent = null;}//OnInspectorGUI是用于绘制检视面板的生命周期函数public override void OnInspectorGUI(){//标题显示EditorGUILayout.LabelField("测试拓展脚本");//简单数据类型绘制testComponent.ID = EditorGUILayout.IntField("角色ID", testComponent.ID);testComponent.Name = EditorGUILayout.TextField("角色姓名", testComponent.Name);testComponent.isDead = EditorGUILayout.Toggle("是否死亡", testComponent.isDead);//对象数据类型绘制/testComponent.weapon = EditorGUILayout.ObjectField("武器", testComponent.weapon, typeof(GameObject), true) as GameObject;testComponent.texture = EditorGUILayout.ObjectField("贴图", testComponent.texture, typeof(Texture), false) as Texture;//标题,原始组件的值,成员变量的类型,是否可以将场景中对象拖给这个变量,注意纹理来源于project而非场景中物体,故用false//枚举数据类型绘制testComponent.testEnum = (E_testEnum)EditorGUILayout.EnumPopup("玩家职业", testComponent.testEnum);//终极数据类型绘制(适用于list等,以及自己写的类型的数据)OtherDataDraw("player", "玩家");//滑动条绘制testComponent.processSlider = EditorGUILayout.Slider(new GUIContent("滑动条"), testComponent.processSlider, 0, 100);if (testComponent.processSlider >= 80){EditorGUILayout.HelpBox("滑动条即将到顶", MessageType.Error);}if (testComponent.processSlider <= 20){EditorGUILayout.HelpBox("滑动条即将到底", MessageType.Warning);}//按钮绘制(默认纵向绘制,一行占一个按钮)if (GUILayout.Button("来个按钮")){Debug.Log("点击了按钮");};//开启横向绘制(一行可多个按钮)GUILayout.BeginHorizontal();//关闭横向绘制GUILayout.EndHorizontal();}void OtherDataDraw(string originalDataName, string processedHeadName){//更新可序列化数据serializedObject.Update();//通过成员变量名找到组件上的成员变量SerializedProperty sp = serializedObject.FindProperty(originalDataName);//可序列化数据绘制(取到的数据,标题,是否将所有获得的序列化数据显示)EditorGUILayout.PropertyField(sp, new GUIContent(processedHeadName), true);//将修改的数据写入到可序列化的原始数据中serializedObject.ApplyModifiedProperties();}
}

2.[AddComponment( )]

标记实例脚本,编辑器面板Componment菜单拓展

使用:点击拓展脚本即可为目标物体添加脚本组件。

常用重载

1.AddComponentMenu(string menuName)

编辑器面板Componment菜单拓展,标记实例脚本


2.AddComponentMenu(string menuName, int order) 

编辑器面板Componment菜单拓展,标记实例脚本

参数order表示拓展脚本按钮在面板中的优先级,值越小,在面板中位置越靠上。

示例代码

[AddComponentMenu("MyAddC/addc1", 1)]
public class AddC1 : MonoBehaviour{
}

注意:先选中场景内游戏物体,再为其添加脚本~

3.[MenuItem( )]

编辑器面板菜单拓展,标记静态函数。点击拓展方法即可在编辑器面板下执行。

常用重载

1.[MenuItem("MenuName/FuncName")]

编辑器面板菜单拓展,标记静态方法。

//增加菜单栏选项
[MenuItem("MyTools/SendMes1 &1", false, 900)]
static void SendMes1()
{print("Print1");
}

2.[MenuItem("MenuName/FuncName",int priority)] 

编辑器面板菜单拓展,标记静态方法。

参数priority表示拓展方法在面板中的优先级,值越小,在面板中位置越靠上。

优先级每差出10级,面板下多一条分割线(见下图)


3.[MenuItem(“CONTEXT/组件名称/拓展功能名称”)]

Inspector拓展脚本缩略点内功能,对当前实例脚本内非静态方法使用。

示例代码

  //给某目标类型组件添加右键菜单选项【“CONTEXT/Rigibody(组件名称)/Init(按钮名称)”】[MenuItem("CONTEXT/Rigidbody/Init")]static void RigInit(){Debug.Log("我是Rigibody");}

4.[ContextMenu( )]

常用重载

1.[ContextMenu(“功能描述”)]

Inspector拓展脚本缩略点内功能,对当前实例脚本内非静态方法使用。


2.[ContextMenuItem("功能描述", "实例方法名称")]

Inspector拓展字段右键菜单功能,对当前实例脚本内非静态方法使用。
优化:nameof( )关键字替代"实例方法" ,便于后期维护。

示例代码

public class AttributesTest : MonoBehaviour
{[ContextMenuItem("增加10点力量", "AddPower")]public int power;//对当前实例脚本使用,方法需非静态,打开脚本右侧缩略点可直接调用该方法[ContextMenu("组件目录菜单")]void Init(){Debug.Log("方法调用");}void AddPower(){power += 10;}
}

    以上是我学习过程中总结的印象中大致所有的Attribute特性及其应用,可能会有瑕疵或缺漏,欢迎大家不吝赐教。

本篇完!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/43028.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探究 CSS 如何在HTML中工作

2025/3/28 向全栈工程师迈进&#xff01; 一、CSS的作用 简单一句话——美化网页 <p>Lets use:<span>Cascading</span><span>Style</span><span>Sheets</span> </p> 对于如上代码来说&#xff0c;其显示效果如下&#xff1…

【docker】docker-compose安装RabbitMQ

docker-compose安装RabbitMQ 1、配置docker-compose.yml文件&#xff08;docker容器里面的目录请勿修改&#xff09;2、启动mq3、访问mq4、查看服务器映射目录5、踩坑5.1、权限不足 1、配置docker-compose.yml文件&#xff08;docker容器里面的目录请勿修改&#xff09; versi…

小红书xhs逆向算法还原(202503月更新)

今天闲着没事再来看下小红书&#xff0c;发现好像过不去了&#xff0c;解开base64看看 {"signSvn":"56","signType":"x2","appId":"xhs-pc-web","signVersion":"1","payload":&qu…

全国产1U机架式交换机解决方案

规格参数 基本参数信息 基本信息 端口规格 32个10/100/1000Base-T RJ45接口&#xff0c;8个1G/10Gig SFP Console管理端口&#xff0c;RJ45&#xff0c;数量&#xff1a;1 支持1个USB接口&#xff0c;1个复位按键 外形尺寸 482 mm&#xff08;长&#xff09; 300mm &#…

【8】递归之经典题型总结

&#x1f4da;博客主页&#xff1a;代码探秘者 ✨专栏&#xff1a;《JavaSe》 其他更新ing… ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;作者水平有限&#xff0c;欢迎各位大佬指点&…

JC4010快速入门

目录 一、硬件接线二、软件操作2.1、 设置2.2、 零点 校准2.3、闭环控制2.4、调整PI参数2.5、切换控制模式 三、CAN模块操作3.1、使用CANable3.2、发送指令3.3、其它 一、硬件接线 ZH1.5-6P 和 SH1.0-3P 端子定义如下&#xff1a; 红色接电源正极&#xff0c;黑色接电源负极&a…

基于Spring Boot的高校普法系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

从零开始跑通3DGS教程:(三)坐标系与尺度编辑(CloudCompare)

写在前面 本文内容 本文所属《从零开始跑通3DGS教程》系列文章&#xff1b; sfm重建的点云已经丢掉了尺度信息&#xff0c;并且坐标系跟图像数据有关(SFM初始化选择的图像)&#xff0c;所以如果想恢复物理真实尺度&#xff0c;以及在想要的视角下渲染&#xff0c;那么需要对尺度…

代码随想录day31 贪心part05

56.合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;in…

【MyBatis】MyBatis 操作数据库(入门)

文章目录 前言一、什么是MyBatis&#xff1f;二、MyBatis入门2.1、准备工作2.1.1 创建工程2.1.2、数据准备 2.2、配置数据库连接字符串2.3、写持久层代码2.4 单元测试 三、MyBatis的基础操作3.1 打印日志3.2、参数传递3.3、增(Insert)3.4、 删(Delete)3.5、改(Update)3.6、查(S…

蓝桥杯备考:多米诺骨牌

这道题要求上下方格子和之差要最小&#xff0c;其实就是算每个上下格子的差求和的最小值 这道题其实是动态规划01背包问题 我们直接按步骤做吧 step1:定义状态表示f[i][j]表示从1到i个编号的差值里选出刚好j个数的最小操作次数 step2:推导状态转移方程 如图这就是我们的状态…

bluecode-20240913_1_数据解码

时间限制&#xff1a;C/C 1000MS&#xff0c;其他语言 2000MS 内存限制&#xff1a;C/C 256MB&#xff0c;其他语言 512MB 难度&#xff1a;困难 数据解码 指定有一段经过编码的二进制数据&#xff0c;数据由0个或多个"编码单元"组成。"编码单元"的编码方式…

day1_Flink基础

文章目录 Flink基础今日课程内容目标为什么要学Flink技术更新迭代市场需求 流式计算批量计算概念特点 批量计算的优势和弊端流式计算生活中流场景流式计算的概念 Flink简介Flink历史Flink介绍 Flink架构体系已学过的框架技术Flink架构 Flink集群搭建Flink的集群模式Standalone模…

集多功能为一体的软件,支持批量操作。

今天我给大家分享一个超实用的小工具&#xff0c;真的是太好用了&#xff01;这个软件是吾爱大神无知灰灰制作的&#xff0c;它能直接一键把webp格式的图片转换成png格式。 webp转为png 一键操作&#xff0c;支持压缩 其实&#xff0c;作者最近在工作中经常遇到webp格式的图片…

Linux 基本使用和 web 程序部署

目录 Linux 常用命令 ls cd 认识 Linux 目录结构 绝对路径 vs 相对路径 使用 tab 键补全 使用 ctrl c 重新输入 pwd touch cat echo vim 1) 创建文件 / 打开文件 ​编辑 2) 进入插入模式 3) 保存 4) 退出 mkdir rm mv cp man grep ps netstat 搭建 J…

CentOS 7 部署RuoYi 项目

换源 备份现有的 YUM 源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 默认的 CentOS 官方镜像源替换为阿里云的镜像源&#xff0c;以提高下载速度和稳定性。 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.co…

【Kafka】分布式消息队列的核心奥秘

文章目录 一、Kafka 的基石概念​主题&#xff08;Topic&#xff09;​分区&#xff08;Partition&#xff09;​生产者&#xff08;Producer&#xff09;​消费者&#xff08;Consumer&#xff09;​ 二、Kafka 的架构探秘​Broker 集群​副本机制​ 三、Kafka 的卓越特性​高…

linux课程学习二——缓存

一.文件io与标准io的一个区别 遇到死循环可以ctrl c结束进程 使用printf输出&#xff0c;输出没有问题 用wirte输出&#xff0c;参数1&#xff0c;可以理解为上面介绍的linux标准文件描述符的1&#xff08;STDOUT&#xff09;标准输出&#xff0c;我们加上一个死循环while&…

【区块链安全 | 第九篇】基于Heimdall设计的智能合约反编译项目

文章目录 背景目的安装1、安装 Rust2、克隆 heimdall-dec3、编译 heimdall-dec4、运行 heimdall-dec 使用说明1、访问 Web 界面2、输入合约信息3、查看反编译结果 实战演示1、解析普通合约2、解析代理合约 背景 在区块链安全研究中&#xff0c;智能合约的审计和分析至关重要。…

CANoe入门——CANoe的诊断模块,调用CAPL进行uds诊断

目录 一、诊断窗口介绍 二、诊断数据库文件管理 三、添加基础诊断描述文件&#xff08;若没有CDD/ODX/PDX文件&#xff09;并使用对应的诊断功能进行UDS诊断 3.1、添加基础诊断描述文件 3.2、基于基础诊断&#xff0c;使用诊断控制台进行UDS诊断 3.2.1、生成基础诊断 3.…