夺宝网站怎样做优化,空间设计图片,C语言做网站需要创建窗口吗,网站建设公司能力要求推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好#xff0c;我是佛系工程师☆恬静的小魔龙☆#xff0c;不定时更新Unity开发技巧#xff0c;觉得有用记得一键三连哦。
一、前言
嗨#xff0c;大家好#xff0c;我是恬静的小魔龙。
同学们… 推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好我是佛系工程师☆恬静的小魔龙☆不定时更新Unity开发技巧觉得有用记得一键三连哦。
一、前言
嗨大家好我是恬静的小魔龙。
同学们国庆节好呀放假了有没有好好学习呢。
最近学习了Unity3D编辑器方面的知识在学习的过程中发现一些比较容易混杂的点特意总结了一下方便自己和同学们学习做了一份Unity3D编辑器开发脉络图恳请敬请批评指正。
二、Unity3D编辑器开发
2-1、Unity3D编辑器开发脉络图
首先放一张脉络图。 大图可放大查看。
看着这张图是不是感觉有些不知道从哪里开始看起好呢接下来就来分析一下如何查看。
2-2、Unity3D编辑器开发分类
博主刚开始学习编辑器开发也是一脸懵的样子为啥一会用OnGUI绘制窗口一会用Editor绘制窗口一会用EditorWindows绘制窗口还有继承PropertyDrawer后进行属性绘制的。
它们之间有什么区别与联系呢。
它们简单可以分成窗口绘制、检视器绘制、场景绘制、属性绘制窗口绘制需要继承与EditorWindow类然后在OnGUI里面进行窗口绘制。检视器绘制需要继承与Editor类然后在OnInspectorGUI里面进行窗口绘制。场景绘制需要继承与Editor类然后在OnSceneGUI里面进行绘制。属性绘制需要继承与PropertyDrawer类然后在OnGUI里面进行绘制。还有一个检视器属性这个单独来说。
这么一分析是不是有些明了了就是如果要绘制窗口的话就需要继承EditorWindow类然后在OnGUI里面进行窗口绘制。
重新绘制检视器窗口也就是Inspector窗口或者场景Scene窗口就需要继承Editor类然后在OnInspectorGUI里面进行Inspector窗口绘制在OnSceneGUI里面进行Scene窗口绘制。
2-3、检视器属性
2-3-1、HideInInspector
介绍可以隐藏公共成员变量防止Inspector的值影响到他同时保证脚本中变量的可访问度。
举个例子
不加[HideInInspector]
using UnityEngine;public class Test01 : MonoBehaviour
{public string Name;//注意这是public访问权限
}加[HideInInspector]
using UnityEngine;public class Test01 : MonoBehaviour
{[HideInInspector]public string Name;//注意这是public访问权限
}2-3-2、SerializeField
介绍将私有变量设置为检视面板可见可修改Unity会将对象进行序列化存储即使是私有的标记为可序列化后也会显示公有变量默认是可序列化的。
举个例子
不加[SerializeField]
using UnityEngine;public class Test01 : MonoBehaviour
{private string Name;
}加[SerializeField]
using UnityEngine;public class Test01 : MonoBehaviour
{[SerializeField]private string Name;
}2-3-3、Space
介绍在当前成员变量上方留 50 像素空白区域
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[Space]public string Name;
}2-3-4、Header
介绍在当前成员变量上方加入一个标题文字
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[Header(标题)]public string Name;
}2-3-5、Tooltip
介绍添加变量悬浮提示当鼠标放入后会有提示
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[Tooltip(输入名字)]public string Name;
}2-3-6、Range
介绍给数值设定范围。
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[Range(0,10)]public int Age;
}2-3-7、Multiline
介绍指定输入行字符参数为行数。
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[Multiline(5)]public string Name;
}2-3-8、TextArea
介绍设置默认显示 5 行最多显示 10 行内容再多用滚动条控制显示。
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[TextArea(5,10)]//(最小行数最大行数)public string Name;
}2-3-9、ContextMenu
介绍在小齿轮中添加一个回调函数参数为函数名称用于调用该特性标记的方法。
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[ContextMenu(CallBack)]public void CallBackFun(){Debug.Log(回调函数);}
}2-3-10、ContextMenuItem
介绍给一个变量添加右键菜单第一个参数是菜单名称第二个参数是回调函数。
举个例子
using UnityEngine;public class Test01 : MonoBehaviour
{[ContextMenuItem(点击调用函数, CallBackFun)]public string Name;public void CallBackFun(){Debug.Log(回调函数);}
}2-3-11、AddComponentMenu
介绍在编辑器添加一个用于添加组件的菜单项将拥有该属性的脚本添加到选中的物体上。第一个参数分类名/组件名第二个参数列表中显示的顺序。
举个例子
using UnityEngine;[AddComponentMenu(点击添加组件函数)]
public class Test01 : MonoBehaviour
{
}2-3-12、ExecuteInEditMode
介绍使生命周期函数在编辑器状态下可以执行游戏中也可以正常使用Update()在场景中对象发生变化或项目组织发生变化时会在编辑器下执行。也就是说不在运行状态也可以运行Start、Awake函数。
举个例子
using UnityEngine;[ExecuteInEditMode]
public class Test01 : MonoBehaviour
{private void Awake(){Debug.Log(Awake);}private void Start(){Debug.Log(Start);}private void Update(){Debug.Log(Update);}
}2-3-13、RequireComponent
介绍依赖、绑定作用是当我们把一个Script绑定到GameObject上时会同时把需要依赖的脚本也一起绑定添加上去。
举个例子
using UnityEngine;[RequireComponent(typeof(Rigidbody))]
public class Test01 : MonoBehaviour
{
}2-3-14、CanEditMultipleObjects
介绍告诉 Unity 可以使用此编辑器来选择多个对象并同时更改所有对象。
举个例子
新建脚本Test01.cs编辑代码
using UnityEngine;public class Test01 : MonoBehaviour
{public int m_MyInt 75;public Vector3 m_MyVector new Vector3(20, 1, 0);public GameObject m_MyGameObject;
}在Project视图中Script文件夹内新建Editor文件夹在这个文件夹新建Test01Editor.cs脚本编辑代码
using UnityEngine;
using UnityEditor;[CustomEditor(typeof(Test01))]
public class Test01Editor : Editor
{SerializedProperty m_IntProp;SerializedProperty m_VectorProp;SerializedProperty m_GameObjectProp;void OnEnable(){m_IntProp serializedObject.FindProperty(m_MyInt);m_VectorProp serializedObject.FindProperty(m_MyVector);m_GameObjectProp serializedObject.FindProperty(m_MyGameObject);}public override void OnInspectorGUI(){EditorGUILayout.PropertyField(m_IntProp, new GUIContent(Int Field), GUILayout.Height(20));EditorGUILayout.PropertyField(m_VectorProp, new GUIContent(Vector Object));EditorGUILayout.PropertyField(m_GameObjectProp, new GUIContent(Game Object));serializedObject.ApplyModifiedProperties();}
}这时候给多个对象挂载Test01脚本然后选中多个对象修改脚本就会显示Multi-object editing not supported.不支持多对象编辑 这时候修改Test01Editor.cs脚本
using UnityEngine;
using UnityEditor;[CustomEditor(typeof(Test01))]
[CanEditMultipleObjects]
public class Test01Editor : Editor
{SerializedProperty m_IntProp;SerializedProperty m_VectorProp;SerializedProperty m_GameObjectProp;void OnEnable(){m_IntProp serializedObject.FindProperty(m_MyInt);m_VectorProp serializedObject.FindProperty(m_MyVector);m_GameObjectProp serializedObject.FindProperty(m_MyGameObject);}public override void OnInspectorGUI(){EditorGUILayout.PropertyField(m_IntProp, new GUIContent(Int Field), GUILayout.Height(20));EditorGUILayout.PropertyField(m_VectorProp, new GUIContent(Vector Object));EditorGUILayout.PropertyField(m_GameObjectProp, new GUIContent(Game Object));serializedObject.ApplyModifiedProperties();}
}就可以同时编辑多个对象了
2-3-15、MenuItem
介绍在顶部显示工具菜单。
举个例子
新建脚本Test01.cs编辑代码
using UnityEditor;
using UnityEngine;public class Test01 : MonoBehaviour
{[MenuItem(Test/顶部菜单)]public static void CallBackFun(){}
}2-3-16、CustomEditor
介绍自定义编辑器可以修改所关联组件检视面板的属性然后重新绘制Editor目录下建立编辑器脚本将编辑器脚本与原始脚本关联。
举个例子
新建脚本Test01.cs编辑代码
using UnityEngine;public class Test01 : MonoBehaviour
{public int m_MyInt 75;public Vector3 m_MyVector new Vector3(20, 1, 0);public GameObject m_MyGameObject;
}在Project视图中Script文件夹内新建Editor文件夹在这个文件夹新建Test01Editor.cs脚本编辑代码
using UnityEngine;
using UnityEditor;[CustomEditor(typeof(Test01))]
public class Test01Editor : Editor
{SerializedProperty m_IntProp;SerializedProperty m_VectorProp;SerializedProperty m_GameObjectProp;void OnEnable(){m_IntProp serializedObject.FindProperty(m_MyInt);m_VectorProp serializedObject.FindProperty(m_MyVector);m_GameObjectProp serializedObject.FindProperty(m_MyGameObject);}// 用于重新绘制Inspector面板中的属性public override void OnInspectorGUI(){// 设置高度EditorGUILayout.PropertyField(m_IntProp, new GUIContent(Int Field), GUILayout.Height(100));EditorGUILayout.PropertyField(m_VectorProp, new GUIContent(Vector Object));EditorGUILayout.PropertyField(m_GameObjectProp, new GUIContent(Game Object));serializedObject.ApplyModifiedProperties();}
}2-4、窗口绘制
2-4-1、使用窗口绘制
好到这里暂停一下回想一下还记得前文说的窗口绘制要继承什么类吗 ↓ ↓ ↓ ↓ 窗口绘制需要继承与EditorWindow类然后在OnGUI里面进行窗口绘制。
继承EditorWindow类需要将脚本放到Editor脚本中才能生效。
让我们在Editor文件夹中新建Test02EditorWindow.cs脚本编辑代码
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;public class Test02EditorWindow : EditorWindow
{[MenuItem(工具/创建窗口)]static void OpenWindow(){//泛型T 窗口类型。必须派生自 EditorWindow。//第一个参数设置为 true 可创建浮动实用程序窗口设置为 false 可创建正常窗口。//第三个参数设置是否为窗口提供焦点如果已存在。Test02EditorWindow window GetWindowTest02EditorWindow(false, 弹窗标题, true);window.minSize new Vector2(40, 30);window.minSize new Vector2(80, 60);}//开窗口调用private void OnEnable(){Debug.Log(enable);}//关窗口调用private void OnDisable(){Debug.Log(disable);}//窗口开启就调用private void Update(){Debug.Log(update);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button(测试点击)){Debug.Log(测试点击);}}//场景结构发生变化执行回调函数private void OnHierarchyChange(){Debug.Log(hierarchy);}//项目结构发生变化执行回调函数private void OnProjectChange(){Debug.Log(project);}//选中物体发生变化执行回调函数private void OnSelectionChange(){//获取当前选中的物体的名称Debug.Log(Selection.activeGameObject.name);}
}编辑器编译通过后在编辑器的菜单栏找到工具→创建窗口 这个就是渲染出来的窗口了 绘制就在OnGUI里面绘制的UI也是OnGUI支持的UI就可以了。
具体OnGUI怎么用这里就不再赘述了。
这里再分享一些常用的小功能代码。
2-4-2、检查开启mipmap的非2的幂贴图
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;public class Test02EditorWindow : EditorWindow
{[MenuItem(工具/检查开启mipmap的非2的幂贴图)]static void OpenWindow(){Test02EditorWindow window GetWindowTest02EditorWindow(false, 弹窗标题, true);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button(检查开启mipmap的非2的幂贴图)){CheckNPOT();}}private void CheckNPOT(){Liststring files AssetDatabase.FindAssets(t:Texture).Select(AssetDatabase.GUIDToAssetPath).ToList();Liststring outputList new Liststring();foreach (var file in files){TextureImporter textureImporter AssetImporter.GetAtPath(file) as TextureImporter;if (textureImporter){//贴图为Sprite或设置了2的幂scaleif (textureImporter.textureType TextureImporterType.Sprite || textureImporter.npotScale ! TextureImporterNPOTScale.None){continue;}//贴图长宽均为2的幂textureImporter.GetSourceTextureWidthAndHeight(out var width, out var height);if (IsPowerOfTwo(width) IsPowerOfTwo(height)){continue;}if (textureImporter.mipmapEnabled){outputList.Add(file);Debug.Log(file);}}}WriteLog(NPOT.log, outputList);}private void WriteLog(string fileName, Liststring outputList){if (!Directory.Exists(Logs)){Directory.CreateDirectory(Logs);}if (!File.Exists(Logs/ fileName)){using (FileStream fs new FileStream(Logs/ fileName, FileMode.CreateNew)){}}File.WriteAllLines(Logs/ fileName, outputList);}private bool IsPowerOfTwo(int value){return (value (value - 1)) 0;}
}2-4-3、获取选中文件夹下的所有资源
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;public class Test02EditorWindow : EditorWindow
{[MenuItem(工具/获取选中文件夹下的所有资源)]static void OpenWindow(){Test02EditorWindow window GetWindowTest02EditorWindow(false, 获取选中文件夹下的所有资源, true);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button(获取选中文件夹下的所有资源)){Liststring pathList new Liststring();Object[] m_objects Selection.GetFiltered(typeof(Object), SelectionMode.Unfiltered | SelectionMode.DeepAssets);foreach (var obj in m_objects){string path AssetDatabase.GetAssetPath(obj);if (!pathList.Contains(path)){pathList.Add(path);}}foreach (var item in pathList){Debug.Log(item);}}}
}2-4-4、删除prefab中missing的script
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;public class Test02EditorWindow : EditorWindow
{[MenuItem(工具/删除prefab中missing的script)]static void OpenWindow(){Test02EditorWindow window GetWindowTest02EditorWindow(false, 删除prefab中missing的script, true);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button(删除prefab中missing的script)){Liststring logList new Liststring();Liststring prefabPathList new Liststring();foreach (var prefabPath in prefabPathList){if (EditorUtility.DisplayCancelableProgressBar(Processing, string.Format({0} {1}/{2},prefabPath, prefabPathList.IndexOf(prefabPath), prefabPathList.Count),prefabPathList.IndexOf(prefabPath) / (float)prefabPathList.Count)){EditorUtility.ClearProgressBar();return;}GameObject go AssetDatabase.LoadAssetAtPathGameObject(prefabPath);if (go){int count GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(go);if (count 0){GameObjectUtility.RemoveMonoBehavioursWithMissingScript(go);logList.Add(string.Format(删除了{0}中的{1}个missing的script, prefabPath, count));}}}EditorUtility.ClearProgressBar();}}
}未完待续欢迎补充。。。
2-5、检视器Inspector绘制
将普通的类关联Editor工具实现特殊功能。
比如一个Test01.cs类是普通类在Editor文件夹内新建一个Test01Editor.cs编辑类Test01Editor.cs就是一个自定义编辑器然后在Test01Editor.cs的OnInspectorGUI函数内进行属性的修改绘制。
接下来一个老例子来说明一下如何使用
举个例子
新建脚本Test01.cs编辑代码
using UnityEngine;public class Test01 : MonoBehaviour
{public int m_MyInt 75;public Vector3 m_MyVector new Vector3(20, 1, 0);public GameObject m_MyGameObject;
}默认是这样的 在Project视图中Script文件夹内新建Editor文件夹在这个文件夹新建Test01Editor.cs脚本编辑代码
using UnityEngine;
using UnityEditor;//CustomEditor 属性告知 Unity 应该作为哪个组件的编辑器。
[CustomEditor(typeof(Test01))]
public class Test01Editor : Editor
{SerializedProperty m_IntProp;SerializedProperty m_VectorProp;SerializedProperty m_GameObjectProp;void OnEnable(){m_IntProp serializedObject.FindProperty(m_MyInt);m_VectorProp serializedObject.FindProperty(m_MyVector);m_GameObjectProp serializedObject.FindProperty(m_MyGameObject);}// 用于重新绘制Inspector面板中的属性public override void OnInspectorGUI(){// 设置高度EditorGUILayout.PropertyField(m_IntProp, new GUIContent(Int Field), GUILayout.Height(100));EditorGUILayout.PropertyField(m_VectorProp, new GUIContent(Vector Object));EditorGUILayout.PropertyField(m_GameObjectProp, new GUIContent(Game Object));serializedObject.ApplyModifiedProperties();}
}修改后是这样的
2-6、场景Scene绘制
OnSceneGUI的运行方式很像 OnInspectorGUI只不过在 Scene 视图中运行而已。
为了方便创建自己的编辑控件可以使用在 Handles 类中定义的函数。
其中的所有函数都是为 3D 模式的 Scene 视图设计的。
举个例子 新建脚本Test01.cs编辑代码
using UnityEditor;
using UnityEngine;[ExecuteInEditMode]
public class Test01 : MonoBehaviour
{public Vector3 lookAtPoint Vector3.zero;public void Update(){transform.LookAt(lookAtPoint);}
}在Project视图中Script文件夹内新建Editor文件夹在这个文件夹新建Test01Editor.cs脚本编辑代码
using UnityEngine;
using UnityEditor;[CustomEditor(typeof(Test01))]
[CanEditMultipleObjects]
public class Test01Editor : Editor
{SerializedProperty lookAtPoint;void OnEnable(){lookAtPoint serializedObject.FindProperty(lookAtPoint);}public void OnSceneGUI(){var t (target as Test01);EditorGUI.BeginChangeCheck();Vector3 pos Handles.PositionHandle(t.lookAtPoint, Quaternion.identity);if (EditorGUI.EndChangeCheck()){Undo.RecordObject(target, Move point);t.lookAtPoint pos;t.Update();}}
}2-7、属性Property绘制
用于从中派生自定义属性绘制器的基类。使用此基类可为您自己的 Serializable 类或者具有自定义 PropertyAttribute 的脚本变量创建自定义绘制器。
PropertyDrawer 有两种用途 自定义 Serializable 类的每个实例的 GUI。 自定义具有自定义 PropertyAttribute 的脚本成员的 GUI。 如果您有自定义的 Serializable 类可以使用 PropertyDrawer 来控制它在 Inspector 中的外观。
举个例子 新建脚本Recipe.cs编辑代码
using System;
using UnityEngine;public enum IngredientUnit { Spoon,Cup,Bowl,Piece}[Serializable]
public class Ingredient
{public string name;public int amount 1;public IngredientUnit unit;
}public class Recipe : MonoBehaviour
{public Ingredient potionResult;public Ingredient[] pointIngredients;
}
在Editor文件夹内新建脚本IngredientDrawerUIE.cs编辑代码
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;[CustomPropertyDrawer(typeof(Ingredient))]
public class IngredientDrawerUIE : PropertyDrawer
{public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){EditorGUI.BeginProperty(position, label, property);// labelposition EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);// 控制字段缩进 设置为不缩进var indent EditorGUI.indentLevel;EditorGUI.indentLevel 0;// 计算矩形范围var nameRect new Rect(position.x, position.y, 30, position.height); var amountRect new Rect(position.x 35, position.y, 50, position.height);var unitRect new Rect(position.x 90, position.y, position.width - 90, position.height);// 绘制字段EditorGUI.PropertyField(nameRect, property.FindPropertyRelative(name), GUIContent.none);EditorGUI.PropertyField(amountRect, property.FindPropertyRelative(amount), GUIContent.none);EditorGUI.PropertyField(unitRect, property.FindPropertyRelative(unit), GUIContent.none);// 控制字段缩进 设置为原来的数值EditorGUI.indentLevel indent;EditorGUI.EndProperty();}
}将Recipe脚本添加到对象上查看效果
2-8、参考链接
Unity学习笔记之编辑器开发
Unity编辑器工具开发经验总结
自定义编辑器
属性绘制器
三、后记
OK。总结一下。
Unity3D编辑器开发就是基于Unity3D编辑器做一些帮助开发的小工具。
在这里可以分成检视器属性、界面绘制、属性绘制三个大方面。
检视器属性参考2-3小节。
界面绘制可以分为窗口绘制、检视器界面绘制、场景绘制。
窗口绘制的话就需要继承EditorWindow类然后在OnGUI里面渲染UI。
检视器界面绘制需要继承Editor类然后在OnInspectorGUI里面进行绘制。
场景绘制需要继承Editor类然后在OnSceneGUI里面进行绘制。
属性绘制需要继承PropertyDrawer类然后在OnGUI里面进行绘制。
如果觉得本篇文章有用别忘了点个关注关注不迷路持续分享更多Unity干货文章。 你的点赞就是对博主的支持有问题记得留言
博主主页有联系方式。
博主还有跟多宝藏文章等待你的发掘哦
专栏方向简介Unity3D开发小游戏小游戏开发教程分享一些使用Unity3D引擎开发的小游戏分享一些制作小游戏的教程。Unity3D从入门到进阶入门从自学Unity中获取灵感总结从零开始学习Unity的路线有C#和Unity的知识。Unity3D之UGUIUGUIUnity的UI系统UGUI全解析从UGUI的基础控件开始讲起然后将UGUI的原理UGUI的使用全面教学。Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。Unity3D之数据集合数据集合数组集合数组、List、字典、堆栈、链表等数据集合知识分享。Unity3D之VR/AR虚拟仿真开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法插件介绍等Unity3D之日常开发日常记录主要是博主日常开发中用到的用到的方法技巧开发思路代码分享等Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中遇到的BUG和坑让后来人可以有些参考。