描述
点击鼠标左键在屏幕上绘制线段
准备
- VertexHelper 网格绘制工具类
- 向量、叉乘
- RectTransformUtility.ScreenPointToLocalPointInRectangle
- SetVerticesDirty
- OnPopulateMesh
思路
- 鼠标按下,记录线段起点;
- 鼠标持续按下,记录鼠标当前帧的移动向量;
- 使用叉乘获取垂直与移动向量的单位向量;
- 根据设置的宽度获取四个顶点;设置顶点脏数据,更新网格
示例
新建脚本,继承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();//设置顶点脏数据 更新网格
}
}
}