UGUI 绘制线段

描述

点击鼠标左键在屏幕上绘制线段

准备

  1. VertexHelper 网格绘制工具类
  2. 向量、叉乘
  3. RectTransformUtility.ScreenPointToLocalPointInRectangle
  4. SetVerticesDirty
  5. OnPopulateMesh

思路

  1. 鼠标按下,记录线段起点;
  2. 鼠标持续按下,记录鼠标当前帧的移动向量;
  3. 使用叉乘获取垂直与移动向量的单位向量;
  4. 根据设置的宽度获取四个顶点;设置顶点脏数据,更新网格

示例

新建脚本,继承MaskableGraphic;
创建一个Image,移除Image组件,添加新建脚本。
脚本内容如下:

引入命名空间

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

属性

private List<List<UIVertex>> vertexList = new List<List<UIVertex>>();//缓存线段上的网格顶点
private Vector3 lastPoint;//上一帧的点击点
private Vector3 lastLeftPoint;
private Vector3 lastRightPoint;
bool isNewLine;//绘制新的线段
[SerializeField] private float lineWidth = 4f;//线段宽度

方法 绘制网格

protected override void OnPopulateMesh(VertexHelper vh)//绘制网格
{
    
    
    vh.Clear();
    for (int i = 0; i < vertexList.Count; i++)
        vh.AddUIVertexQuad(vertexList[i].ToArray());
}

方法 屏幕坐标转为本地坐标

Vector2 ScreenPointToLocalPoint(Vector2 mousePoint)
{
    
    
    var Rect = GetComponent<RectTransform>();
    Vector2 result = Vector2.zero;
    switch (canvas.renderMode)
    {
    
    
        case RenderMode.ScreenSpaceOverlay:
            RectTransformUtility.ScreenPointToLocalPointInRectangle(Rect, mousePoint, null, out result);
            break;
        case RenderMode.ScreenSpaceCamera:
            RectTransformUtility.ScreenPointToLocalPointInRectangle(Rect, mousePoint, canvas.worldCamera, out result);
            break;
        case RenderMode.WorldSpace:
            RectTransformUtility.ScreenPointToLocalPointInRectangle(Rect, mousePoint, canvas.worldCamera, out result);
            break;
    }
    return result;
}

方法 设置网格顶点

private void Update()
{
    
    
    if (Input.GetMouseButtonDown(0))//按下鼠标坐标表示 绘制新的线段
    {
    
    
        lastPoint = ScreenPointToLocalPoint(Input.mousePosition);//屏幕点转换到当前recttransform上的点
        isNewLine = true;
        vertexList.Clear();//清除上一次绘制的线段 若要保留 可不清除
    }
    else
    {
    
    
        if (Input.GetMouseButton(0))
        {
    
    
            Vector3 currentPoint = ScreenPointToLocalPoint(Input.mousePosition);
            Vector3 dir = currentPoint - lastPoint;//移动向量
            if (dir.magnitude < 10)//移动量过小 不绘制网格
                return;
            Vector3 normal = Vector3.Cross(dir.normalized, transform.forward);//移动向量和当前ui的朝向 进行叉乘
            if (isNewLine)
            {
    
    
                isNewLine = false;
                lastLeftPoint = lastPoint + normal * lineWidth;//绘制新的线段时 作为左侧起点
                lastRightPoint = lastPoint - normal * lineWidth;
            }
            Vector3 leftPoint = currentPoint + normal * lineWidth;//当前线段的左侧终点
            Vector3 rightPoint = currentPoint - normal * lineWidth;
            
            List<UIVertex> ver = new List<UIVertex>();
            UIVertex uIVertex = new UIVertex();//网格顶点列表
            uIVertex.position = lastLeftPoint;
            uIVertex.color = color;
            ver.Add(uIVertex);
            UIVertex uIVertex2 = new UIVertex();
            uIVertex2.position = lastRightPoint;
            uIVertex2.color = color;
            ver.Add(uIVertex2);
            UIVertex uIVertex3 = new UIVertex();
            uIVertex3.position = rightPoint;
            uIVertex3.color = color;
            ver.Add(uIVertex3);
            UIVertex uIVertex4 = new UIVertex();
            uIVertex4.position = leftPoint;
            uIVertex4.color = color;
            ver.Add(uIVertex4);
            vertexList.Add(ver);
            
            lastLeftPoint = leftPoint;//更新起点 当前帧的终点作为下一帧的起点
            lastRightPoint = rightPoint;
            lastPoint = currentPoint;
            SetVerticesDirty();//设置顶点脏数据 更新网格
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43796392/article/details/133276108