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

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] 特殊目录 命名空间 /*检视器属性控制*/ //添加变量悬浮提示文字 //给数值设定范围&#xff08;最小0&#xff0c;最大150&#xff09; //指定输入框&#xff0c;拥有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 我們要記住一点&#xff1a;如果是全库导出导入的话&#xff0c;目标数据库没有的表空间我们要事先创建&#…...

Java-网络爬虫(二)

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

【android】rk3588-android-bt

文章目录 蓝牙框架HCI接口蓝牙VENDORLIBvendorlib是什么 代码层面解读vendorlib1、 vendorlib实现&#xff0c;协议栈调用2、协议栈实现&#xff0c;vendorlib调用&#xff08;回调函数&#xff09;2.1、 init函数2.2、BT_VND_OP_POWER_CTRL对应处理2.3、BT_VND_OP_USERIAL_OPE…...

如何在 Microsoft Edge 浏览器中启用自动刷新

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

Redis之集群方案比较

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

WPF 布局

了解 WPF中所有布局如下&#xff0c;我们一一尝试实现&#xff0c;本文档主要以图形化的形式展示每个布局的功能。 布局&#xff1a; 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挂载到实例上去之后调用 详情 注意&#xff1a;此处并不能确定子组…...

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章 循环神经网络

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

腾讯实验平台基于 StarRocks 构建湖仓底座

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

【基础工具篇使用】ADB 的安装和使用

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

数字图像处理练习题

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

开关电源PFC电路原理详解及matlab仿真

PFC全称“Power Factor Correction”&#xff0c;意为“功率因数校正”。PFC电路即能对功率因数进行校正&#xff0c;或者说能提高功率因数的电路。是开关电源中很常见的电路。 在电学中&#xff0c;功率因数PF指有功功率P&#xff08;单位w&#xff09;与视在功率S&#xff08…...

SpringBoot+Hutool实现图片验证码

图片验证码在注册、登录、交易、交互等各类场景中都发挥着巨大作用&#xff0c;能够防止操作者利用机器进行暴力破解、恶意注册、滥用服务、批量化操作和自动发布等行为。 创建一个实体类封装&#xff0c;给前端返回的验证码数据&#xff1a; Data public class ValidateCodeV…...

【MySQL】MySQL版本8+ 窗口函数 Lead 的两种使用

力扣题 1、题目地址 1709. 访问日期之间最大的空档期 2、模拟表 表&#xff1a;UserVisits Column NameTypeuser_idintvisit_datedate 该表没有主键&#xff0c;它可能有重复的行该表包含用户访问某特定零售商的日期日志。 3、要求 假设今天的日期是 ‘2021-1-1’ 。 …...

Hive 的 安装与使用

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

Zynq 电源

ZYNQ芯片的电源分PS系统部分和PL逻辑部分&#xff0c;两部分的电源分别是独立工作。PS系统部分的电源和PL逻辑部分的电源都有上电顺序&#xff0c;不正常的上电顺序可能会导致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) 参数说明&#xff1a; host – 数据库服务器所在的主机…...

【AI视野·今日NLP 自然语言处理论文速览 第七十四期】Wed, 10 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 10 Jan 2024 Totally 38 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Model Editing Can Hurt General Abilities of Large Language Models Authors Jia Chen Gu, Hao Xiang Xu, J…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

命令行关闭Windows防火墙

命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)​方法二:CMD命令…...

leetcode73-矩阵置零

leetcode 73 思路 记录 0 元素的位置&#xff1a;遍历整个矩阵&#xff0c;找出所有值为 0 的元素&#xff0c;并将它们的坐标记录在数组zeroPosition中置零操作&#xff1a;遍历记录的所有 0 元素位置&#xff0c;将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...