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

news2025/1/9 18:57:27

推荐阅读

  • 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,z
            s.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,z
    Vector3 ParseV3(string strVector3)
    {
        string[] s = strVector3.Split(',');
        return new Vector3(float.Parse(s[0]), float.Parse(s[1]), float.Parse(s[2]));
    }

    // x,y,z
    string 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和坑,让后来人可以有些参考。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在ASO中使用App Store的促销文本

App Store中的促销文字如何使用&#xff0c;需要填写吗&#xff1f;从名称上就可以看出&#xff0c;这是用于推广应用的广告文字&#xff0c;由于其简洁而非常方便&#xff0c;这也是向现有或潜在用户展示将会有某种事件或重要更新的好方法。表明我们积极监控应用&#xff0c;总…

【滑动窗口】“正难则反法” 解决最小操作数的问题

Problem: 1658. 将 x 减到 0 的最小操作数 文章目录 题目解析算法原理分析Code复杂度 题目解析 首先我们来解读一下本题的题目含义 题目会给到我们一个整数数组和一个整数x&#xff0c;我们可以从左侧&#xff0c;也可以从右侧去减&#xff0c;只要让这个x最终减到【0】即可。不…

算法通关村第18关【白银】| 回溯热门问题

1.组合总和问题 思路&#xff1a;回溯模板 &#xff08;1&#xff09;确定方法返回值和参数 分析可知遍历数组然后求和值&#xff0c;不需要返回什么值 参数也就是candidates&#xff0c;list&#xff0c;path&#xff0c;target&#xff0c;start &#xff08;2&#xff…

【2023研电赛】基于三维视觉感知的可重构智能表面通信方案

该作品参与极术社区组织的研电赛作品征集活动&#xff0c;欢迎同学们投稿&#xff0c;获取作品传播推广&#xff0c;并有丰富礼品哦~ 基于三维视觉感知的可重构智能表面通信方案 参赛单位&#xff1a;华北水利水电大学 参赛队伍&#xff1a;智能队 指导老师&#xff1a;邵霞 参…

服务器中了locked勒索病毒怎么办,勒索病毒解密,数据恢复

最近一段时间内&#xff0c;相信很多使用金蝶或用友的办公软件的企业&#xff0c;有很多都经历了locked勒索病毒的攻击&#xff0c;导致企业服务器被加密无法正常使用&#xff0c;严重影响了企业的正常工作。通过云天数据恢复中心的解密恢复发现&#xff0c;在今年locked勒索病…

【LeetCode(数据结构与算法)】:反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1] 示例 3&#xff1a; 输入&#xff1a;head [] 输出&#xff1a;[] …

Linux下按键驱动实验

按键驱动和LED驱动原理上来讲基本都是一样的&#xff0c;都是操作GPIO&#xff0c;只不过一个是读取GPIO的高低电平&#xff0c;一个是从GPIO输出高低电平给LED。 本实验使用的开发板是IMX6DL&#xff0c;实验中使用的按键是通过使用下图中P1的EIM_A20和VCC3.3V两个引脚实现的&…

如何选择超声波清洗机、超声波清洗机排行榜

眼镜的日常清洗生活中很多人都会把它给忘记&#xff01;长时间下来眼镜支架就会变成黄色的&#xff0c;非常的难洗掉&#xff0c;从而又浪费了一个眼镜。一副好的眼镜也不便宜的&#xff0c;把换眼镜的钱省下来入一款超声波清洗机&#xff0c;可以大大的减少金钱的支持&#xf…

java基于springboot+vue的厨房预订预约管理系统

历经长达几个月的毕业作品制作&#xff0c;我凭借自己的知识技能&#xff0c;还有大家的指导帮助&#xff0c;能够在学校规定的时间段之内提交毕业作品。虽然已经算是完成了毕业作品&#xff0c;但是付出了这么多心血&#xff0c;还是想把这个作品做得更加完美一点。针对我的毕…

如何通过内网穿透实现远程连接NAS群晖drive并挂载电脑硬盘?

文章目录 前言1.群晖Synology Drive套件的安装1.1 安装Synology Drive套件1.2 设置Synology Drive套件1.3 局域网内电脑测试和使用 2.使用cpolar远程访问内网Synology Drive2.1 Cpolar云端设置2.2 Cpolar本地设置2.3 测试和使用 3. 结语 前言 群晖作为专业的数据存储中心&…

hash join的基本原理是怎样的?

我们知道数据库里面两表关联主要有三种常见的关联方式&#xff0c;即 nested loop joinhash joinmerge join nested loop join在OLTP交易场景占比是最多的&#xff0c;常用于关联字段为主键或索引字段的情况&#xff0c;通过主键或索引以及loop的方式&#xff0c;A表可以快速…

BricsCAD 23 for Mac:轻松驾驭CAD建模的强大工具

如果你正在寻找一款功能强大、操作简便的CAD建模软件&#xff0c;那么BricsCAD 23 for Mac绝对值得你考虑。这款软件将为你提供一套完整的2D和3D设计解决方案&#xff0c;让你在Mac上轻松创建、编辑和修改图形。 一、BricsCAD 23的功能特点 高效的2D和3D建模&#xff1a;Bric…

2652. 倍数求和

2652. 倍数求和 题目方法-【枚举】 & 题目特征-【求计算在给定范围内满足某种条件的整数之和】方法-【容斥原理】 & 题目特征-【计算满足多个条件的元素之和&#xff0c;并且需要避免重复计数】 题目 题目链接&#xff1a;https://leetcode.cn/problems/sum-multiples…

倾斜摄影三维模型的根节点合并的重要性分析

倾斜摄影三维模型的根节点合并的重要性分析 倾斜摄影三维模型的根节点合并是整个模型构建过程中的一个重要环节&#xff0c;具有重要的意义和作用。本文将对倾斜摄影三维模型的根节点合并的重要性进行详细分析。 一、定义和概述 在倾斜摄影三维模型的构建过程中&#xff0c;根…

概率神经网络分类问题程序

欢迎关注“电击小子程高兴的MATLAB小屋” %% 概率神经网络 %% 解决分类问题 clear all; close all; P[1:8]; Tc[2 3 1 2 3 2 1 1]; Tind2vec(Tc) %数据类型的转换 netnewpnn(P,T); Ysim(net,P); Ycvec2ind(Y) %转换回来

一文带你认识高速低侧栅极驱动器 FAN3111ESX 带你深入了解其特点及应用

FAN3111ESX一款低端驱动器产品&#xff0c;是外部 DC 2 至 5 V 参考输入、单通道同相输出、1.4 A 峰值灌电流、1.4 A 源电流低端栅极驱动器。 FAN3111ESX 1A栅极驱动器为驱动一个在低侧开关应用中的 N沟道增强型 MOSFET 而设计。 对于使用低压控制器和其它和驱动器相比使用更…

二维码智慧门牌管理系统:地址管理的现代革命

文章目录 前言一、标准地址的革新二、广泛的应用前景 前言 在科技不断发展和社会进步的背景下&#xff0c;高效、精准、智能的管理系统已经成为当今社会的迫切需求。传统的门牌管理系统在应对这一需求方面已显得力不从心&#xff0c;因此&#xff0c;二维码智慧门牌管理系统的…

力扣每日一题43:字符串相乘

题目描述&#xff1a; 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2"…

强化学习基础(1)- 理论和算法

目录 1.基本概念 1.1组成部分 1.2 马尔可夫决策过程 2 有模型强化学习 2.1状态值函数 2.2动作值函数 2.3二者关系 2.4 探索和利用 2.5动态规划&#xff08;DP&#xff09;&#xff08;有模型求解方法&#xff09; 2.5.1预测任务 2.5.1控制任务 3.无模型强化学习 3.1 Valu…

AI全栈大模型工程师(四)OpenAI API初探

五、它是怎么生成结果的? 其实,它只是根据上文,猜下一个词(的概率)…… OpenAI 的接口名就叫「completion」,也证明了其只会「生成」的本质。 下面用程序演示「生成下一个字」。你可以自己修改 prompt 试试。还可以使用相同的 prompt 运行多次。 import openai import…