Unity编辑器扩展(外挂)
每日一句:未来的样子藏在现在的努力里
目录
什么是编译器开发
C#特性[System.Serializable]
特殊目录
命名空间
/*检视器属性控制*/
//添加变量悬浮提示文字
//给数值设定范围(最小0,最大150)
//指定输入框,拥有5行
//默认显示5行,最多显示10行内容,再多用滚动条控制显示区域
//给小齿轮增加一个回调函数
编辑器外挂
弹窗
编辑器扩展案例
什么是编译器开发
对编译器实现功能扩展,一般会使用它开发项目工具,或实现unity插件
C#特性[System.Serializable]
用于在C#运行时,传递程序中各种元素(类,结构体,变量,方法,枚举,组件)的行为信息的声明标签。一个声明标签是通过放置在它所在应用元素的前面的方括号“[]”中来描述
特殊目录
Plugins:需要跨语言调用的代码逻辑代码存储目录,手机SDK接入
Resources:存储跟随游戏包的资源目录
StreamingAssets:只读,存储跟随游戏包的资源目录
编辑器目录:Editor
制作多目录合并
项目中建立的Editor目录,编译器相关的逻辑和资源会放在其内部,相关内容,在打包生成时,不会一起生成到项目中,玩家也不会使用到编译器相关的内容
Editor目录下的脚本,无法挂载在场景对象下
命名空间
Unity代码逻辑命名空间:UnityEngine
Unity编译器命名空间:UnityEditor,此命名空间,不要出现在游戏被发布的逻辑代码中,会导致项目打包失败
/*检视器属性控制*/
如果对象不标记为可序列化,则Unity在存储的时候,会认为它不可被序列化,那么也就无法被显示
[Serializable]
public class Numerical
{
public int Atk;
public int Def;
}
public class Test : MonoBehaviour
{
//监视面板显示对象
public Numerical nul;
}
//一个成员变量可以添加多个特性
//添加变量悬浮提示文字
[Tooltip("不要填写大于150岁的年龄")]
//给数值设定范围(最小0,最大150)
[Range(0,150)]
public int Age;
//指定输入框,拥有5行
[Multiline(5)]
public string NickName;
//默认显示5行,最多显示10行内容,再多用滚动条控制显示区域
[TextArea(5, 10)]
public string Description;
//给小齿轮增加一个回调函数
[ContextMenu("输出攻防比")]
public void PrintAD()
{
Debug.Log("角色攻防比");
}
编辑器外挂
//使生命周期函数,在编辑器状态下可以执行,游戏中也可以正常使用
//Update()在场景中对象发生变化或项目组织发生变化时会执行
[ExecuteInEditMode]
//当前组件依赖于盒子碰撞体
//当前组件挂载在对象时,盒子碰撞体会一起被添加上去
//当Player组件没有被移除时,盒子碰撞体不能被删除
[RequireComponent(typeof(BoxCollider))]
public class Player : MonoBehaviour
{
public int ID;
public GameObject Weapon;
public Texture Cloth;
public PlayerProfression Pro;
public PlayerLoveColor LoveColor;
public List<string> Items;
public float Ack;
}
//单选使用十进制理解,即不同数代表不同选项
public enum PlayerProfression
{
Warrior=0,
Wizard=1,
}
//多选使用二进制理解,即不同位代表不同选项
public enum PlayerLoveColor
{
Green=1,
Red=2,
Pink=4,
}
using UnityEditor;
[CustomEditor(typeof(Player))]
//将编辑器开发脚本与需要编辑的组件脚本建立外挂关联关系
//外挂脚本因为存储在Editor目录下,所以不会被打入最终的游戏包
public class PlayerEditor : Editor
{
Player _Component;
//当关联组件所在对象被选中或被添加时调用
private void OnEnable()
{
_Component = target as Player;
}
//当关联组件所在对象被取消或被移出时调用
private void OnDisable()
{
_Component = null;
}
public override void OnInspectorGUI()
{
//标题显示
EditorGUILayout.LabelField("人物相关属性");
_Component.ID = EditorGUILayout.IntField("玩家ID", _Component.ID);
//.TextField()文本 .FolatField()浮点数 .Toggle()布尔 .Vector3Field()向量
//.ColorField()颜色
//对象数据类型绘制(1.标题 2.原始组件的值 3.成员变量的类型
//4.是否可以将场景中的对象拖给这个成员变量)
_Component.Weapon = EditorGUILayout.ObjectField("持有武器", _Component.Weapon, typeof(GameObject), true) as GameObject;
//纹理
_Component.Cloth= EditorGUILayout.ObjectField("衣服材质贴图", _Component.Weapon, typeof(Texture), false) as Texture;
//枚举数据类型绘制
//整数转枚举
//int id=0;
//PLAYER.PROFESSION P=(PLAYER_PROFESSION)id;
//单选枚举(标题,组件上的原始值)
_Component.Pro = (PlayerProfression)EditorGUILayout.EnumPopup("玩家职业", _Component.Pro);
//多选枚举(标题,组件上的原始值)
_Component.LoveColor= (PlayerLoveColor)EditorGUILayout.EnumFlagsField("玩家喜欢的颜色", _Component.LoveColor);
//终极数据类型绘制
//更新可序列化数据
serializedObject.Update();
//通过成员变量名找到组件上的成员变量
SerializedProperty sp = serializedObject.FindProperty("Items");
//可序列化数据绘制(取到的数据,标题,是否将所有获得的序列化数据显示出俩)
EditorGUILayout.PropertyField(sp, new GUIContent("道具信息"), true);
//将修改的数据,写入到可序列化的原始数据中
serializedObject.ApplyModifiedProperties();
//滑动条绘制
//滑动条显示(1.标题,2.原始变量,最小值,最大值)
_Component.Ack = EditorGUILayout.Slider(new GUIContent("玩家攻击力"), _Component.Ack, 0, 100);
if(_Component.Ack>80)
{
//显示消息框(红色)
EditorGUILayout.HelpBox("攻击力太高了", MessageType.Error);
}
if (_Component.Ack <20)
{
//显示消息框(红色)
EditorGUILayout.HelpBox("攻击力太低了", MessageType.Warning);
}
//按钮显示和元素排列
GUILayout.Button("来个按钮");
GUILayout.Button("来个按钮");
if(GUILayout.Button("测试点击"))
{
Debug.Log("测试点击");
}
//开始横向排列绘制
EditorGUILayout.BeginHorizontal();
GUILayout.Button("再来个按钮");
GUILayout.Button("再来个按钮");
//结束横向排列绘制
EditorGUILayout.EndHorizontal();
}
}
弹窗
using UnityEditor;
using UnityEngine;
public class PopWindw : EditorWindow
{
[MenuItem("工具/创建窗口")]
static void OpenWindow()
{
PopupWindow window = GetWindow<PopupWindow>(false, "弹窗标题", true);
window.minSize = new Vector2(400, 300);
window.maxSize = new Vector2(800, 600);
}
}
编辑器扩展案例
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]//在编辑模式下可以执行一些生命周期函数
public class NodeManager : MonoBehaviour
{
//存储了所有编辑器下点击生成的点,并使用预制体显示
public List<GameObject> nodes;
private void Update()
{
for (int i = 0; i < nodes.Count - 1; i++)
{
Debug.DrawLine(nodes[i].transform.position, nodes[i + 1].transform.position, Color.red, Time.deltaTime);
}
}
}
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(NodeManager))]
public class NodeManagerEditor : Editor
{
NodeManager manager;
bool isEditor = false;
//当选中带有NodeManager组件对象时,获得组件
private void OnEnable()
{
manager = (NodeManager)target;
}
//绘制组件的生命周期函数
public override void OnInspectorGUI()
{
serializedObject.Update();
SerializedProperty nodes = serializedObject.FindProperty("nodes");
//Debug.Log("nodes" + nodes);
EditorGUILayout.PropertyField(nodes, new GUIContent("路径"), true);
serializedObject.ApplyModifiedProperties();
//返回 bool 如果向 SerializedObject 应用了任何待处理的属性更改,则返回 true。
if (!isEditor && GUILayout.Button("开始编辑"))
{
NodeWindow.OpenWindow(manager.gameObject);
//调用打开界面方式
isEditor = true;
}
else if (isEditor && GUILayout.Button("结束编辑"))
{
NodeWindow.CloseWindow();
isEditor = false;
}
if (GUILayout.Button("删除最后一个节点"))
{
RemoveAtLast();
}
else if (GUILayout.Button("删除所有节点"))
{
RemoveAll();
}
}
RaycastHit hit;
//当选中关联的脚本挂载的物体
//当鼠标在Scene视图下发生时,执行该方法,如鼠标移动
private void OnSceneGUI()
{
if (!isEditor)//非编辑器下不能生成路点
{
return;
}
//当鼠标按下左键时发射一条射线
//非运行时,使用Event类
if (Event.current.button == 0 && Event.current.type == EventType.MouseDown)
{
//从鼠标的位置需要发射射线了
//因为是从Scene视图下发射射线,跟场景中的摄像机并没有关系,所以不能使用相机发射射线的方式
//从编辑器GUI中的一个点向世界定义一条射线,参数一般都是鼠标的坐标
Debug.Log("aaa");
//将 2D GUI 位置转换为世界空间射线HandleUtility.GUIPointToWorldRay
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
Debug.Log(ray);
//Debug.DrawLine(Event.current.mousePosition, Color.red);
Debug.Log(Physics.Raycast(ray, out hit, 1000));
if (Physics.Raycast(ray, out hit, 1000))
{
Debug.Log("bbb");
//需要在检测到的点实例化路点
InstancePathNode(hit.point + Vector3.up * 0.1f);
}
}
}
//生成节点
void InstancePathNode(Vector3 position)
{
GameObject prefab = Resources.Load<GameObject>("PathNode");
Debug.Log(prefab);
GameObject pathNode = Instantiate<GameObject>(prefab, position, Quaternion.identity, manager.transform);
manager.nodes.Add(pathNode);//把生成的路点添加到列表里
}
//删除最后一个节点
void RemoveAtLast()
{
//保证有节点才能删节点
if (manager.nodes.Count > 0)
{
//从场景中删除游戏物体
DestroyImmediate(manager.nodes[manager.nodes.Count - 1]);
//把该节点从列表中移除
manager.nodes.RemoveAt(manager.nodes.Count - 1);
}
}
//删除所有的节点
void RemoveAll()
{
//遍历删除所有的节点物体
for (int i = 0; i < manager.nodes.Count; i++)
{
if (manager.nodes[i] != null)
{
DestroyImmediate(manager.nodes[i]);
}
manager.nodes.Clear();
}
}
}
public class NodeWindow : EditorWindow
{
static NodeWindow window;
static GameObject nodeManager;
public static void OpenWindow(GameObject manager)
{
nodeManager = manager;
//真正开启了一个窗口
window = EditorWindow.GetWindow<NodeWindow>();
}
private void Update()
{
Selection.activeGameObject = nodeManager;
}
public static void CloseWindow()
{
window.Close();
}
}
链接:https://pan.baidu.com/s/1Kr2vYQKIoA897YY-l3j8kg?pwd=acap
提取码:acap
相关文章:

Unity编辑器扩展(外挂)
每日一句:未来的样子藏在现在的努力里 目录 什么是编译器开发 C#特性[System.Serializable] 特殊目录 命名空间 /*检视器属性控制*/ //添加变量悬浮提示文字 //给数值设定范围(最小0,最大150) //指定输入框,拥有5行 //默认…...

oracle 19c容器数据库data dump数据泵传输数据(2)---11g导19c
目录 1.在11gnon-cdb数据库中创建测试用户 2.在19cCDB容器数据库中新建pdb2 3.执行命令导出 4.执行命令导入 Exporting from a Non-CDB and Importing into a PDB 我們要記住一点:如果是全库导出导入的话,目标数据库没有的表空间我们要事先创建&#…...

Java-网络爬虫(二)
文章目录 前言一、WebMagic二、使用步骤1. 搭建 Maven 项目2. 引入依赖 三、入门案例四、核心对象&组件1. 核心对象SipderRequestSitePageResultItemsHtml(Selectable) 2. 四大组件DownloaderPageProcessorSchedulerPipeline 上篇:Java-网…...

【android】rk3588-android-bt
文章目录 蓝牙框架HCI接口蓝牙VENDORLIBvendorlib是什么 代码层面解读vendorlib1、 vendorlib实现,协议栈调用2、协议栈实现,vendorlib调用(回调函数)2.1、 init函数2.2、BT_VND_OP_POWER_CTRL对应处理2.3、BT_VND_OP_USERIAL_OPE…...

如何在 Microsoft Edge 浏览器中启用自动刷新
你是否经常发现自己在使用 Microsoft Edge 时点击刷新按钮?如果您需要一个网页以设定的时间间隔自动更新,那么请接着往下看。 在这篇博文中,我们探讨如何在 Microsoft Edge 浏览器中启用和管理自动刷新功能。 为什么选择自动刷新࿱…...

Redis之集群方案比较
哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般&a…...

WPF 布局
了解 WPF中所有布局如下,我们一一尝试实现,本文档主要以图形化的形式展示每个布局的功能。 布局: Border、 BulletDecorator、 Canvas、 DockPanel、 Expander、 Grid、 GridView、 GridSplitter、 GroupBox、 Panel、 ResizeGrip、 Separat…...
#Uniapp:uni-app中vue2生命周期--11个
uni-app中vue2生命周期 生命周期钩子描述H5App端小程序说明beforeCreate在实例初始化之后被调用 详情√√√created在实例创建完成后被立即调用 详情√√√beforeMount在挂载开始之前被调用 详情√√√mounted挂载到实例上去之后调用 详情 注意:此处并不能确定子组…...
pytorch 分布式 Node/Worker/Rank等基础概念
分布式训练相关基本参数的概念如下: Definitions Node - A physical instance or a container; maps to the unit that the job manager works with. Worker - A worker in the context of distributed training. WorkerGroup - The set of workers that execute the same f…...

《动手学深度学习》学习笔记 第8章 循环神经网络
本系列为《动手学深度学习》学习笔记 书籍链接:动手学深度学习 笔记是从第四章开始,前面三章为基础知识,有需要的可以自己去看看 关于本系列笔记: 书里为了让读者更好的理解,有大篇幅的描述性的文字,内容很…...

腾讯实验平台基于 StarRocks 构建湖仓底座
作者: 腾讯大数据平台部科学实验中心Tech Lead、专家工程师 马金勇博士 腾讯大数据平台部科学实验中心数据负责人、专家工程师 胡明杰 StarRocks Contributor、腾讯高级工程师 刘志行 在 2022 年,腾讯 A/B Test 团队启动了海外商业化版本 ABetterChoice …...

【基础工具篇使用】ADB 的安装和使用
文章目录 ADB的命令安装ADB 命令使用查看帮助 ——adb help查看连接设备 ADB的命令安装 ADB 命令的全称为“Android Debug Bridge”,从英文中看出主要是用作安卓的调试工具。ADB 命令在嵌入式开发中越来越常用了 在 Windows 上按“win”“R”组合件打开运行, 输入 …...

数字图像处理练习题
数字图像处理练习题 文章目录 数字图像处理练习题第 一 章1.什么是数字图像?2.数字图像有哪些特点?3.数字图像处理的目的是什么?4.简述数字图像的历史。5.数字图像有哪些主要应用?6.列举生活中数字图像的获得途径。7.结合自己的生活实例,举出一个数字图像的应用实例8.数字图…...

开关电源PFC电路原理详解及matlab仿真
PFC全称“Power Factor Correction”,意为“功率因数校正”。PFC电路即能对功率因数进行校正,或者说能提高功率因数的电路。是开关电源中很常见的电路。 在电学中,功率因数PF指有功功率P(单位w)与视在功率S(…...

SpringBoot+Hutool实现图片验证码
图片验证码在注册、登录、交易、交互等各类场景中都发挥着巨大作用,能够防止操作者利用机器进行暴力破解、恶意注册、滥用服务、批量化操作和自动发布等行为。 创建一个实体类封装,给前端返回的验证码数据: Data public class ValidateCodeV…...
【MySQL】MySQL版本8+ 窗口函数 Lead 的两种使用
力扣题 1、题目地址 1709. 访问日期之间最大的空档期 2、模拟表 表:UserVisits Column NameTypeuser_idintvisit_datedate 该表没有主键,它可能有重复的行该表包含用户访问某特定零售商的日期日志。 3、要求 假设今天的日期是 ‘2021-1-1’ 。 …...

Hive 的 安装与使用
目录 1 安装 MySql2 安装 Hive3 Hive 元数据配置到 MySql4 启动 Hive5 Hive 常用交互命令6 Hive 常见属性配置 Hive 官网 1 安装 MySql 为什么需要安装 MySql? 原因在于Hive 默认使用的元数据库为 derby,开启 Hive 之后就会占用元数据库,且不与其他客户…...

Zynq 电源
ZYNQ芯片的电源分PS系统部分和PL逻辑部分,两部分的电源分别是独立工作。PS系统部分的电源和PL逻辑部分的电源都有上电顺序,不正常的上电顺序可能会导致ARM系统和FPGA系统无法正常工作。 PS部分的电源有VCCPINT、VCCPAUX、VCCPLL和PS VCCO。 VCCPINT为PS内…...
DevOps系列之 Python操作数据库
pymysql操作mysql数据库 安装pymysql pip install pymysql pymysql操作数据库 1.连接数据库 使用Connect方法连接数据库 pymysql.Connections.Connection(hostNone, userNone, password, databaseNone, port0, charset) 参数说明: host – 数据库服务器所在的主机…...

【AI视野·今日NLP 自然语言处理论文速览 第七十四期】Wed, 10 Jan 2024
AI视野今日CS.NLP 自然语言处理论文速览 Wed, 10 Jan 2024 Totally 38 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Model Editing Can Hurt General Abilities of Large Language Models Authors Jia Chen Gu, Hao Xiang Xu, J…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...