Unity-微信截图功能简单复刻-03绘制空心矩形

思路-绘制空心矩形

拓展UGUI的Graphic类,实现拖拽接口。

开始拖拽时记录鼠标位置,

使用拖拽中的鼠标位置和记录的位置,计算矩形顶点,绘制矩形。

两个三角形合并为一个矩形,作为空心矩形的一条边,四个边合并为空心矩形。

示例-绘制空心矩形

csharp 复制代码
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class TestDraw : Graphic, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    UIVertex[] rectangle1 = new UIVertex[4];
    UIVertex[] rectangle2 = new UIVertex[4];
    UIVertex[] rectangle3 = new UIVertex[4];
    UIVertex[] rectangle4 = new UIVertex[4];

    [SerializeField] float width = 5f;

    Vector3 lastPoint;

    protected override void Awake()
    {
        Init(rectangle1);
        Init(rectangle2);
        Init(rectangle3);
        Init(rectangle4);
        void Init(UIVertex[] uIVertices)
        {
            var length = uIVertices.Length;
            for (int i = 0; i < length; i++)
                uIVertices[i] = new UIVertex();
        }
    }

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        vh.AddUIVertexQuad(rectangle1);
        vh.AddUIVertexQuad(rectangle2);
        vh.AddUIVertexQuad(rectangle3);
        vh.AddUIVertexQuad(rectangle4);
    }

    public void ClearDraw()
    {
        Clear(rectangle1);
        Clear(rectangle2);
        Clear(rectangle3);
        Clear(rectangle4);
        void Clear(UIVertex[] uIVertices)
        {
            var length = uIVertices.Length;
            for (int i = 0; i < length; i++)
                uIVertices[i].position = Vector3.zero;
        }
        SetVerticesDirty();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        lastPoint = ScreenPointToLocalPoint(rectTransform, eventData.position);
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector3 point = ScreenPointToLocalPoint(rectTransform, eventData.position);

        if (lastPoint.x < point.x && lastPoint.y < point.y)//起点在左下角
        {
            //水平方向投影向量           
            var horizontalNormal = Vector3.Project(point - lastPoint, Vector3.right);
            SetRectangleVertex(point - horizontalNormal, point, lastPoint + horizontalNormal, lastPoint);
            SetRectangleColor(color);
            SetVerticesDirty();
        }
        else if (lastPoint.x > point.x && lastPoint.y > point.y)//起点在右上角
        {
            var horizontalNormal = Vector3.Project(point - lastPoint, Vector3.right);
            SetRectangleVertex(lastPoint + horizontalNormal, lastPoint, point - horizontalNormal, point);
            SetRectangleColor(color);
            SetVerticesDirty();
        }
        else if (lastPoint.x > point.x && lastPoint.y < point.y)//起点在右下角
        {
            var horizontalNormal = Vector3.Project(point - lastPoint, Vector3.right);
            SetRectangleVertex(point, point - horizontalNormal, lastPoint, lastPoint + horizontalNormal);
            SetRectangleColor(color);
            SetVerticesDirty();
        }
        else if (lastPoint.x < point.x && lastPoint.y > point.y)//起点在左上角
        {
            var horizontalNormal = Vector3.Project(point - lastPoint, Vector3.right);
            SetRectangleVertex(lastPoint, lastPoint + horizontalNormal, point, point - horizontalNormal);
            SetRectangleColor(color);
            SetVerticesDirty();
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        lastPoint = Vector3.zero;
    }

    void SetRectangleVertex(Vector3 topLeftUp, Vector3 topRigthUp, Vector3 bottomRightDown, Vector3 bottomLeftDown)
    {
        //top矩形
        rectangle1[0].position = topLeftUp;
        rectangle1[1].position = topRigthUp;
        rectangle1[2].position = topRigthUp - Vector3.up * width;
        rectangle1[3].position = topLeftUp - Vector3.up * width;

        //bottom矩形
        rectangle2[0].position = bottomRightDown;
        rectangle2[1].position = bottomLeftDown;
        rectangle2[2].position = bottomLeftDown + Vector3.up * width;
        rectangle2[3].position = bottomRightDown + Vector3.up * width;

        //left矩形
        rectangle3[0].position = topLeftUp - Vector3.up * width;
        rectangle3[1].position = topLeftUp - Vector3.up * width + Vector3.right * width;
        rectangle3[2].position = bottomLeftDown + Vector3.up * width + Vector3.right * width;
        rectangle3[3].position = bottomLeftDown + Vector3.up * width;

        //right矩形
        rectangle4[0].position = topRigthUp - Vector3.up * width;
        rectangle4[1].position = bottomRightDown + Vector3.up * width;
        rectangle4[2].position = bottomRightDown + Vector3.up * width - Vector3.right * width;
        rectangle4[3].position = topRigthUp - Vector3.up * width - Vector3.right * width;
    }

    void SetRectangleColor(Color color)
    {
        var length = rectangle1.Length;
        for (int i = 0; i < length; i++)
            rectangle1[i].color = color;
        length = rectangle2.Length;
        for (int i = 0; i < length; i++)
            rectangle2[i].color = color;
        length = rectangle3.Length;
        for (int i = 0; i < length; i++)
            rectangle3[i].color = color;
        length = rectangle4.Length;
        for (int i = 0; i < length; i++)
            rectangle4[i].color = color;
    }

    Vector2 ScreenPointToLocalPoint(RectTransform rect, Vector2 mousePoint)
    {
        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;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
            ClearDraw();
    }
}

场景结构

TestDraw对象挂载TestDraw脚本,该对象需要CanvsRenderer脚本,大小为屏幕大小

运行结果

上方为矩形网格

运行,拖拽鼠标显示矩形。

按下空格键,清除矩形。

知识点

三角形的绘制需要三个顶点,三角形使用顺时针的顺序进行绘制。

其他几何图形的绘制思路

线:多个矩形组合而成

箭头:一个三角形,一个矩形组合而成。

空心椭圆:获取两个圆上的顶点,按照顺序绘制三角形。

椭圆绘制思路:已知圆心,半径

将圆划分多份,利用三角函数和弧度获取x坐标,y坐标。

将x,y坐标缩放,可得到椭圆上的点。

相关推荐
程序员茶馆2 小时前
【unity】Vulkan模式下部分Android机型使用VideoPlayer组件播放视频异常问题
游戏·unity·游戏引擎·图形渲染·unity3d·游戏开发
虾球xz3 小时前
游戏引擎学习第238天:让 OpenGL 使用我们的屏幕坐标
学习·游戏引擎
李詹5 小时前
防护接入新纪元:DeepSeek攻防大脑如何重塑网络安全防线
网络·安全·web安全·游戏引擎·游戏程序
benben04412 小时前
Unity3D仿星露谷物语开发36之锄地动画2
游戏·ui·unity·游戏引擎
zdsji13 小时前
从零开始物理引擎(六)- 重构完成与MVP理解
c++·算法·重构·ue5·游戏引擎
虾球xz15 小时前
游戏引擎学习第231天
c++·学习·算法·游戏引擎
人生不过一瞬间19 小时前
Unity webgl 获取图片或视频数据
unity·lucene·webgl
Tockm1 天前
微信、抖音、小红书emoji符号大全
微信
虾球xz1 天前
游戏引擎学习第234天:实现基数排序
c++·学习·算法·游戏引擎