Unity3D插件开发教程(二):制作批处理工具

Unity3D插件开发教程(二):制作批处理工具

文章来源:Unity3D插件开发教程(二):制作批处理工具 - 知乎 (zhihu.com)

声明:
  • 题图来自于Gratisography | Free High Resolution Pictures
  • 欢迎分享本文
  • 本文未经允许不能以任何形式转载。

俗语说:工欲善其事,必先利其器。

一个好的工具能让你的工作进度加快不少。

在制作关卡时,很多时候会遇到同一个物体可能需要复制多份,然后分布在不同地方。如果 一个个复制太浪费时间了,而美术和策划又不会使用代码批量复制。这时候,就需要做一个批量工具来加快制作的效率了。

首先来看一下我们今天要做的批量工具面板,并且可以根据输入的变量,批量的变更每个的位移,旋转和缩放:

知识要点:

  • EditorWindow
  • GUI/GUILayout/EditorGUI/EditorGUILayout
  • Selection
  • Undo

使用版本:

  • Unity3D 5.3.3

目标:

  • 学习创建EditorWindow面板,然后使用GUI等工具绘制面板,最后批量复制对象。

整个插件的结构:

和上一篇教程一样,在Editor目录下创建我们的批处理面板脚本————BatchingLiteWindow.cs,然后继承EditorWindow

EditorWindow是所有编辑器面板的基类,绘制面板必须要继承它。

然后我们使用MenuItem和静态函数添加启动面板的菜单。

MenuItem的使用方法请看 上一篇教程的最后部分。
public class BatchingLiteWindow : EditorWindow
{
    [MenuItem("Tools/BatchingLite")]
    public static void ShowWindow()
    {
        //GetWindow函数的意思是创建一个面板
        //类型为BatchingLiteWindow
        //第一个参数是面板的标题
        EditorWindow.GetWindow<BatchingLiteWindow>("Batcking");
    }
}

然后我们定义几个变量,用于后面使用。

/// <summary>
/// 位移增量
/// </summary>
private Vector3 _position;

/// <summary>
/// 旋转增量
/// </summary>
private Vector3 _rotation;

/// <summary>
/// 缩放增量
/// </summary>
private Vector3 _scale;

/// <summary>
/// 复制的数量
/// </summary>
private int _number;

好了,接下来,就是本文的重点之一,绘制面板了。 首先,我们定义一个函数叫OnGUI,返回值为void。

说到OnGUI,用过老版本Unity引擎的朋友应该很清楚了。这是一套Unity最早的UI引擎。这套UI系统有别于现在流行的 UGUINGUI,是一套 imGUI(Immediate Mode GUI)。如果需要深入展开imGUI的原理来讲,那么可能需要好几个篇章,所以在此只讲一下怎么使用。 如果有兴趣的朋友可以上网搜索资料,或者到看这个回答  如何用 C++ 从零编写 GUI? - 回答作者: 文刀秋二
首先,绘制面板,一定要使用这套GUI,并且需要在特定函数内使用,例如 OnGUIOnSceneGUIOnInspectorGUIOnHeaderGUIOnPreviewGUI等。 其次,imGUI其中一个特性是不保存状态的,例如 UGUINGUI的按钮类都会保存按钮当前是按下状态还是松开状态,可 imGUI的按钮是不保存这个的。
imGUI有四个绘制类。分别是 GUIGUILayoutEditorGUIEditorGUILayout,他们有相同的地方和不同的地方。
  • GUI:多用与应用/游戏内绘制UI。(编辑器绘制也可使用)
  • GUILayout:GUI的功能上增加了布局的功能。
  • EditorGUI:用于编辑器内绘制UI。(仅限于编辑器内使用)
  • EditorGUILayout:EditorGUI的功能上增加了布局的功能。

好了,接下就开始写绘制面板的逻辑了。

void OnGUI()
{
    //使用Vector3Field方法绘制Vector3的输入框,第一个为输入框的标签(显示的名字),第二个参数需要传入需要显示的Vector3值。
    //返回值为一个Vector3,当没有修改的时候,这个值为原来的值,当有修改的时候,这个返回值就是修改后的值。
    //例如,把返回值赋予给_position,这样,输入框有修改的时候,_position能够拿到最新的值。
    _position = EditorGUILayout.Vector3Field("Position", _position);

    _rotation = EditorGUILayout.Vector3Field("Rotation", _rotation);

    _scale = EditorGUILayout.Vector3Field("Scale", _scale);

    //Space的作用是空一行
    EditorGUILayout.Space();

    //然后使用IntField方法绘制一个int类型的输入框,使用与Vector3相似
    //由于复制的数量不能为负数,所以我们要限制一下修改后的数值
    _number = Mathf.Max(EditorGUILayout.IntField("Number", _number), 0);

    EditorGUILayout.Space();

    //BeginHorizontal方法和EndHorizontal是成对存在的,然后他们的作用是水平布局,在两个函数内绘制的UI会限制在一个水平位置。
    //相似的方法还有BeginVertical和EndVertical,是垂直布局。
    EditorGUILayout.BeginHorizontal();

    //绘制一个Generate Button,这里使用GUILayout而不使用EditorGUILayout是因为EditorGUILayout没有Button(不知道原因)。
    //Button方法第一个参数是button显示的label。
    //返回值为Button是否为点击,
    if (GUILayout.Button("Generate"))
    {
        Generate();
    }

    //这里缓存Cancel按钮的状态,在EndHorizontal之后再调用Cancel方法。
    bool isCancel = GUILayout.Button("Cancel");

    EditorGUILayout.EndHorizontal();

    if (isCancel)
    {
        Cancel();
    }
}

绘制完面板,然后就开始写复制部分的逻辑

/// <summary>
/// 生成复制对象
/// </summary>
private void Generate()
{
    //上一篇有介绍过Selection.activeGameObject是选中的对象,然后Selection.gameObjects是多选时,所有选中的对象。
    //因为有可能是多个对象同时复制,所以使用选中对象组
    GameObject[] selectGameObjects = Selection.gameObjects;

    int len = selectGameObjects.Length;

    for (int i = 0; i < len; i++)
    {
        GameObject selectGameObject = selectGameObjects[i];

        for (int j = 0; j < _number; j++)
        {
            //根据选中对象,实例化对象,然后根据索引和增量,设置移动、旋转、缩放
            GameObject gameObject = GameObject.Instantiate<GameObject>(selectGameObject);

            gameObject.transform.SetParent(selectGameObject.transform.parent);

            gameObject.transform.localPosition = selectGameObject.transform.localPosition + _position * j;

            gameObject.transform.localRotation = selectGameObject.transform.localRotation * Quaternion.Euler(_rotation * j);

            gameObject.transform.localScale = selectGameObject.transform.localScale + _scale * j;

            gameObject.name = selectGameObject.name;

            //Undo是Unity3d用于设置步骤,执行/撤销等
            //RegisterCreatedObjectUndo是注册一个新创建的对象的步骤,然后名字为“Batching Create GameObject”,用于
            Undo.RegisterCreatedObjectUndo(gameObject, "Batching Create GameObject");
        }
    }
}

最后是Cancel方法

/// <summary>
/// 取消操作
/// 同ctrl + z
/// </summary>
private void Cancel()
{
    //PerformUndo作用跟ctrl + z一样
    Undo.PerformUndo();
}
解释一下,为啥OnGUI时, Cancel为什么要 EditorGUILayout.EndHorizontal之后才调用,这是因为 Cancel会导致之前 EditorGUILayout.StartHorizontal的标记没了,然后执行 EditorGUILayout.EndHorizontal会报错。

最后可以试一下面板的效果:

增加一个彩蛋,做了一个100*100*100的正方体矩阵然后直接占满8g内存.......

源码:L-Lawliet/UnityEditorTutorial

==========================分割线==========================

如果大家有什么意见和建议,或者是有什么疑问,或者是有想看的知识点内容,都欢迎到评论区发上你们的评论。

最后我希望有更多人参与到插件开发的队伍里。也欢迎大家投稿。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STL源码刨析:序列式容器之list

目录 1.前言 2.list的节点定义和结构 3.list的迭代器定义和结构 4.list的定义和结构 5.list的内存管理 6.list的元素操作 前言 在刨析了vector容器的源码后&#xff0c;list容器相比与vector容器&#xff0c;其元素的插入和删除较快&#xff0c;不需要对原本容器中的元…

集合的交集、并集和差集运算

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 集合最常用的操作就是进行交集、并集、差集和对称差集运算。进行交集运算时使用“&”符号&#xff0c;进行并集运算时使用“&#xff5c;”符号&…

SQL数据库多层嵌套 json转sql建表语句,SQL数据库里数组里对象数据怎么创建

1. uniapp sqlite 一个数组包含对象嵌套对象通过主外键方式插入数据库&#xff1a; // 假设有一个对象数组&#xff0c;对象中包含嵌套对象 const objectsArray [{parentObject: {id: 1,name: Parent 1,// 其他父对象属性},childObject: {id: 11,parentId: 1,name: Child 1 o…

vue中的$nextTick和过渡与动画

一.vue中的$nextTick 简述与用法&#xff1a;这是一个生命周期钩子 1.语法&#xff1a;this.$nextTick(回调函数) 2.作用&#xff1a;在下一次DOM更新结束后执行其指定的回调 3.什么时候用&#xff1a;当修改数据后&#xff0c;要基于更新后的新dom进行某些操作时&#xff0c;…

精酿啤酒:品质与口感在不同消费人群中的差异与共性

在啤酒市场中&#xff0c;不同消费人群对品质与口感的喜好存在一定的差异。然而&#xff0c;Fendi club啤酒凭借其卓着的品质和与众不同的口感&#xff0c;在不同消费人群中都展现出一定的共性。 从性别差异来看&#xff0c;男性消费者通常更注重啤酒的品质和口感&#xff0c;而…

Llama 3 模型家族构建安全可信赖企业级AI应用之使用 Llama Guard 保护大模型对话 (八)

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

机器学习(七) ----------聚类(K-means)

目录 1 核心思想 2 K-means算法 2.1 算法概述 2.2 算法步骤 2.3 数学原理 2.4 ‘肘’方法确定K值 2.4.1 原理 2.4.2 步骤 2.4.3 代码实现 2.5 聚类评估方法 2.5.1 SC轮廓系数&#xff08;Silhouette Coefficient&#xff09; 计算方法 解读 注意事项 2.5.2 Cal…

Windows UWP ContentDialog去掉阴影(全透明)的实现

一、前言 在WIndows开发中&#xff0c;使用UWP&#xff08;Universal WIndows&#xff09;项目开发过程中&#xff0c;使用ContentDialog 的过程中&#xff0c;我们可能并不满足现有的样式&#xff0c;这时就需要自定义样式。笔者在自定义样式过程中&#xff0c;遇到了一个难题…

数据库多表查询

多表查询&#xff1a; SELECT *FROM stu_table,class WHERE stu_table.c_idclass.c_id; 多表查询——内连接 查询两张表交集部分。 隐式内连接&#xff1a; #查询学生姓名&#xff0c;和班级名称&#xff0c;隐式调用 SELECT stu_table.s_name,class.c_name FROM stu_table…

php反序列化学习(1)

1、php面向对象基本概念 类的定义&#xff1a; 类是定义了一件事物的抽象特征&#xff0c;它将数据的形式以及这些数据上的操作封装住在一起。&#xff08;对象是具有类类型的变量&#xff0c;是对类的实例&#xff09; 构成&#xff1a; 成员变量&#xff08;属性&#xf…

来自工业界的知识库 RAG 服务(二),RagFlow 源码全流程深度解析

背景介绍 前面介绍过 有道 QAnything 源码解析&#xff0c;通过深入了解工业界的知识库 RAG 服务&#xff0c;得到了不少调优 RAG 服务的新想法。 因此本次趁热打铁&#xff0c;额外花费一点时间&#xff0c;深入研究了另一个火热的开源 RAG 服务 RagFlow 的完整实现流程&…

上交提出TrustGAIN,提出6G网络中可信AIGC新模式!

月16日至18日&#xff0c;2024全球6G技术大会在南京召开。会上&#xff0c;全球移动通信标准制定组织3GPP&#xff08;第三代合作伙伴计划&#xff09;的3位联席主席分享了3GPP6G标准时间表&#xff1a; 2024年9月&#xff0c;启动6G业务需求研究&#xff1b; 2025年6月&…

FastReport 主子表关系

代码中只需要绑定主表的数据就可以&#xff0c;子表的数据会通过报表中的关连关系自动到数据库中带出。 using CloudSaaS.DB.Handler; using CloudSaaS.Model; using CloudSaaS.DAL; using FastReport; using FastReport.Web; using System; using System.Collections.Generic;…

Hotcoin Research | 市场洞察:2024年5月13日-5月19日

加密货币市场表现 目前&#xff0c;加密货币总市值为1.32万亿&#xff0c;BTC占比54.41%。 本周行情呈现震荡上行的态势&#xff0c;BTC在5月15日-16日&#xff0c;有一波大的拉升&#xff0c;周末为震荡行情。BTC现价为67125美元。 上涨的主要原因&#xff1a;美国4月CPI为3…

Oracle创建用户时提示ORA-65096:公用用户名或角色名无效

Oracle创建用户时提示“ORA-65096&#xff1a;公用用户名或角色名无效” 如下图所示&#xff1a; 解决方法&#xff1a;在新增用户名前面加上C##或者c##就可以解决无效问题&#xff0c;具体什么原因还不清楚&#xff0c;需要再研究一下。

JS 中怎么删除数组元素?有哪几种方法?

正文开始之前推荐一位宝藏博主免费分享的学习教程,学起来! 编号学习链接1Cesium: 保姆级教程+源码示例2openlayers: 保姆级教程+源码示例3Leaflet: 保姆级教程+源码示例4MapboxGL: 保姆级教程+源码示例splice() JavaScript中的splice()方法是一个内置的数组对象函数, 用于…

vr数字成果展在线展示突破用户传统认知

想要轻松搭建一个充满互动与创意的3D数字展厅吗?vr互动数字展厅搭建编辑器将是您的不二之选!华锐视点3D云展平台提供的vr互动数字展厅搭建编辑器将空间重建与互动制作完美结合&#xff0c;让您轻松实现3D空间的搭建与互动营销制作。 在vr互动数字展厅搭建编辑器的帮助下&#…

SpringBoot 返回值 i18n 自动处理

定义基础通用类 首先定义一波错误码&#xff1a;ResultCode Getter AllArgsConstructor public enum ResultCode {SUCCESS(200, "请求成功", "request.success"),Fail(400, "请求失败", "request.failed"),PASSWORD_NOT_MATCH(1000…

独家揭秘!Amazon、lazada、Shopee测评自养号,新手也能秒变高手!

近年来&#xff0c;随着国内卖家涌入跨境电商平台&#xff0c;市场竞争愈加激烈。为了迅速占领市场&#xff0c;测评变得至关重要。然而&#xff0c;真人测评供不应求&#xff0c;服务商账号质量不一&#xff0c;且存在高权重账号稀缺和黑卡下单风险。因此&#xff0c;许多大卖…

为什么选择CleanMyMac软件呢?推荐理由

你是否曾经遇到过这样的问题&#xff1a;电脑运行缓慢&#xff0c;存储空间不足&#xff0c;不知道如何清理垃圾文件&#xff1f;别担心&#xff0c;我们为你找到了解决方案——CleanMyMac软件。这款强大的工具可以帮助你轻松解决这些问题&#xff0c;让你的电脑焕然一新&#…