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

【Unity3D编辑器开发】Unity3D中实现Transform组件拓展,快速复制、粘贴、复原【非常实用】

推荐阅读

  • CSDN主页
  • GitHub开源地址
  • Unity3D插件分享
  • 简书地址
  • 我的个人博客

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

在开发中,常常会遇到频繁复制粘贴物体的坐标、旋转、缩放的操作。

使用Unity自带的组件复制粘贴比较麻烦:
复制:
在这里插入图片描述
粘贴:
在这里插入图片描述
还有一些需要复制位置、旋转、缩放的值到到代码中,如果一个一个复制粘贴非常麻烦,还要一些需要复制添加自定义文本,也很不方便。

所以,就开发了一个小工具,来提升开发效率。

二、正文

2-1、实现快速复制/粘贴,位置/旋转/缩放功能

效果图:
在这里插入图片描述
在Editor文件夹中新建脚本,随便命名,然后编辑代码:

using UnityEngine;
using UnityEditor;
using System.Text;
using static UnityEditor.IMGUI.Controls.PrimitiveBoundsHandle;
using static UnityEngine.UI.Image;[CanEditMultipleObjects]
[CustomEditor(typeof(Transform), true)]
public class TransformEditor : Editor
{static public TransformEditor instance;//当前的本地坐标SerializedProperty mPos;//当前的本地旋转SerializedProperty mRot;//当前的本地缩放SerializedProperty mScale;void OnEnable(){instance = this;if (this){try{var so = serializedObject;mPos = so.FindProperty("m_LocalPosition");mRot = so.FindProperty("m_LocalRotation");mScale = so.FindProperty("m_LocalScale");}catch { }}}void OnDestroy() { instance = null; }/// <summary>/// Draw the inspector widget.绘制inspector小部件。/// </summary>public override void OnInspectorGUI(){//设置label的宽度EditorGUIUtility.labelWidth = 15f;serializedObject.Update();DrawPosition();DrawRotation();DrawScale();DrawCopyAndPaste();serializedObject.ApplyModifiedProperties();}void DrawCopyAndPaste(){GUILayout.BeginHorizontal();bool reset = GUILayout.Button("Copy");bool reset2 = GUILayout.Button("Paste");GUILayout.EndHorizontal();if (reset){//把数值打印出来var select = Selection.activeGameObject;if (select == null)return;//Debug.Log(select.name+"("+ mPos.vector3Value.x.ToString()+ ","+ mPos.vector3Value.y.ToString() + ","+ mPos.vector3Value.z.ToString() + ")");//Debug.Log(select.name + mRot.quaternionValue);//Debug.Log(select.name + "(" + mScale.vector3Value.x.ToString() + "," + mScale.vector3Value.y.ToString() + "," + mScale.vector3Value.z.ToString() + ")");StringBuilder s = new StringBuilder();s.Append("TransformInspector_" + "(" + mPos.vector3Value.x.ToString() + "," + mPos.vector3Value.y.ToString() + "," + mPos.vector3Value.z.ToString() + ")" + "_");s.Append(mRot.quaternionValue + "_");s.Append("(" + mScale.vector3Value.x.ToString() + "," + mScale.vector3Value.y.ToString() + "," + mScale.vector3Value.z.ToString() + ")");//添加到剪贴板UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();}if (reset2){//把数值打印出来//Debug.Log(UnityEngine.GUIUtility.systemCopyBuffer);string s = UnityEngine.GUIUtility.systemCopyBuffer;string[] sArr = s.Split('_');if (sArr[0] != "TransformInspector"){Debug.LogError("未复制Transform组件内容!Transform component content not copied!");return;}//Debug.Log("Pos:" + sArr[1]);//Debug.Log("Rot:" + sArr[2]);//Debug.Log("Scale:" + sArr[3]);try{mPos.vector3Value = ParseV3(sArr[1]);mRot.quaternionValue = new Quaternion() { x = ParseV4(sArr[2]).x, y = ParseV4(sArr[2]).y, z = ParseV4(sArr[2]).z, w = ParseV4(sArr[2]).w };mScale.vector3Value = ParseV3(sArr[3]);}catch (System.Exception ex){Debug.LogError(ex);return;}}}/// <summary>/// String To Vector3/// </summary>/// <param name="strVector3"></param>/// <returns></returns>Vector3 ParseV3(string strVector3){strVector3 = strVector3.Replace("(", "").Replace(")", "");string[] s = strVector3.Split(',');return new Vector3(float.Parse(s[0]), float.Parse(s[1]), float.Parse(s[2]));}/// <summary>/// String To Vector4/// </summary>/// <param name="strVector4"></param>/// <returns></returns>Vector4 ParseV4(string strVector4){strVector4 = strVector4.Replace("(", "").Replace(")", "");string[] s = strVector4.Split(',');return new Vector4(float.Parse(s[0]), float.Parse(s[1]), float.Parse(s[2]), float.Parse(s[3]));}#region Position 位置void DrawPosition(){GUILayout.BeginHorizontal();EditorGUILayout.PropertyField(mPos.FindPropertyRelative("x"));EditorGUILayout.PropertyField(mPos.FindPropertyRelative("y"));EditorGUILayout.PropertyField(mPos.FindPropertyRelative("z"));bool reset = GUILayout.Button("P", GUILayout.Width(20f));GUILayout.EndHorizontal();if (reset) mPos.vector3Value = Vector3.zero;}#endregion#region Scale 缩放void DrawScale(){GUILayout.BeginHorizontal();{EditorGUILayout.PropertyField(mScale.FindPropertyRelative("x"));EditorGUILayout.PropertyField(mScale.FindPropertyRelative("y"));EditorGUILayout.PropertyField(mScale.FindPropertyRelative("z"));bool reset = GUILayout.Button("S", GUILayout.Width(20f));if (reset) mScale.vector3Value = Vector3.one;}GUILayout.EndHorizontal();}#endregion#region Rotation is ugly as hell... since there is no native support for quaternion property drawing 旋转是丑陋的地狱。。。因为四元数属性绘图没有本地支持enum Axes : int{None = 0,X = 1,Y = 2,Z = 4,All = 7,}Axes CheckDifference(Transform t, Vector3 original){Vector3 next = t.localEulerAngles;Axes axes = Axes.None;if (Differs(next.x, original.x)) axes |= Axes.X;if (Differs(next.y, original.y)) axes |= Axes.Y;if (Differs(next.z, original.z)) axes |= Axes.Z;return axes;}Axes CheckDifference(SerializedProperty property){Axes axes = Axes.None;if (property.hasMultipleDifferentValues){Vector3 original = property.quaternionValue.eulerAngles;foreach (Object obj in serializedObject.targetObjects){axes |= CheckDifference(obj as Transform, original);if (axes == Axes.All) break;}}return axes;}/// <summary>/// Draw an editable float field. 绘制可编辑的浮动字段。/// </summary>/// <param name="hidden">Whether to replace the value with a dash 是否将值替换为破折号</param>/// <param name="greyedOut">Whether the value should be greyed out or not 值是否应灰显</param>static bool FloatField(string name, ref float value, bool hidden, GUILayoutOption opt){float newValue = value;GUI.changed = false;if (!hidden){newValue = EditorGUILayout.FloatField(name, newValue, opt);}else{float.TryParse(EditorGUILayout.TextField(name, "--", opt), out newValue);}if (GUI.changed && Differs(newValue, value)){value = newValue;return true;}return false;}/// <summary>/// Because Mathf.Approximately is too sensitive.因为数学近似值太敏感了。/// </summary>static bool Differs(float a, float b) { return Mathf.Abs(a - b) > 0.0001f; }/// <summary>/// 注册Undo/// </summary>/// <param name="name"></param>/// <param name="objects"></param>static public void RegisterUndo(string name, params Object[] objects){if (objects != null && objects.Length > 0){UnityEditor.Undo.RecordObjects(objects, name);foreach (Object obj in objects){if (obj == null) continue;EditorUtility.SetDirty(obj);}}}/// <summary>/// 角度处理/// </summary>/// <param name="angle"></param>/// <returns></returns>static public float WrapAngle(float angle){while (angle > 180f) angle -= 360f;while (angle < -180f) angle += 360f;return angle;}void DrawRotation(){GUILayout.BeginHorizontal();{Vector3 visible = (serializedObject.targetObject as Transform).localEulerAngles;visible.x = WrapAngle(visible.x);visible.y = WrapAngle(visible.y);visible.z = WrapAngle(visible.z);Axes changed = CheckDifference(mRot);Axes altered = Axes.None;GUILayoutOption opt = GUILayout.MinWidth(30f);if (FloatField("X", ref visible.x, (changed & Axes.X) != 0, opt)) altered |= Axes.X;if (FloatField("Y", ref visible.y, (changed & Axes.Y) != 0, opt)) altered |= Axes.Y;if (FloatField("Z", ref visible.z, (changed & Axes.Z) != 0, opt)) altered |= Axes.Z;bool reset = GUILayout.Button("R", GUILayout.Width(20f));if (reset){mRot.quaternionValue = Quaternion.identity;}else if (altered != Axes.None){RegisterUndo("Change Rotation", serializedObject.targetObjects);foreach (Object obj in serializedObject.targetObjects){Transform t = obj as Transform;Vector3 v = t.localEulerAngles;if ((altered & Axes.X) != 0) v.x = visible.x;if ((altered & Axes.Y) != 0) v.y = visible.y;if ((altered & Axes.Z) != 0) v.z = visible.z;t.localEulerAngles = v;}}}GUILayout.EndHorizontal();}#endregion
}

运行结果:
在这里插入图片描述
这样就实现了基本的快速复制/粘贴,位置/旋转/缩放功能。

接下来,就实现单独的位置、旋转、缩放的复制和粘贴吧。

2-2、单独的位置、旋转、缩放的赋值粘贴功能

效果图:
在这里插入图片描述
示例代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;public class ButtonHandler
{public string showDescription;public Action onClickCallBack;public ButtonHandler(string showDescription, Action onClickCallBack){this.showDescription = showDescription;this.onClickCallBack = onClickCallBack;}
}
[CanEditMultipleObjects]
[CustomEditor(typeof(Transform))]
public class TransformEditor2 : Editor
{static public Editor instance;private bool extensionBool;ButtonHandler[] buttonHandlerArray;//当前的本地坐标SerializedProperty mPos;//当前的本地旋转SerializedProperty mRot;//当前的本地缩放SerializedProperty mScale;private void OnEnable(){instance = this;var editorType = Assembly.GetAssembly(typeof(Editor)).GetTypes().FirstOrDefault(m => m.Name == "TransformInspector");instance = CreateEditor(targets, editorType);if (this){try{var so = serializedObject;mPos = so.FindProperty("m_LocalPosition");mRot = so.FindProperty("m_LocalRotation");mScale = so.FindProperty("m_LocalScale");}catch { }}extensionBool = EditorPrefs.GetBool("extensionBool");buttonHandlerArray = new ButtonHandler[9];buttonHandlerArray[0] = new ButtonHandler("Position Copy", () =>{var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();// x,y,zs.Append(mPos.vector3Value.x.ToString() + "," + mPos.vector3Value.y.ToString() + "," + mPos.vector3Value.z.ToString());//添加到剪贴板UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();});buttonHandlerArray[1] = new ButtonHandler("Position Paste", () =>{//把数值打印出来string s = UnityEngine.GUIUtility.systemCopyBuffer;try{mPos.vector3Value = ParseV3(s);}catch (System.Exception ex){Debug.LogError(ex);return;}});buttonHandlerArray[2] = new ButtonHandler("Position Reset", () =>{mPos.vector3Value = Vector3.zero;});buttonHandlerArray[3] = new ButtonHandler("Rotation Copy", () =>{//把数值打印出来var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();s.Append(mRot.quaternionValue.eulerAngles.x + "," + mRot.quaternionValue.eulerAngles.y + "," + mRot.quaternionValue.eulerAngles.z);//添加到剪贴板UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();});buttonHandlerArray[4] = new ButtonHandler("Rotation Paste", () =>{//把数值打印出来Debug.Log(UnityEngine.GUIUtility.systemCopyBuffer);string s = UnityEngine.GUIUtility.systemCopyBuffer;try{mRot.quaternionValue = Quaternion.Euler(ParseV3(s));}catch (System.Exception ex){Debug.LogError(ex);return;}});buttonHandlerArray[5] = new ButtonHandler("Rotation Reset", () =>{mRot.quaternionValue = Quaternion.identity;});buttonHandlerArray[6] = new ButtonHandler("Scale Copy", () =>{//把数值打印出来var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();s.Append(mScale.vector3Value.x.ToString() + "," + mScale.vector3Value.y.ToString() + "," + mScale.vector3Value.z.ToString());//添加到剪贴板UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();});buttonHandlerArray[7] = new ButtonHandler("Scale Paste", () =>{//把数值打印出来Debug.Log(UnityEngine.GUIUtility.systemCopyBuffer);string s = UnityEngine.GUIUtility.systemCopyBuffer;try{mScale.vector3Value = ParseV3(s);}catch (System.Exception ex){Debug.LogError(ex);return;}});buttonHandlerArray[8] = new ButtonHandler("Scale Reset", () =>{mScale.vector3Value = Vector3.one;});}private void OnDisable(){EditorPrefs.SetBool("extensionBool", extensionBool);}public override void OnInspectorGUI(){instance.OnInspectorGUI();GUI.color = Color.cyan;extensionBool = EditorGUILayout.Foldout(extensionBool, "拓展功能");if (extensionBool){EditorGUILayout.BeginHorizontal();for (int i = 0; i < buttonHandlerArray.Length; i++){ButtonHandler temporaryButtonHandler = buttonHandlerArray[i];if (GUILayout.Button(temporaryButtonHandler.showDescription, "toolbarbutton"))//, GUILayout.MaxWidth(150){temporaryButtonHandler.onClickCallBack();}GUILayout.Space(5);if ((i + 1) % 3 == 0 || i + 1 == buttonHandlerArray.Length){EditorGUILayout.EndHorizontal();if (i + 1 < buttonHandlerArray.Length){GUILayout.Space(5);EditorGUILayout.BeginHorizontal();}}}}GUI.color = Color.white;serializedObject.ApplyModifiedProperties();}Vector3 ParseV3(string strVector3){string[] s = strVector3.Split(',');return new Vector3(float.Parse(s[0]), float.Parse(s[1]), float.Parse(s[2]));}
}

演示:
在这里插入图片描述
这样就实现了单独的位置/旋转/缩放复制/粘贴功能。

接下来,就实现单独的位置/旋转/缩放复制/粘贴功能以及位置/旋转/缩放一起复制和粘贴功能。

以及,自定义文本拼接的功能。

2-3、自定义文本拼接的功能

效果图:
在这里插入图片描述

参考代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;
using static UnityEditor.IMGUI.Controls.PrimitiveBoundsHandle;
using static UnityEngine.GraphicsBuffer;
using static UnityEngine.UI.Image;[CanEditMultipleObjects]
[CustomEditor(typeof(Transform))]
public class TransformEditor : Editor
{static public Editor instance;Transform m_Transform;private bool extensionBool;string axisName = "Local";bool isAxis = false;bool isDefined = false;string row1;string row2;string row3;string row4;//当前的本地坐标SerializedProperty mPos;//当前的本地旋转SerializedProperty mRot;//当前的本地缩放SerializedProperty mScale;private void OnEnable(){instance = this;var editorType = Assembly.GetAssembly(typeof(Editor)).GetTypes().FirstOrDefault(m => m.Name == "TransformInspector");instance = CreateEditor(targets, editorType);isAxis = EditorPrefs.GetBool("isAxis");isDefined = EditorPrefs.GetBool("isDefined");m_Transform = this.target as Transform;if (this){try{var so = serializedObject;mPos = so.FindProperty("m_LocalPosition");mRot = so.FindProperty("m_LocalRotation");mScale = so.FindProperty("m_LocalScale");}catch { }}}private void OnDisable(){EditorPrefs.SetBool("extensionBool", extensionBool);EditorPrefs.SetBool("isDefined", isDefined);}public override void OnInspectorGUI(){instance.OnInspectorGUI();extensionBool = EditorPrefs.GetBool("extensionBool");extensionBool = EditorGUILayout.Foldout(extensionBool, "拓展功能");if (extensionBool){OnTopGUI();OnTransformGUI();OnPositionGUI();OnRotationGUI();OnScaleGUI();OnDefindGUI();}}void OnTopGUI(){EditorGUILayout.BeginHorizontal();GUILayout.Label("Name");if (GUILayout.Button("Local/Global")){isAxis = !isAxis;EditorPrefs.SetBool("isAxis", isAxis);}axisName = isAxis ? "Local" : "Global";GUILayout.Label("当前坐标轴:" + axisName);EditorGUILayout.EndHorizontal();}void OnTransformGUI(){EditorGUILayout.BeginHorizontal();GUILayout.Label("Transform");if (GUILayout.Button("Copy")){var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();s.Append("Transform_");if (isAxis){s.Append(FormatVe3(m_Transform.localPosition) + "_");s.Append(FormatVe3(m_Transform.localRotation.eulerAngles) + "_");s.Append(FormatVe3(m_Transform.localScale));}else{s.Append(FormatVe3(m_Transform.position) + "_");s.Append(FormatVe3(m_Transform.rotation.eulerAngles) + "_");s.Append(FormatVe3(m_Transform.localScale));}UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();}if (GUILayout.Button("Paste")){if (isDefined){Debug.LogError("不支持自定义文本!");UnityEngine.GUIUtility.systemCopyBuffer = "";return;}string s = UnityEngine.GUIUtility.systemCopyBuffer;string[] sArr = s.Split('_');if (sArr[0] != "Transform" || s == ""){Debug.LogError("未复制Transform组件内容!");return;}try{m_Transform.position = ParseV3(sArr[1]);m_Transform.rotation = Quaternion.Euler(ParseV3(sArr[2]));m_Transform.localScale = ParseV3(sArr[3]);}catch (System.Exception ex){Debug.LogError(ex);return;}}if (GUILayout.Button("Reset")){m_Transform.position = Vector3.zero;m_Transform.rotation = Quaternion.identity;m_Transform.localScale = Vector3.one;}EditorGUILayout.EndHorizontal();}void OnPositionGUI(){EditorGUILayout.BeginHorizontal();GUILayout.Label("Position");if (GUILayout.Button("Copy")){var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();if (isAxis){s.Append(FormatVe3(m_Transform.localPosition));}else{s.Append(FormatVe3(m_Transform.position));}UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();Debug.Log(s);}if (GUILayout.Button("Paste")){if (isDefined){Debug.LogError("不支持自定义文本!");UnityEngine.GUIUtility.systemCopyBuffer = "";return;}string s = UnityEngine.GUIUtility.systemCopyBuffer;if (s == ""){Debug.LogError("未复制Position内容!");return;}try{m_Transform.position = ParseV3(s);}catch (System.Exception ex){Debug.LogError(ex);return;}}if (GUILayout.Button("Reset")){m_Transform.position = Vector3.zero;}EditorGUILayout.EndHorizontal();}void OnRotationGUI(){EditorGUILayout.BeginHorizontal();GUILayout.Label("Rotation");if (GUILayout.Button("Copy")){var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();if (isAxis){s.Append(FormatVe3(m_Transform.localRotation.eulerAngles));}else{s.Append(FormatVe3(m_Transform.rotation.eulerAngles));}UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();}if (GUILayout.Button("Paste")){if (isDefined){Debug.LogError("不支持自定义文本!");UnityEngine.GUIUtility.systemCopyBuffer = "";return;}string s = UnityEngine.GUIUtility.systemCopyBuffer;if (s == ""){Debug.LogError("未复制Rotation内容!");return;}try{m_Transform.rotation = Quaternion.Euler(ParseV3(s));}catch (System.Exception ex){Debug.LogError(ex);return;}}if (GUILayout.Button("Reset")){m_Transform.rotation = Quaternion.identity;}EditorGUILayout.EndHorizontal();}void OnScaleGUI(){EditorGUILayout.BeginHorizontal();GUILayout.Label("Scale");if (GUILayout.Button("Copy")){var select = Selection.activeGameObject;if (select == null)return;StringBuilder s = new StringBuilder();s.Append(FormatVe3(m_Transform.localScale));UnityEngine.GUIUtility.systemCopyBuffer = s.ToString();}if (GUILayout.Button("Paste")){if (isDefined){Debug.LogError("不支持自定义文本!");UnityEngine.GUIUtility.systemCopyBuffer = "";return;}string s = UnityEngine.GUIUtility.systemCopyBuffer;if (s == ""){Debug.LogError("未复制Scale内容!");return;}try{m_Transform.localScale = ParseV3(s);}catch (System.Exception ex){Debug.LogError(ex);return;}}if (GUILayout.Button("Reset")){m_Transform.localScale = Vector3.one;}EditorGUILayout.EndHorizontal();}void OnDefindGUI(){GUILayout.BeginVertical();isDefined = GUILayout.Toggle(isDefined, "启用自定义文本拼接");if (isDefined){GUILayout.BeginHorizontal();row1 = GUILayout.TextField(row1);GUILayout.Label("X");row2 = GUILayout.TextField(row2);GUILayout.Label("Y");row3 = GUILayout.TextField(row3);GUILayout.Label("Z");row4 = GUILayout.TextField(row4);GUILayout.EndHorizontal();}GUILayout.EndVertical();}// x,y,zVector3 ParseV3(string strVector3){string[] s = strVector3.Split(',');return new Vector3(float.Parse(s[0]), float.Parse(s[1]), float.Parse(s[2]));}// x,y,zstring FormatVe3(Vector3 ve3){string str;if (!isDefined){str = ve3.x + "," + ve3.y + "," + ve3.z;}else{str = row1 + ve3.x + row2 + ve3.y + row3 + ve3.z + row4;}return str;}
}

三、后记

如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多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和坑,让后来人可以有些参考。

相关文章:

【Unity3D编辑器开发】Unity3D中实现Transform组件拓展,快速复制、粘贴、复原【非常实用】

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在开发中&#xff0c;常常会遇到频繁复制粘贴物体的坐标、旋转…...

求解仿射变换矩阵

仿射变换是图形学中经常用到的方法&#xff0c;通常但是仿射变换的系数是未知的&#xff0c;需要找到变换前后的三对对应点进行求解。 from affine import Affine import numpy as np参考文献 矩阵最小二乘法求解仿射变换矩阵 def solve_affine(init_points, goal_points) -&…...

【每日一题】—— 最大素因子

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…...

【JavaEE】JUC 常见的类 -- 多线程篇(8)

JUC 常见的类 1. Callable 接口2. ReentrantLock3. 原子类4. 线程池5. 信号量 Semaphore6. CountDownLatch 1. Callable 接口 Callable Interface 也是一种创建线程的方式 Runnable 能表示一个任务 (run方法) – 返回 voidCallable 也能表示一个任务(call方法) 返回一个具体的…...

java项目运行时信息获取

大体思路如下&#xff0c;想要获取启动时处理器数量、jvm 相关信息&#xff0c;操作系统信息、运行机器信息 运行机器信息 import org.slf4j.Logger; import org.slf4j.LoggerFactory;import java.lang.invoke.MethodHandles;/*** 机器工具类*/ public abstract class ServerU…...

【LeetCode】71. 简化路径

1 问题 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请你将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中&#xff0c;一个点&#xff08;.&#xff09;表示当前目录本身&#xf…...

操作系统【OS】进程的控制【进程的创建、终止、阻塞、唤醒】

定义和过程 对应事件 创建 允许一个进程创建另一个进程允许子进程继承父进程所拥有的资源创建进程的过程如下&#xff1a; 申请一个空白的 PCB&#xff0c;并向 PCB 中填写一些控制和管理进程的信息&#xff0c;比如进程的唯一标识等&#xff1b;为该进程分配运行时所必需的…...

写一个简单的解释器(2) 构建标记流

确定标记类型 分为几个大类&#xff1a; 用户符号&#xff08;类型/标识符/数字/字符串…)关键字 (流程控制和定义符)括号 &#xff08;这里暂时认为 [] 属于括号&#xff09;分号 上述四类标记基本囊括了 vc \texttt{vc} vc 中的所有最小单元的类型&#xff0c;但是因为构…...

Leetcode1833. 雪糕的最大数量

Every day a Leetcode 题目来源&#xff1a;1833. 雪糕的最大数量 解法1&#xff1a;贪心 排序 本题唯一的难点在于计数排序。 计数排序详解&#xff1a;C算法之计数排序 为了尽可能多的买到雪糕&#xff0c;我们选择从价格低的雪糕开始买&#xff0c;统计能够买到的雪糕…...

idea 里 没有svn选项的处理办法

总结一下没有svn选项的几种情况&#xff1a; 情况1&#xff1a;IntelliJ IDEA打开带SVN信息的项目不显示SVN信息&#xff0c;项目右键SVN以及图标还有Changes都不显示解决方法 在VCS菜单中有个开关&#xff0c;叫Enabled Version Control Integration&#xff0c;在打开的窗口…...

基于SpringBoot的招生管理系统

基于SpringBoot的招生管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 登录界面 管理员界面 用户界面 摘要 基于SpringBoot的招生管理系统是一款现…...

01、MySQL-------性能优化

目录 一、影响性能的相关因素存储过程&#xff1a; 二、sql优化1>、Mysql系统架构2>、引擎区别&#xff1a; 3>、索引1、什么是索引&#xff1f;联合主键索引理解&#xff1a;索引长度理解&#xff1a;什么是慢查询&#xff1f; 1&#xff09;、索引理解2&#xff09;…...

Flutter - APP跳转高德、百度、腾讯、谷歌地图

demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新&#xff0c;请前往github查看最新代码 这里介绍的是不需要自己开发地图&#xff0c;直接通过给定的经纬度&#xff0c;跳转到三方地图APP调用导航的方式 一种是写的工具类&#xff0c;一种是通过调用三方…...

Flyway Desktop updated

Flyway Desktop updated 为比较工件序列化和反序列化添加了额外的调试日志记录。 Flyway Desktop现在将记住以前用于创建项目和匹配克隆的位置。 新的脱机许可工作流现在已在Microsoft Windows上启用。 现在&#xff0c;在配置目标数据库列表时&#xff0c;环境ID是可见的。 现…...

阿里云短信服务设置操作项目

在这里插入图片描述...

学习笔记|串口通信实战|简易串口控制器|sprintf函数|STC32G单片机视频开发教程(冲哥)|第二十一集(下):串口与PC通信

目录 3.串口通信实战实操简易的工作原理Tips:sprintf函数简介 总结课后练习 3.串口通信实战 做一个简易串口控制器。发送对应指令&#xff0c;让板子做相应的事情&#xff0c;或者传输数据&#xff08;文本模式下发送&#xff0c;不要选择HEX&#xff09;。 1.串口发送字符Ax\…...

卷积神经网络CNN学习笔记-卷积计算Conv2D函数的理解

目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.Conv2D函数解析9.conv2d代码9.1 stride19.2 stride2 参考文章 1.全连接层存在的问题 在全连接层中&#xff0c;相邻层的神经元全部连接…...

收藏,安装报错信息汇总,MacOS上安装Adobe等软件/插件报错问题解决合集

打开允许“允许任何来源” 如何打开允许任何来源&#xff1f;在 Finder 菜单栏选择 【前往】 – 【实用工具 】&#xff0c;找到【终端】程序&#xff0c;双击打开&#xff0c;在终端窗口中输入&#xff1a;sudo spctl --master-disable 输入代码后&#xff0c;按【return 回车…...

Qt 报错:munmap_chunk(): invalid pointer解决方案

问题 在用Qt写程序的时候。报了munmap_chunk(): invalid pointer这个错误消息。 造成原因 在 Qt 程序中&#xff0c;这种错误可能出现在多种情况下&#xff0c;以下几点是容易造成此问题的原因&#xff1a; 函数未实现返回值&#xff1a;函数有返回值&#xff0c;但函数体中…...

【Java题】实现继承和多态的例子

一&#xff1a;题目 1.员工类Employee&#xff1a; &#xff08;1&#xff09;私有成员变量&#xff1a;姓名&#xff0c;年龄&#xff0c;工资 &#xff08;2&#xff09;提供无参&#xff0c;有参构造 &#xff08;3&#xff09;成员方法&#xff1a;work()方法——员工工作 …...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...