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

news2025/5/10 9:06:33

思路-绘制空心矩形

拓展UGUI的Graphic类,实现拖拽接口。
开始拖拽时记录鼠标位置,
使用拖拽中的鼠标位置和记录的位置,计算矩形顶点,绘制矩形。
两个三角形合并为一个矩形,作为空心矩形的一条边,四个边合并为空心矩形。

示例-绘制空心矩形

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坐标缩放,可得到椭圆上的点。

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

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

相关文章

国产品牌芯洲科技100V降压芯片系列

SCT2A25采用带集成环路补偿的恒导通时间(COT)模式控制&#xff0c;大大简化了转换器的片外配置。SCT2A25具有典型的140uA低静态电流&#xff0c;采用脉冲频率调制(PFM)模式&#xff0c;它使转换器在轻载或空载条件下实现高转换效率。 芯洲科技100V降压芯片系列提供丰富的48V系…

研一自救指南 - 07. CSS面向面试学习

最近的前端面试多多少少都会遇到css的提问&#xff0c;感觉还是要把重点内容记记背背。这里基于b站和我自己面试的情况整理。 20250418更新&#xff1a; 1. BFC Block Formatting Context&#xff0c;一个块级的盒子&#xff0c;可以创建多个。里面有很多个块&#xff0c;他们…

图灵奖得主LeCun:DeepSeek开源在产品层是一种竞争,但在基础方法层更像是一种合作;新一代AI将情感化

图片来源&#xff1a;This is World 来源 | Z Potential Z Highlights&#xff1a; 新型的AI系统是以深度学习为基础&#xff0c;能够理解物理世界并且拥有记忆、推理和规划能力的。一旦成功构建这样的系统&#xff0c;它们可能会有类似情感的反应&#xff0c;但这些情感是基…

使用Redis5.X部署一个集群

文章目录 1.用Redis5.x来创建Cluste2. 查看节点信息 nodes3. 添加节点 add-node4.删除节点 del-node5.手动指定从节点 replicate6.检查集群健康状态 check 建议使用5.x版本。 首先&#xff0c;下载Redis&#xff0c;根据自己的环境选择版本。 一键启动Redis集群文件配置。 ech…

Ubuntu Linux 中文输入法默认使用英文标点

ubuntu从wayland切换到x11, 然后安装fcitx(是fcitx4版本)和 fcitx-googlepinyin, 再sudo dpkg -i 安装百度输入法deb包. 在fcitx配置中, 附加组件,打勾高级, 取消打勾标点支持和全角字符. 百度输入法就可以默认用英文标点了. 而google拼音输入法的问题是字体大小没法保存,每…

Java漏洞原理与实战

一、基本概念 1、序列化与反序列化 (1)序列化:将对象写入IO流中&#xff0c;ObjectOutputStream类的writeobject()方法可以实现序列化 (2)反序列化:从IO流中恢复对象&#xff0c;ObjectinputStream类的readObject()方法用于反序列化 (3)意义:序列化机制允许将实现序列化的J…

第十届团体程序设计天梯赛-上理赛点随笔

2025.4.19来到军工路580号上海理工大学赛点参加cccc 校内环境挺好的&#xff0c;校内氛围也不错&#xff1b;临走前还用晚餐券顺走一袋橘子 再来说说比赛 首先是举办方服务器爆了&#xff0c;导致前10分钟刷不出题&#xff0c;一个多小时还上交不了代码 然后就是我用py总有几…

面试专栏-02-MySQL知识点(第二部分)

6、锁 1、分类&#xff1a; 全局锁&#xff1a;锁住数据库中的所有表表级锁&#xff1a;每次操作锁住整张表行级锁&#xff1a;每次操作锁住对应行的数据 2、全局锁 加锁后&#xff0c;整个实例只能进行读取操作&#xff0c;从而保证数据的完成性和一致性。 特点&#xff…

【MySQL数据库入门到精通】

文章目录 一、SQL分类二、DDL-数据库操作1.查询2.创建数据库3.删除数据库4.使用数据库 三、DDL-表操作1.查询 一、SQL分类 根据功能主要分为DDL DML DQL DCL DDL:Date Definition Language数据定义语言&#xff1a;定义数据库&#xff0c;表和字段 DML:Date Manipulatin Lan…

[Swift]pod install成功后运行项目报错问题error: Sandbox: bash(84760) deny(1)

操作&#xff1a; platform :ios, 14.0target ZKMKAPP do# Comment the next line if you dont want to use dynamic frameworksuse_frameworks!# Pods for ZKMKAPPpod Moyaend pod install成功后运行报错 报错&#xff1a; error: Sandbox: bash(84760) deny(1) file-writ…

游戏引擎学习第233天

原地归并排序地方很蒙圈 game_render_group.cpp&#xff1a;注意当前的SortEntries函数是O(n^2)&#xff0c;并引入一个提前退出的条件 其实我们不太讨论这些话题&#xff0c;因为我并没有深入研究过计算机科学&#xff0c;所以我也没有太多内容可以分享。但希望在过去几天里…

卷积神经网络基础(二)

停更好久的卷积神经网络基础知识终于开始更新了哈哈&#xff0c;今天主要介绍的是误差反向传播法。 目录 一、计算图 1.1 用计算图求解 1.2 局部计算 1.3 为什么采用计算图 二、链式法则 2.1 计算图的反向传播 2.2 链式法则 2.3 链式法则和计算图 三、反向传播 3.1 …

探索大语言模型(LLM):定义、发展、构建与应用

文章目录 引言大规模语言模型的基本概念大规模语言模型的发展历程1. 基础模型阶段&#xff08;2018年至2021年&#xff09;2. 能力探索阶段&#xff08;2019年至2022年&#xff09;3. 突破发展阶段&#xff08;以2022年11月ChatGPT的发布为起点&#xff09; 大规模语言模型的构…

树莓派超全系列教程文档--(33)树莓派启动选项

树莓派启动选项 启动选项start_file &#xff0c;fixup_filecmdlinekernelarm_64bitramfsfileramfsaddrinitramfsauto_initramfsdisable_poe_fandisable_splashenable_uartforce_eeprom_reados_prefixotg_mode &#xff08;仅限Raspberry Pi 4&#xff09;overlay_prefix配置属…

Python 爬虫解决 GBK乱码问题

文章目录 前言爬取初尝试与乱码问题编码知识科普UTF - 8GBKUnicode Python中的编码转换其他编码补充知识GBKGB18030GB2312UTF&#xff08;UCS Transfer Format&#xff09;Unicode 总结 前言 在Python爬虫的过程中&#xff0c;我尝试爬取一本小说&#xff0c;遇到GBK乱码问题&a…

解决echarts饼图label显示不全的问题

解决办法 添加如下配置&#xff1a; labelLayout: {hideOverlap: false},

JCST 2025年 区块链论文 录用汇总

Conference&#xff1a;Journal of Computer Science and Technology (JCST) CCF level&#xff1a;CCF B Categories&#xff1a;交叉/综合/新兴 Year&#xff1a;2025&#xff08;截止4.19&#xff09; JCST 2024年 区块链论文 录用汇总 1 Title: An Understandable Cro…

不带无线网卡的Linux开发板上网方法

I.MX6ULL通过网线上网 设置WLAN共享修改开发板的IP 在使用I.MX6ULL-MINI开发板学习Linux的时候&#xff0c;有时需要更新或者下载一些资源包&#xff0c;但是开发板本身是不带无线网卡或者WIFI芯片的&#xff0c;尝试使用网口连接笔记本&#xff0c;笔记本通过无线网卡连接WIFI…

选择排序(简单选择排序、堆排序)

简单选择排序&#xff08;Selection Sort&#xff09; 1. 算法思想 它通过多次遍历数组&#xff0c;每次从未排序部分中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;将其放到已排序部分的末尾&#xff08;或开头&#xff09;&#xff0c;直到整个数组有序。 2.…

velocity模板引擎

文章目录 学习链接一. velocity简介1. velocity简介2. 应用场景3. velocity 组成结构 二. 快速入门1. 需求分析2. 步骤分析3. 代码实现3.1 创建工程3.2 引入坐标3.3 编写模板3.4 输出结果示例1编写模板测试 示例2 4. 运行原理 三. 基础语法3.1 VTL介绍3.2 VTL注释3.2.1 语法3.2…