33.HandleUtility

33.Scene窗口拓展-HandleUtility


33.1 知识点

获取窗口上鼠标位置

Event.current.mousePosition

HandleUtility公共类的主要作用

HandleUtility是 Unity 中的一个工具类,用于处理场景中的编辑器句柄(Handles)以及其他一些与编辑器交互相关的功能。它提供了一系列静态方法,用于处理编辑器中的鼠标交互、坐标转换以及其他与Handles相关的功能。

HandleUtility类中的常用API

1. GetHandleSize(Vector3 position)

我们之前已经使用过的API,获取在场景中给定位置的句柄的合适尺寸。这个方法通常用于根据场景中对象的距离来调整句柄的大小,以便在不同的缩放级别下保持合适的显示大小。

private void OnSceneGUI()
{
    // 1.GetHandleSize(Vector3 position)  之前学习过 所以不需要举例
}

2. WorldToGUIPoint(Vector3 worldPosition)

将世界坐标转换为 GUI 坐标。这个方法通常用于将场景中的某个点的位置转换为屏幕上的像素坐标,以便在 GUI 中绘制相关的信息。

private void OnSceneGUI()
{
    // 2.WorldToGUIPoint(Vector3 worldPosition)
    Vector2 pos = HandleUtility.WorldToGUIPoint(testSceneMono.transform.position);
    Handles.BeginGUI();
    // 测试按钮可以一直跟着对象移动
    GUI.Button(new Rect(pos.x, pos.y, 50, 20), "测试按钮");
    Handles.EndGUI();
}

3. GUIPointToWorldRay(Vector2 position)

将屏幕上的像素坐标转换为射线。这个方法通常用于从屏幕坐标中获取一条射线,用于检测场景中的物体或进行射线投射。

private void OnSceneGUI()
{
    // 3.GUIPointToWorldRay(Vector2 position)
    Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
    RaycastHit info;
    if (Physics.Raycast(ray, out info))
        Debug.Log(info.collider.name);
}

4. DistanceToLine(Vector3 lineStart, Vector3 lineEnd)

计算场景中一条线段与鼠标光标的最短距离。可以用来制作悬停变色等功能。

private void OnSceneGUI()
{
    // 4.DistanceToLine(Vector3 lineStart, Vector3 lineEnd)
    float dis = HandleUtility.DistanceToLine(Vector3.zero, Vector3.right);
    // Debug.Log("和向右的单位线段的距离"+ dis);
}

5. PickGameObject(Vector2 position, bool isSelecting)

在编辑器中进行对象的拾取。这个方法通常用于根据鼠标光标位置获取场景中的对象,以实现对象的选择或交互操作。

private void OnSceneGUI()
{
    // 5.PickGameObject(Vector2 position, bool isSelecting)
    GameObject testObj = HandleUtility.PickGameObject(Event.current.mousePosition, true);
    if (testObj != null)
        Debug.Log("选择对象的名字:" + testObj.name);
}

更多内容

官方文档:HandleUtility Class (Unity Documentation)


33.2 知识点代码

Lesson33_Scene窗口拓展_HandleUtility

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson33_Scene窗口拓展_HandleUtility : MonoBehaviour
{
    void Start()
    {
        #region 知识回顾 获取窗口上鼠标位置

        //Event.current.mousePosition

        #endregion

        #region 知识点一 HandleUtility公共类的主要作用

        //HandleUtility是 Unity 中的一个工具类
        //用于处理场景中的编辑器句柄(Handles)以及其他一些与编辑器交互相关的功能
        //它提供了一系列静态方法,用于处理编辑器中的鼠标交互、坐标转换以及其他与Handles相关的功能

        #endregion

        #region 知识点二 HandleUtility类中的常用API

        //1.GetHandleSize(Vector3 position)
        //  我们之前已经使用过的API
        //  获取在场景中给定位置的句柄的合适尺寸
        //  个方法通常用于根据场景中对象的距离来调整句柄的大小,以便在不同的缩放级别下保持合适的显示大小

        //2.WorldToGUIPoint(Vector3 worldPosition)
        //  将世界坐标转换为 GUI 坐标
        //  这个方法通常用于将场景中的某个点的位置转换为屏幕上的像素坐标
        //  以便在 GUI 中绘制相关的信息

        //3.GUIPointToWorldRay(Vector2 position)
        //  将屏幕上的像素坐标转换为射线
        //  这个方法通常用于从屏幕坐标中获取一条射线,用于检测场景中的物体或进行射线投射

        //4.DistanceToLine(Vector3 lineStart, Vector3 lineEnd)
        //  计算场景中一条线段与鼠标光标的最短距离
        //  可以用来制作悬停变色等功能

        //5.PickGameObject(Vector2 position, bool isSelecting)
        //  在编辑器中进行对象的拾取
        //  这个方法通常用于根据鼠标光标位置获取场景中的对象,以实现对象的选择或交互操作

        #endregion

        #region 知识点三 更多内容

        //官方文档:https://docs.unity3d.com/ScriptReference/HandleUtility.html

        #endregion
    }
}

TestSceneMonoEditor

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(TestSceneMono))]
public class TestSceneMonoEditor : Editor
{
    private TestSceneMono testSceneMono;

    private void OnEnable()
    {
        testSceneMono = target as TestSceneMono;
    }


    private void OnSceneGUI()
    {
        //选中挂载TestSceneMono的对象会打印
        // Debug.Log("Scene窗口拓展相关逻辑");

        #region Lesson28_Scene窗口拓展_Handles_文本线段虚线

        //颜色
        Handles.color = new Color(0, 1, 0, 1f);

        //文本
        Handles.Label(testSceneMono.transform.position, "测试文本显示");

        //线段
        Handles.DrawLine(testSceneMono.transform.position,
            testSceneMono.transform.position + testSceneMono.transform.right * 5, 5);

        //虚线
        Handles.color = new Color(0, 0, 1, 1f);
        Handles.DrawDottedLine(testSceneMono.transform.position,
            testSceneMono.transform.position + testSceneMono.transform.forward * 5, 5);

        #endregion

        #region Lesson29_Scene窗口拓展_Handles_弧线圆立方体几何体

        //弧线(圆弧)
        Handles.color = Color.white;
        //如果向圆弧跟着对象动,第二个参数传入本地坐标 例如testSceneMono.transform.up,
        Handles.DrawWireArc(testSceneMono.transform.position, Vector3.up, testSceneMono.transform.forward, 30, 5);
        // Handles.DrawSolidArc(testSceneMono.transform.position, Vector3.up, testSceneMono.transform.forward, 30, 4);
        //向左旋转15度 这样以人物正前方为等分
        Handles.DrawSolidArc(testSceneMono.transform.position, testSceneMono.transform.up,
            Quaternion.Euler(0, -15, 0) * testSceneMono.transform.forward, 30, 4);


        //圆
        Handles.color = Color.gray;
        Handles.DrawSolidDisc(testSceneMono.transform.position, testSceneMono.transform.up, 2);
        Handles.DrawWireDisc(testSceneMono.transform.position, testSceneMono.transform.up, 3);

        //立方体
        Handles.color = Color.red;
        Handles.DrawWireCube(testSceneMono.transform.position, Vector3.one);


        //几何体
        //(0,0,0)
        //(1,0,0)
        //(1,0,1)
        //(0,0,z)
        Handles.DrawAAConvexPolygon(Vector3.zero, Vector3.right, Vector3.right + Vector3.forward, Vector3.forward);

        #endregion

        #region Lesson30_Scene窗口拓展_Handles_移动旋转缩放

        //移动
        //可以在选择其他默认不显示移动坐标轴工具栏也显示移动轴 以下两个API作用一致
        //注意:假如传入Vector.zero 或者 Quaternion.identity这种写死的全局值,移动轴是不会跟着对象动的
        testSceneMono.transform.position =
            Handles.DoPositionHandle(testSceneMono.transform.position, testSceneMono.transform.rotation);
        //testSceneMono.transform.position = Handles.PositionHandle(testSceneMono.transform.position, testSceneMono.transform.rotation);

        //旋转
        testSceneMono.transform.rotation =
            Handles.DoRotationHandle(testSceneMono.transform.rotation, testSceneMono.transform.position);
        //testSceneMono.transform.rotation = Handles.RotationHandle(testSceneMono.transform.rotation, testSceneMono.transform.position);


        //缩放
        //最后一个参数的括号中传入Vector3.zero的话,缩放轴不会变化,传入testSceneMono.transform.position缩放轴长短会随对象位置变化
        testSceneMono.transform.localScale = Handles.DoScaleHandle(testSceneMono.transform.localScale,
            testSceneMono.transform.position, testSceneMono.transform.rotation,
            HandleUtility.GetHandleSize(testSceneMono.transform.position));

        //testSceneMono.transform.localScale = Handles.ScaleHandle(testSceneMono.transform.localScale, testSceneMono.transform.position, testSceneMono.transform.rotation,
        //                                                 HandleUtility.GetHandleSize(Vector3.zero));

        #endregion

        #region Lesson31_Scene窗口拓展_Handles_自由移动自由旋转

        //自由移动
        //会始终绘制一个矩形对着摄像机 鼠标按下在矩形范围内可以自由移动对象
        testSceneMono.transform.position = Handles.FreeMoveHandle(testSceneMono.transform.position,
            HandleUtility.GetHandleSize(testSceneMono.transform.position),
            Vector3.one * 5, Handles.RectangleHandleCap);

        //自由旋转
        //会始终绘制一个圆形对着摄像机 鼠标按下在圆形范围内可以自由旋转对象
        testSceneMono.transform.rotation = Handles.FreeRotateHandle(testSceneMono.transform.rotation, Vector3.zero,
            HandleUtility.GetHandleSize(Vector3.zero));

        #endregion

        #region Lesson32_Scene窗口拓展_Handles_显示GUI

        Handles.BeginGUI();

        if (GUILayout.Button("测试按钮"))
        {
            Debug.Log("Scene中的按钮响应");
        }

        //得到宽高可以精确设置需要显示的控件在Scene窗口的哪里
        float w = SceneView.currentDrawingSceneView.position.width;
        float h = SceneView.currentDrawingSceneView.position.height;

        GUILayout.BeginArea(new Rect(w - 100, h - 100, 100, 100));
        GUILayout.Label("测试文本控件显示");
        if (GUILayout.Button("测试按钮"))
        {
            Debug.Log("Scene中的按钮响应");
        }

        GUILayout.EndArea();

        Handles.EndGUI();

        #endregion

        #region Lesson33_Scene窗口拓展_HandleUtility

        //1.GetHandleSize(Vector3 position)
        //  之前学习过 所以不需要举例

        //2.WorldToGUIPoint(Vector3 worldPosition)
        Vector2 pos = HandleUtility.WorldToGUIPoint(testSceneMono.transform.position);
        Handles.BeginGUI();
        //测试按钮可以一直跟着对移动
        GUI.Button(new Rect(pos.x, pos.y, 50, 20), "测试按钮");
        Handles.EndGUI();

        //3.GUIPointToWorldRay(Vector2 position)
        Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
        RaycastHit info;
        if (Physics.Raycast(ray, out info))
            Debug.Log(info.collider.name);

        //4.DistanceToLine(Vector3 lineStart, Vector3 lineEnd)
        float dis = HandleUtility.DistanceToLine(Vector3.zero, Vector3.right);
        // Debug.Log("和向右的单位线段的距离"+ dis);

        //5.PickGameObject(Vector2 position, bool isSelecting)
        GameObject testObj = HandleUtility.PickGameObject(Event.current.mousePosition, true);
        if (testObj != null)
            Debug.Log("选择对象的名字:" + testObj.name);

        #endregion
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏