【Unity3D编辑器开发】Unity3D编辑器开发基础性框架结构【全面总结】
推荐阅读
- 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 = GetWindow<Test02EditorWindow>(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 = GetWindow<Test02EditorWindow>(false, "弹窗标题", true);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button("检查开启mipmap的非2的幂贴图")){CheckNPOT();}}private void CheckNPOT(){List<string> files = AssetDatabase.FindAssets("t:Texture").Select(AssetDatabase.GUIDToAssetPath).ToList();List<string> outputList = new List<string>();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, List<string> 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 = GetWindow<Test02EditorWindow>(false, "获取选中文件夹下的所有资源", true);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button("获取选中文件夹下的所有资源")){List<string> pathList = new List<string>();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 = GetWindow<Test02EditorWindow>(false, "删除prefab中missing的script", true);}//用于绘制窗口内容private void OnGUI(){if (GUILayout.Button("删除prefab中missing的script")){List<string> logList = new List<string>();List<string> prefabPathList = new List<string>();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.LoadAssetAtPath<GameObject>(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之UGUI | UGUI | Unity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。 |
Unity3D之读取数据 | 文件读取 | 使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。 |
Unity3D之数据集合 | 数据集合 | 数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。 |
Unity3D之VR/AR(虚拟仿真)开发 | 虚拟仿真 | 总结博主工作常见的虚拟仿真需求进行案例讲解。 |
Unity3D之插件 | 插件 | 主要分享在Unity开发中用到的一些插件使用方法,插件介绍等 |
Unity3D之日常开发 | 日常记录 | 主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等 |
Unity3D之日常BUG | 日常记录 | 记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。 |
相关文章:
【Unity3D编辑器开发】Unity3D编辑器开发基础性框架结构【全面总结】
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 嗨,大家好,我是恬静的小魔龙。 同学们…...
一座“城池”:泡泡玛特主题乐园背后,IP梦想照亮现实
“更适合中国宝宝体质”的主题乐园,被泡泡玛特造出来了。 9月26日,位于北京朝阳公园内的国内首个潮玩行业沉浸式 IP 主题乐园,也是泡泡玛特首个线下乐园——泡泡玛特城市乐园 POP LAND正式开园。 约4万平方米的空间中,泡泡玛特使…...
【什么是闭包? 闭包产生的原因? 闭包有哪些表现形式?】
JS闭包 什么是闭包?闭包产生的原因?闭包有哪些表现形式? 什么是闭包? 闭包是指一个函数可以访问并操作在其作用域之外的变量的能力。在 JavaScript 中,每当函数被创建时,就会创建一个闭包。 以下是一个简单的闭包示例…...
JackJson和FastJson
前言: fastjson是一款强大的json格式转换工具,我个人在开发中就非常喜欢用fastjson;但是由于某些原因,导致fastjson会有一些漏洞,因此在漏洞扫描后需要修复都是要求我们升级版本,或者替换为jackjson&#…...
SpringCloud学习一
单体应用存在的问题 随着业务的发展,开发变得越来越复杂。 修改、新增某个功能,需要对整个系统进行测试、重新部署。 一个模块出现问题,很可能导致整个系统崩溃。 多个开发团队同时对数据进行管理,容易产生安全漏洞。 各个模块…...
SpringBoot, EventListener事件监听的使用
1、背景 在开发工作中,会遇到一种场景,做完某一件事情以后,需要广播一些消息或者通知,告诉其他的模块进行一些事件处理,一般来说,可以一个一个发送请求去通知,但是有一种更好的方式,…...
课题学习(三)----倾角和方位角的动态测量方法(基于陀螺仪的测量系统)
一、内容介绍 该测量系统基于三轴加速度和三轴陀螺仪,安装在钻柱内部,随钻柱一起旋转,形成捷联惯性导航系统,安装如下图所示: 假设三轴加速度和陀螺仪的输出为: f b [ f x f y f z ] T f^b\begin{bmatrix}f_{x} …...
1876. 长度为三且各字符不同的子字符串
1876. 长度为三且各字符不同的子字符串 C代码:滑动窗口 // 存在三种字符,且不重复、子串数量 int countGoodSubstrings(char * s){int k 3;int hash[26] {0};int len 0;int l 0;int ans 0;for (int i 0; i < strlen(s); i) {hash[s[i] - a];if…...
Mall脚手架总结(一)——SpringSecurity实现鉴权认证
前言 在结束理论知识的学习后,荔枝开始项目学习,这个系列文章将围绕荔枝学习mall项目过程中总结的知识点来梳理。本篇文章主要涉及如何整合Spring Security和JWT实现鉴权认证的功能!希望能帮助到一起学习mall项目的小伙伴~~~ 文章目录 前言 …...
beego-简单项目写法--路径已经放进去了
Beego案例-新闻发布系统 1.注册 后台代码和昨天案例代码一致。,所以这里面只写一个注册的业务流程图。 **业务流程图 ** 2.登陆 业务流程图 登陆和注册业务和我们昨天登陆和注册基本一样,所以就不再重复写这个代码 但是我们遇到的问题是如何做代码的迁移&…...
Linux-CPU相关常用命令合集
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、cpu相关常用命令 二、cpuinfo 参数详细对照表 前言 本篇文章主要记录平时Linux-常用命令整理! 提示:以下是本篇文章正文内容&#…...
vue 百度地图/天地图设置铺满屏幕100%,解决空隙问题
设置100%无效,刷新依然右侧有空隙,解决:min-width: 100vw; <div class"aui-flex-col" style"width: 100%; height:100%"><div id"mapAllCon" style"width: 100%; min-width: 100vw; height: 10…...
第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第六节 - Python 中字符串的逻辑运算符)
对于 python 中的字符串,布尔运算符(and、or、not)起作用。让我们考虑两个字符串,即 str1 和 str2,并在它们上尝试布尔运算符: Python3 str1 = str2 = geeks# 使用 repr 打印带引号的字符串# 返回 str1 print(repr(str1 and str2)) # 返回 str1 print(repr(str2 and…...
Bark Ai 文本转语音 模型缓存位置修改
默认缓存位置在:~/.cache 加入环境变量:XDG_CACHE_HOME,指定缓存位置 修改后新的位置为: D:\Ai\Bark\Bark Cache...
Docker 镜像的创建
目录 一、Docker镜像的创建 1、基于已有镜像创建 2、基于本地模板创建 3、基于dockerfile创建 3.1 dockerfile结构 3.2 构建镜像命令 二、镜像分层的原理 1、联合文件系统(UnionFS) 2、镜像加载的原理 三、Dockerfile 操作常用的指令 案例实验…...
【ORM】浅聊C#和Java的ORM底层框架
给自己一个目标,然后坚持一段时间,总会有收获和感悟! 国庆假期马上结束,闲暇时间,突然对Ado.Net这个词的由来感兴趣,然后就一顿复习了一遍,顺便也了解了下java关于ORM框架的底层是什么ÿ…...
windows redis 自启动 Redis服务无法启动报错1067问题
如果你的系统服务里面已经有redis服务并且无法启动,则使用下面的命令卸载此服务 ! 1、停止Redis服务: redis-server --service-uninstall 2、删除系统服务 sc delete redis 进入到你的Redis安装目录,我的在以下目录,谨记此时不…...
Ubuntu Server CLI专业提示
基础 网络 获取所有接口的IP地址 networkctl status 显示主机的所有IP地址 hostname -I 启用/禁用接口 ip link set <interface> up ip link set <interface> down 显示路线 ip route 将使用哪条路线到达主机 ip route get <IP> 安全 显示已登录的用户 w…...
Centos7升级OpenSSH9.1
最近遇到了服务器漏洞,需要对服务器的OpenSSH版本进行升级,查阅了相关资料,总结出了一套比较简单的方案。中间遇到的个别问题也进行了记录,供大家参考。 下载准备 从https://ftp.jaist.ac.jp/pub/OpenBSD/OpenSSH/portable/opens…...
linux——信号
目录 一.信号的保存 二.信号集操作 1.信号集 2.信号集操作函数 3.sigprocmask 4.sigpending 三. 信号的捕捉 1.内核态和用户态 2. sigaction 四.可重入函数 五.SIGCHLD信号 一.信号的保存 实际执行信号的处理动作称为信号递达(Delivery)。信号从产生到递达之间的状…...
存档&改造【03】Apex-Fancy-Tree-Select花式树的导入及学习
Apex-Fancy-Tree-Select git学习网页 GitHub - RonnyWeiss/Apex-Fancy-Tree-Select: Fancy Tree Plug-in for Oracle APEX 如何从其他应用程序导出已有插件到新应用程序中 1.从其他应用程序导出插件 其他应用程序-【共享组件】-【插件】-【任务 导出插件】-选择想要导出的…...
【单片机】14-I2C通信之EEPROM
1.EEPROM概念 1.EEPROM 1.1 一些概念 (1)一些概念:ROM【只读存储器---硬盘】,RAM【随机访问存储器--内存】,PROM【可编程的ROM】,EPROM【可擦除ROM】,EEPROM【电可擦除ROM】 1.2 为什么需要EE…...
Mini-dashboard 和meilisearch配合使用
下载的meilisearch一般是development模式,内置客户端,修改客户端后需要重要全部编译,花时间太长了。前后端分离才是正道,客户端修改不用重新编译后端。 方法如下: 1、修改配置文件/etc/meilisearch.toml,…...
leetcode 886. 可能的二分法
给定一组 n 人(编号为 1, 2, …, n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。 给定整数 n 和数组 dislikes ,其中 dislikes[i] [ai, bi] ,表示不允许将…...
Elasticsearch:使用 ELSER 文本扩展进行语义搜索
在今天的文章里,我来详细地介绍如何使用 ELSER 进行文本扩展驱动的语义搜索。 安装 Elasticsearch 及 Kibana 如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考如下的链接来进行安装: 如何在 Linux,MacOS 及 Windows 上…...
OpenRadar DOA函数 Bartlett/CBF和Capon使用
Bartlett / CBF原理看这里 Capon原理看这里 这里只讲怎么调用openradar提供的aoa_bartlett和aoa_capon函数: 一些吐槽:虽然看起来openradar的作者代码水平很高,但里面有很多匪夷所思的写法,比如他demo里的解析文件格式就很迷啊等…...
二叉树--翻转二叉树
文章前言:如果有小白同学还是对于二叉树不太清楚,作者推荐:二叉树的初步认识_加瓦不加班的博客-CSDN博客 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 如果思路不清楚,请看动态页面&am…...
强化学习环境 - robogym - 学习 - 3
强化学习环境 - robogym - 学习 - 3 文章目录 强化学习环境 - robogym - 学习 - 3项目地址为什么选择 robogymObservation - 观测信息Action - 动作信息Initialization - 初始状态设置 项目地址 https://github.com/openai/robogym 为什么选择 robogym 自己的项目需要做一些机…...
CUDA+cuDNN+TensorRT 配置避坑指南
深度学习模型加速部署的环境配置,需要在本地安装NVIDIA的一些工具链和软件包,这是一个些许繁琐的过程,而且一步错,步步错。笔者将会根据自己的经验来提供建议,减少踩坑几率。当然可以完全按照官方教程操作,…...
海口网站建设设计/网络整合营销案例
题目 给你一个混合字符串 s ,请你返回 s 中 第二大 的数字,如果不存在第二大的数字,请你返回 -1 。 混合字符串 由小写英文字母和数字组成。 示例 输入:s “dfa12321afd” 输出:2 解释:出现在 s 中的数…...
谷多网站/个人网页设计作品欣赏
格式说明符/占位符:% 目的:格式与内容分离,制作复杂的公共字符串模板,让某些位置变成动态可输入的。 用法:‘ %[datatype] ‘ % (data, data, ...) %前设置输出格式,用引号括起来&am…...
银川做网站的有哪些/cms快速建站
Willow 点击次数:9274由Huihoo Power开发详细可到其中文主页查看。OpenWFE 点击次数:8182OpenWFE是一个开放源码的Java工作流引擎。它是一个完整的业务处理管理套件:一个引擎,一个工作列表,一个Web界面和一个反应器…...
ps网站首页设计/电脑培训网
国内有科技企业公布了EUV光刻机专利,热闹了几天,然而仔细想来,这专利恐怕对于中国光刻机产业影响有限,离量产依然很远,就如此前的石墨烯专利一样。EUV光刻机可谓是科技行业的皇冠,它集中了全球诸多科技的精…...
腾讯微博 wordpress/怎么创作自己的网站
这一篇是衔接上一篇的,就是要用ggplot2程序包对PCA和PCoA进行可视化。代码我直接照搬过来了,只是绘图的时候用ggplot函数。ggplot2包实现了一个在R中基于全面一致的语法创建图形时的系统。这提供了在R中画图时经常缺乏的图形创造的一致性并允许我们创建具…...
网站建设交流发言稿/东莞营销外包公司
1. 公司内部,内网和外网的网关不一样,怎么样让电脑可以同时上内网和外网呢? 来一张不相关的磁盘结构图: ------------------------------------------------------------------------- 原文: http://www.cnblogs.com/f…...