当前位置: 首页 > news >正文

在Unity编辑模式下运行Mono中的方法

[ExecuteAlways]

最简单的方法当然是直接给Mono加上[ExecuteAlways]修饰,这样Mono中的Awake,Update等等都可以在编辑模式下按照原本的时机运行。

[ExecuteAlways]
public class TestScript : MonoBehaviour {void TestMethod(){Debug.Log("TestMethod");}void Update(){TestMethod();}
}

OnValidate

除了ExecuteAlways以外,还可以用OnValidate,OnValidate 方法会在脚本中的变量发生更改时自动调用,适用于与 Inspector 参数联动的逻辑。

public class TestScript : MonoBehaviour {public float value;private void OnValidate(){// 在编辑器中参数变更时自动调用Debug.Log($"Value changed to: {value}");}
}

OnDrawGizmos+SceneView.RepaintAll()

有的时候如果想让某段代码能在编辑模式下像Update一样一直运行,但又不想用[ExecuteAlways]或者觉得没必要,就可以用这个方法,需要在SceneView里打开Gizmos的开关

public class TestScript : MonoBehaviour {void TestMethod(){Debug.Log("TestMethod");}//force update on editormodevoid OnDrawGizmos() {if (!Application.isPlaying) {//call you methodTestMethod();}//force Repaintif (!Application.isPlaying) {UnityEditor.EditorApplication.QueuePlayerLoopUpdate();UnityEditor.SceneView.RepaintAll();}}
}

扩展

一般来说上面提到的几个算是够用了,但我在使用OnDrawGizmos方法的时候,依旧觉得太麻烦,就没有什么更方便的方法吗,于是我想到了C#的Attribute,如果可以像[ExecuteAlways]那样简单的标记一个方法,让这方法可以不断的被调用,那写起来不就方便多了吗,于是

EditorUpdateMethodManager

//==============================================================================
// Filename:     EditorUpdateMethodManager
// Description:  
//               
// Version:      1.0
// Compiler:     2022.3.40f1 (cbdda657d2f0)
// Author:       Akota
// CreateTime:   2024-12-02 10:14:40
//==============================================================================
using System;
using UnityEngine;
#if UNITY_EDITOR
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
#endif[ExecuteAlways]
public class EditorUpdateMethodManager : MonoBehaviour {private void Awake() {if (Application.isPlaying) {Destroy(gameObject);}}
#if UNITY_EDITORprivate  List<RegisteredMethod> RegisteredMethods = new List<RegisteredMethod>();private void OnEnable() {if (!Application.isPlaying) { RegisterMethodsFromScene();EditorApplication.hierarchyChanged += RegisterMethodsFromScene; // 监听层级变化}}private void OnDisable() {if (!Application.isPlaying) { EditorApplication.hierarchyChanged -= RegisterMethodsFromScene; // 移除监听}}private void Update() {if (!Application.isPlaying) { foreach (var registeredMethod in RegisteredMethods) {// 仅调用激活的 MonoBehaviour 实例上的方法if (registeredMethod.MonoInstance != null &&registeredMethod.MonoInstance.enabled &&registeredMethod.MonoInstance.gameObject.activeInHierarchy) {registeredMethod.Method.Invoke(registeredMethod.MonoInstance, null);}}}}/// <summary>/// 注册当前场景中的所有标记方法/// </summary>public void RegisterMethodsFromScene() {RegisteredMethods.Clear();// 获取当前场景中所有 MonoBehaviourvar monoBehaviours = FindObjectsOfType<MonoBehaviour>(true); // 包括未激活的对象foreach (var mono in monoBehaviours) {// 查找带有 RegisterEditorUpdateMethodAttribute 的方法var methods = mono.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(m => m.GetCustomAttribute<EditorUpdateMethodAttribute>() != null);foreach (var method in methods) {// 记录方法和实例RegisteredMethods.Add(new RegisteredMethod(mono, method));}}}/// <summary>/// 注册方法信息/// </summary>private class RegisteredMethod {public MonoBehaviour MonoInstance { get; }public MethodInfo Method { get; }public RegisteredMethod(MonoBehaviour monoInstance, MethodInfo method) {MonoInstance = monoInstance;Method = method;}}
#endif
}/// <summary>
/// 标记可以被 EditorUpdateMethodManager 调用的方法
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class EditorUpdateMethodAttribute : Attribute {
}

原理也很简单,就是利用[ExecuteAlways]来标记EditorUpdateMethodManager,然后在EditorUpdateMethodManager里面查找当前场景下的所有Mono里被EditorUpdateMethod标记的方法,并在Manager的Update中统一调用。

示例

public class TestScript : MonoBehaviour {[EditorUpdateMethod]void TestMethod(){Debug.Log("TestMethod");}
}

要是手动在场景里创建一个Manager还是嫌麻烦的话

EditorUpdateManagerInitializer

//==============================================================================
// Filename:     EditorUpdateManagerInitializer
// Description:  
//               
// Version:      1.0
// Compiler:     2022.3.40f1 (cbdda657d2f0)
// Author:       Akota
// CreateTime:   2024-12-02 10:16:02
//==============================================================================
#if UNITY_EDITOR
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;[InitializeOnLoad]
public static class EditorUpdateManagerInitializer {static EditorUpdateManagerInitializer() {// 监听层级变化EditorApplication.hierarchyChanged += EnsureEditorUpdateMethodManagerExists;EnsureEditorUpdateMethodManagerExists(); // 初次调用}/// <summary>/// 检查场景中是否存在标记方法,并确保 EditorUpdateMethodManager 存在/// </summary>private static void EnsureEditorUpdateMethodManagerExists() {// 检查场景中是否存在 EditorUpdateMethodManagervar existingManager = GameObject.FindObjectOfType<EditorUpdateMethodManager>();if (existingManager == null) { if (HasRegisterEditorUpdateMethodsInScene()) {// 没有 EditorUpdateMethodManager,创建一个var managerObject = new GameObject("EditorUpdateMethodManager");managerObject.AddComponent<EditorUpdateMethodManager>();// 标记场景为脏Undo.RegisterCreatedObjectUndo(managerObject, "Create EditorUpdateMethodManager");EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());Debug.Log("[EditorUpdateManagerInitializer] 自动创建了 EditorUpdateMethodManager");}}else {// 如果不需要且已有 Manager,则移除//Debug.Log("[EditorUpdateManagerInitializer] 场景中没有标记方法,移除了 EditorUpdateMethodManager");//Undo.DestroyObjectImmediate(existingManager.gameObject);//EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());}}/// <summary>/// 检查场景中是否有被 RegisterEditorUpdateMethodAttribute 标记的方法/// </summary>private static bool HasRegisterEditorUpdateMethodsInScene() {// 获取当前场景中所有 MonoBehaviourvar monoBehaviours = GameObject.FindObjectsOfType<MonoBehaviour>(true); // 包括未激活的对象foreach (var mono in monoBehaviours) {// 检查该 MonoBehaviour 类型是否有标记的方法var methods = mono.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(m => m.GetCustomAttribute<EditorUpdateMethodAttribute>() != null);if (methods.Any()) {return true;}}return false;}
}
#endif

这段代码会自动检测场景中是否有被EditorUpdateMethod修饰的方法,有的话就自动创建Manager

更新

考虑到要在场景里创建物体,可能显得有点累赘,于是新版放弃[ExecuteAlways],改为利用EditorApplication.update来实现,更精简了

//==============================================================================
// Filename:     EditorUpdateMethodManager
// Description:  
//               
// Version:      1.0
// Compiler:     2022.3.40f1 (cbdda657d2f0)
// Author:       Akota
// CreateTime:   2024-12-02 14:13:12
//==============================================================================
#if UNITY_EDITOR
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;public class EditorUpdateMethodManager{public static EditorUpdateMethodManager instance = null;[InitializeOnLoadMethod]public static void Init() {instance = new EditorUpdateMethodManager();}public EditorUpdateMethodManager() {if (!Application.isPlaying) {RegisterMethodsFromScene();}EditorApplication.hierarchyChanged += RegisterMethodsFromScene; // 监听层级变化EditorApplication.update += Update;}private List<RegisteredMethod> RegisteredMethods = new List<RegisteredMethod>();void Update() {if (!Application.isPlaying) {foreach (var registeredMethod in RegisteredMethods) {// 仅调用激活的 MonoBehaviour 实例上的方法if (registeredMethod.MonoInstance != null &&registeredMethod.MonoInstance.enabled &&registeredMethod.MonoInstance.gameObject.activeInHierarchy) {registeredMethod.Method.Invoke(registeredMethod.MonoInstance, null);}}}}/// <summary>/// 注册当前场景中的所有标记方法/// </summary>public void RegisterMethodsFromScene() {RegisteredMethods.Clear();// 获取当前场景中所有 MonoBehaviourvar monoBehaviours = Object.FindObjectsOfType<MonoBehaviour>(true); // 包括未激活的对象foreach (var mono in monoBehaviours) {// 查找带有 RegisterEditorUpdateMethodAttribute 的方法var methods = mono.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(m => m.GetCustomAttribute<EditorUpdateMethodAttribute>() != null);foreach (var method in methods) {// 记录方法和实例RegisteredMethods.Add(new RegisteredMethod(mono, method));}}}/// <summary>/// 注册方法信息/// </summary>private class RegisteredMethod {public MonoBehaviour MonoInstance { get; }public MethodInfo Method { get; }public RegisteredMethod(MonoBehaviour monoInstance, MethodInfo method) {MonoInstance = monoInstance;Method = method;}}
}
#endif
/// <summary>
/// 标记可以被 EditorUpdateMethodManager 调用的方法
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Method)]
public class EditorUpdateMethodAttribute : System.Attribute {
}

其他

还有其他的一些,比如编写CustomEditor,在Editor中一直调用方法,又或者用Editor画个按钮,通过在Inspector上手动点击来调用代码,当然也可以用Odin插件,直接用Button修饰Mono中的方法,就会在Inspector上出现按钮了。

结语

代码写的很随便也很丑陋,望包涵

相关文章:

在Unity编辑模式下运行Mono中的方法

[ExecuteAlways] 最简单的方法当然是直接给Mono加上[ExecuteAlways]修饰&#xff0c;这样Mono中的Awake&#xff0c;Update等等都可以在编辑模式下按照原本的时机运行。 [ExecuteAlways] public class TestScript : MonoBehaviour {void TestMethod(){Debug.Log("TestMe…...

Y20030028 JAVA+SSM+MYSQL+LW+基于JAVA的考研监督互助系统的设计与实现 源代码 配置 文档

基于JAVA的考研监督互助系统 1.项目描述2. 课题开发背景及意义3.项目功能4.界面展示5.源码获取 1.项目描述 随着高等教育的普及和就业竞争的加剧&#xff0c;越来越多的学生选择继续深造&#xff0c;参加研究生入学考试。考研人数的不断增加&#xff0c;使得考研过程中的学习监…...

MATLAB期末复习笔记(下)

目录 五、数据和函数的可视化 1.MATLAB的可视化对象 2.二维图形的绘制 3.图形标识 4.多子图绘图 5.直方图的绘制 &#xff08;1&#xff09;分类 &#xff08;2&#xff09;垂直累计式 &#xff08;3&#xff09;垂直分组式 &#xff08;4&#xff09;水平分组式 &…...

「Mac畅玩鸿蒙与硬件37」UI互动应用篇14 - 随机颜色变化器

本篇将带你实现一个随机颜色变化器应用。用户点击“随机颜色”按钮后&#xff0c;界面背景会随机变化为淡色系颜色&#xff0c;同时显示当前的颜色代码&#xff0c;页面还会展示一只猫咪图片作为装饰&#xff0c;提升趣味性。 关键词 UI互动应用随机颜色生成状态管理用户交互…...

MySql:理解数据库

目录 一、什么是数据库 第一层理解 第二层理解 第三层理解 二、Linux下的数据库 三、基本认识 登录数据库时&#xff0c; mysql -u root -h 127.0.0.1 -P 3306 -p -h指定MySql服务器所在主机&#xff0c;若在本地则为回环地址。-P表示目标主机上MySql服务端口号 一般简单…...

学习笔记051——SpringBoot学习2

文章目录 Spring Boot 原理1、SpringBootConfiguration2、ConfigurationProperties3、ComponentScan4、EnableAutoConfiguration Spring Boot 原理 Spring Boot 可以自动读取配置文件&#xff0c;将项目所需要的组件全部自动加载到 IoC 容器中&#xff0c;包括两部分 开发者自…...

crush rule 20 type does not match pool

问题 kubectl describe CephObjectStore ceph-objectstoreEvents:Type Reason Age From Message---- ------ ---- ---- -------Warning ReconcileFailed 14m …...

BA是什么?

目录 1.EKF的步骤 一、问题定义与模型建立 二、线性化处理 三、应用卡尔曼滤波 四、迭代与收敛 五、结果评估与优化 注意事项 2.BA问题的步骤 一、问题定义与数据准备 二、构建优化模型 三、选择优化算法 四、执行优化过程 五、结果评估与优化 六、应用与验证 1.…...

通过docker 搭建jenkins环境;

一、官网简介使用安装说明: How to use this image docker run -p 8080:8080 -p 50000:50000 jenkins This will store the workspace in /var/jenkins_home. All Jenkins data lives in there - including plugins and configuration. You will probably want to make that …...

10-高级主题

第10节 高级主题 在这一节中&#xff0c;我们将探讨一些 Python 中的高级主题&#xff0c;包括装饰器、生成器、上下文管理器、元类以及常用的设计模式。这些高级特性能够帮助你编写更强大、更灵活的代码。 10.1 装饰器 装饰器是一种特殊类型的函数&#xff0c;可以修改其他函数…...

harbor常见问题及解决方法分享

harbor常见问题及解决方法分享 参考自《harbor权威指南》。 1. harbor配置文件不生效 问题现象 无论是在生产环境下还是在测试环境下&#xff0c;都会有对配置文件进行修改的场景。很多用户在停掉Harbor容器后&#xff0c;都会修改配置文件然后启动Harbor&#xff0c;发现配…...

行列式与线性方程组解的关系

线性方程组是数学中一个重要的概念&#xff0c;它描述了多个变量之间的线性关系。行列式作为方阵的一个特殊值&#xff0c;对于判断线性方程组解的存在性和唯一性有着重要的作用。本文将探讨行列式与线性方程组解之间的关系&#xff0c;并区分齐次和非齐次方程组的情况。 齐次…...

四、自然语言处理_02RNN基础知识笔记

1、RNN的定义 RNN&#xff08;Recurrent Neural Network&#xff0c;循环神经网络&#xff09;是一种专门用于处理序列数据的神经网络架构&#xff0c;它与传统的前馈神经网络&#xff08;Feedforward Neural Network&#xff09;不同&#xff0c;主要区别在于它能够处理输入数…...

Spring 容器管理 Bean

Bean是什么 Bean 是指 Java 中的可重用软件组件,容器会根据提供的元数据来创建和管理这些 Bean,也包括它们之间的依赖关系。Spring 容器对 Bean 并没有太多的要求,无须实现特定接口或依赖特定库,只要是最普通的 Java 对象即可,这类对象也被称为 POJO(Plain Old Java Obj…...

SpringBoot开发——Spring Boot3.4 强大的结构化日志记录

文章目录 1. 简介2. 实战案例2.1 环境依赖2.2 快速入门2.3 输出到文件2.4 添加附加字段2.5 自定义日志格式总结1. 简介 日志记录是应用故障排除中早已确立的部分,也是可观测性的三大支柱之一,另外两个是指标和追踪。在生产环境中,没有人喜欢盲目行事,而当故障发生时,开发…...

信号和槽思维脑图+相关练习

将登录框中的取消按钮使用信号和槽的机制&#xff0c;关闭界面。 将登录按钮使用信号和槽连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是否为"123456",如果账号密码匹配成功&#xff0c;当前界面关…...

Unity Feel插件快速入门

What is Feel? Feel是一个即用型解决方案&#xff0c;让你的Unity项目提高游戏体验&#xff0c;增强玩家获得的反馈感,例如相机震动,屏幕闪烁,淡入淡出,等等几十种效果。这是一个模块化、用户友好、易于扩展的系统。 本文旨在让你快速入门,从全局快速了解这个插件,以及基本用…...

数据链路层(四)---PPP协议的工作状态

1 PPP链路的初始化 通过前面几章的学习&#xff0c;我们学了了PPP协议帧的格式以及组成&#xff0c;那么对于使用PPP协议的链路是怎么初始化的呢&#xff1f; 当用户拨号上网接入到ISP后&#xff0c;就建立起了一条个人用户到ISP的物理链路。这时&#xff0c;用户向ISP发送一…...

【C++】入门【六】

本节目标 一、继承的概念及定义 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员 七、复杂的菱形继承及菱形虚拟继承 八、继承的总结和反思 九、笔试面试题 一、继承的概念及定义 1.继承的概念 继承是面向对象…...

UE5 C++ 不规则按钮识别,复选框不规则识别 UPIrregularWidgets

插件名称&#xff1a;UPIrregularWidgets 插件包含以下功能 你可以点击任何图片&#xff0c;而不仅限于矩形图片。 UPButton、UPCheckbox 基于原始的 Button、Checkbox 扩展。 复选框增加了不规则图像识别功能&#xff0c;复选框增加了悬停事件。 欢迎来到我的博客 记录学习过…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...