【Unity3D-UGUI应用篇】(八)Image实现画线、画三角形、画正方形、画圆

1,879 阅读6分钟

这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

推荐阅读

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

前段时间分享了UGUI的每个组件的属性和使用方法,比如Text、Button、Image、Toggle、InputField、ScrollView等等。

接着分享了UGUI的一些原理,比如说UGUI的渲染模式、UGUI的缩放计算、UGUI的描点定位、UGUI的自动布局等等。

相信大家看完后会对UGUI有一个比较全面的认识了。

下面,就继续分享UGUI的UI组件进行应用的实例。

这是本系列文章的第八篇: 【Unity3D-UGUI应用篇】(一)使用Text实现进度等待动画 【Unity3D-UGUI应用篇】(二)使用Image实现进度条动画 【Unity3D-UGUI应用篇】(三)使用UGUI实现层级菜单 【Unity3D-UGUI应用篇】(四)使用UGUI弹窗显示模型及弹窗模型交互 【Unity3D-UGUI应用篇】(五)使用Button完成鼠标移动到UI上面显示文字功能 【Unity3D-UGUI应用篇】(六)屏幕自适应(多分配率适配) 【Unity3D-UGUI应用篇】(七)UGUI实现窗口的自由拖拽 【Unity3D-UGUI应用篇】(八)Image实现画线、画三角形、画正方形、画圆

二、使用Image画线

首先,来看效果图: 在这里插入图片描述 实现: (1)搭建一个简单的UI场景: 在这里插入图片描述 让Panel覆盖整个屏幕,然后将Image宽高设置为1,在后面用代码设置宽高。

(2)编写代码DrawLine.cs

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// 挂载在Panel上
/// </summary>
public class DrawLine : MonoBehaviour, IPointerDownHandler, IDragHandler
{
    public Image image;//画线的Image
    public Vector2 rectA;//起点
    public Vector2 rectB;//终点

    //划线功能
    void DrawStraightLine(Image image, Vector2 a, Vector2 b)
    {
        float distance = Vector2.Distance(a, b);                                    //求距离
        float angle = Vector2.SignedAngle(a - b, Vector2.left);                     //求夹角
        image.GetComponent<RectTransform>().anchoredPosition = (a + b) / 2;
        image.GetComponent<RectTransform>().sizeDelta = new Vector2(distance, 5);   //长度,宽度
        image.transform.localRotation = Quaternion.AngleAxis(-angle, Vector3.forward);
    }


    public void OnPointerDown(PointerEventData eventData)
    {
        Vector2 startPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
        rectA = startPoint;
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector2 endPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
        rectB = endPoint;
        DrawStraightLine(image, rectA, rectB);
    }
}

一个起点,一个终点,然后调用UGUI的接口实现点击、拖拽等接口代码。

(3)将脚本挂载在Panel,然后将Image拖到对应卡槽中即可。 在这里插入图片描述 (4)运行程序 在这里插入图片描述

三、使用Image画三角形

先看效果图: 在这里插入图片描述 在上一个实例的基础上,修改代码完成。

因为三角形需要有三个点,三条线,所以需要在上一个实例基础上再复制两个Image出来: 在这里插入图片描述 修改DrawLine.cs代码:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// 挂载在Panel上
/// </summary>
public class DrawLine1 : MonoBehaviour, IPointerDownHandler, IDragHandler,IPointerUpHandler
{
    public Image image;//画线的Image
    public Image image1;//画线的Image
    public Image image2;//画线的Image
    private Vector2 rectOne;//第一个点
    private Vector2 rectTwo;//第二个点
    private Vector2 rectThree;//第三个点
    private int lineIndex = 0;

    //划线功能
    void DrawStraightLine(Image image, Vector2 a, Vector2 b)
    {
        float distance = Vector2.Distance(a, b);                                    //求距离
        float angle = Vector2.SignedAngle(a - b, Vector2.left);                     //求夹角
        image.GetComponent<RectTransform>().anchoredPosition = (a + b) / 2;
        image.GetComponent<RectTransform>().sizeDelta = new Vector2(distance, 5);   //长度,宽度
        image.transform.localRotation = Quaternion.AngleAxis(-angle, Vector3.forward);
    }

    void DrawStraightLine1(Image image, Vector2 a, Vector2 b)
    {
        float distance = Vector2.Distance(a, b);                                    //求距离
        float angle = Vector2.SignedAngle(a - b, Vector2.left);                     //求夹角
        image1.GetComponent<RectTransform>().anchoredPosition = (a + b) / 2;
        image1.GetComponent<RectTransform>().sizeDelta = new Vector2(distance, 5);   //长度,宽度
        image1.transform.localRotation = Quaternion.AngleAxis(-angle, Vector3.forward);
    }

    void DrawStraightLine2(Image image, Vector2 a, Vector2 b)
    {
        float distance = Vector2.Distance(a, b);                                    //求距离
        float angle = Vector2.SignedAngle(a - b, Vector2.left);                     //求夹角
        image2.GetComponent<RectTransform>().anchoredPosition = (a + b) / 2;
        image2.GetComponent<RectTransform>().sizeDelta = new Vector2(distance, 5);   //长度,宽度
        image2.transform.localRotation = Quaternion.AngleAxis(-angle, Vector3.forward);
    }


    public void OnPointerDown(PointerEventData eventData)
    {
        if (lineIndex == 0)
        {
            Vector2 startPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
            rectOne = startPoint;
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (lineIndex == 0)
        {
            lineIndex = 1;
        }
        else if (lineIndex == 1)
        {
            lineIndex = 2;
            DrawStraightLine2(image, rectThree, rectOne);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (lineIndex == 0)
        {
            Vector2 endPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
            rectTwo = endPoint;
            DrawStraightLine(image, rectOne, rectTwo);
        }
        else if(lineIndex == 1)
        {
            Vector2 endPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
            rectThree = endPoint;
            DrawStraightLine1(image, rectTwo, rectThree);
        }
    }
}

在不同的点击、拖拽状态下,画不同的线,完成三角形的绘制。

将这个脚本挂载在Panel对象上,并且拖进去不同的Image: 在这里插入图片描述 运行程序: 在这里插入图片描述

四、使用Image画四边形、正方形

先看效果图: 在这里插入图片描述 这个也是在第一个实例的继续上进行修改。

当两个点连上一条直线,送开鼠标,根据两点的距离长度,求出其他点的位置坐标然后生成四边形,如图所示: 在这里插入图片描述 修改DrawLine.cs代码:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// 挂载在Panel上
/// </summary>
public class DrawLine2 : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
    public Image image;//画线的Image
    public Image image1;//画线的Image
    public Image image2;//画线的Image
    public Image image3;//画线的Image
    private Vector2 rectOne;//第一个点
    private Vector2 rectTwo;//第二个点
    private Vector2 rectThree;//第三个点
    private Vector2 rectFour;//第四个点

    //划线功能
    void DrawStraightLine(Image image, Vector2 a, Vector2 b)
    {
        float distance = Vector2.Distance(a, b);                                    //求距离
        float angle = Vector2.SignedAngle(a - b, Vector2.left);                     //求夹角
        image.GetComponent<RectTransform>().anchoredPosition = (a + b) / 2;
        image.GetComponent<RectTransform>().sizeDelta = new Vector2(distance, 5);   //长度,宽度
        image.transform.localRotation = Quaternion.AngleAxis(-angle, Vector3.forward);
    }

    void DrawStraightLine1(Image image, Vector2 a, Vector2 b,Vector2 c,Vector2 d)
    {
        float distance = Vector2.Distance(a, b);                                    //求距离
        float angle = Vector2.SignedAngle(a - b, Vector2.left);                     //求夹角
        image.GetComponent<RectTransform>().anchoredPosition = (a + b) / 2;
        image.GetComponent<RectTransform>().sizeDelta = new Vector2(distance, 5);   //长度,宽度
        image.transform.localRotation = Quaternion.AngleAxis(-angle, Vector3.forward);

        float distance1 = Vector2.Distance(b, c);                                    //求距离
        float angle1 = Vector2.SignedAngle(b - c, Vector2.left);                     //求夹角
        image1.GetComponent<RectTransform>().anchoredPosition = (b + c) / 2;
        image1.GetComponent<RectTransform>().sizeDelta = new Vector2(distance1, 5);   //长度,宽度
        image1.transform.localRotation = Quaternion.AngleAxis(-angle1, Vector3.forward);

        float distance2 = Vector2.Distance(c, d);                                    //求距离
        float angle2 = Vector2.SignedAngle(c - d, Vector2.left);                     //求夹角
        image2.GetComponent<RectTransform>().anchoredPosition = (c + d) / 2;
        image2.GetComponent<RectTransform>().sizeDelta = new Vector2(distance2, 5);   //长度,宽度
        image2.transform.localRotation = Quaternion.AngleAxis(-angle2, Vector3.forward);

        float distance3 = Vector2.Distance(d, a);                                    //求距离
        float angle3 = Vector2.SignedAngle(d - a, Vector2.left);                     //求夹角
        image3.GetComponent<RectTransform>().anchoredPosition = (d + a) / 2;
        image3.GetComponent<RectTransform>().sizeDelta = new Vector2(distance3, 5);   //长度,宽度
        image3.transform.localRotation = Quaternion.AngleAxis(-angle3, Vector3.forward);
    }


    public void OnPointerDown(PointerEventData eventData)
    {
        Vector2 startPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
        rectOne = startPoint;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (rectOne.y - rectTwo.y > 5)
        {
            float distance = Vector2.Distance(rectOne, rectTwo);
            Vector2 c = new Vector2(rectOne.x + distance, rectOne.y);
            Vector2 d = new Vector2(rectTwo.x + distance, rectTwo.y);
            DrawStraightLine1(image, rectOne, rectTwo, d, c);
        }
        else
        {
            float distance = Vector2.Distance(rectOne, rectTwo);
            Vector2 c = new Vector2(rectOne.x , rectOne.y- distance);
            Vector2 d = new Vector2(rectTwo.x , rectTwo.y - distance);
            DrawStraightLine1(image, rectOne, rectTwo, d, c);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector2 endPoint = new Vector2(eventData.position.x - 960, eventData.position.y - 540);
        rectTwo = endPoint;
        DrawStraightLine(image, rectOne, rectTwo);
    }
}

因为四边形需要四条线,所以需要复制4个Image,然后将脚本附加到Panel身上,将Image拖入到对应的卡槽中: 在这里插入图片描述 运行程序: 在这里插入图片描述

五、使用UGUI VertexHelper画圆

先看效果图: 在这里插入图片描述 实现:

新建脚本ChartUtilsPie.cs:

using UnityEngine;
using UnityEngine.UI;

public static class ChartUtilsPie
{
    //画圆形  其实就是画三角形
    public static void DrawCircle(VertexHelper vh, Vector2 circlepoint, float r, int segments, float startdegree, float enddegree)
    {
        float startangle = startdegree * Mathf.Deg2Rad;//代表多少多少角度*1的弧度
        float angle = (enddegree - startdegree) * Mathf.Deg2Rad / segments;
        Vector2 p1, p2;
        p1 = new Vector2(circlepoint.x + r * Mathf.Sin(startangle), circlepoint.y + r * Mathf.Cos(startangle));
        for (int i = 1; i <= segments; i++)
        {
            p2 = new Vector2(circlepoint.x + r * Mathf.Sin(startangle + angle * i), circlepoint.y + r * Mathf.Cos(startangle + angle * i));
            DrawTriangle(vh, circlepoint, p1, p2, Color.red);
            p1 = p2;
        }
    }

    //画三角
    public static void DrawTriangle(VertexHelper vh, Vector3 p1, Vector3 p2, Vector3 p3, Color32 color)
    {
        UIVertex vertex1 = new UIVertex();
        vertex1.position = p1;
        vertex1.color = color;
        vertex1.uv0 = Vector2.zero;

        UIVertex vertex2 = new UIVertex();
        vertex2.position = p2;
        vertex2.color = color;
        vertex2.uv0 = Vector2.zero;

        UIVertex vertex3 = new UIVertex();
        vertex3.position = p3;
        vertex3.color = color;
        vertex3.uv0 = Vector2.zero;

        int index = vh.currentIndexCount;
        vh.AddVert(vertex1);
        vh.AddVert(vertex2);
        vh.AddVert(vertex3);
        vh.AddTriangle(index, index + 1, index + 2);
    }
}

这个脚本就是主要画圆的脚本。

通过画很多个三角形,首尾相连,组成一个圆形。

DrawTriangle画三角的函数没啥好说的,就是三个点,中心点也是圆的圆心,然后三角形的两个点,以及两个点连成的线就是圆的弧,实现过程如图所示: 在这里插入图片描述 所以,理论上这个三角形越多这个圆就越圆。

DrawCircle这个函数就是计算生成三角形的三个点。

这个三角形的中心点也就是圆点已经确定了,那么就根据中心点,然后半径,得到经过圆心的量个点,经过圆心的点的公式为:

x=a+r cosθ y=b+r sinθ(θ∈ [0,2π) ) (a,b) 为圆心坐标,r 为圆半径,θ 为参数,(x,y) 为经过点的坐标

就这样求出p1和p2的坐标值:

p1 = new Vector2(circlepoint.x + r * Mathf.Sin(startangle), circlepoint.y + r * Mathf.Cos(startangle)); p2 = new Vector2(circlepoint.x + r * Mathf.Sin(startangle + angle * i), circlepoint.y + r * Mathf.Cos(startangle + angle * i));

然后p1=p2,首尾相连,下一个三角形的点等于上一个三角形的点。

然后新建脚本PieImageBase.cs:

using UnityEngine.UI;

public class PieImageBase : MaskableGraphic
{
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        vh.Clear();
        DrawCircleShow(vh);
    }
    protected virtual void DrawCircleShow(VertexHelper vh)
    {

    }
}

新建脚本DrawCircle.cs:

using UnityEngine;
using UnityEngine.UI;

public class DrawCircle : PieImageBase
{
    [Header("圆的半径")]
    public float radius = 80;
    [Header("圆的总度数")]
    public float totaldegree = 360;
    [Header("圆分成多少段画")]
    public int segments = 0;
    [Header("圆心")]
    private Vector2 circlepoint = Vector2.zero;

    protected override void DrawCircleShow(VertexHelper vh)
    {
        vh.Clear();
        ChartUtilsPie.DrawCircle(vh, circlepoint, radius, segments,0, totaldegree);
    }
}

传递圆的半径、圆心、圆的度数、圆分成多少度段画。

当圆分成5个画的时候,就相当于用5个三角形做成圆,就变成五边形了: 在这里插入图片描述 这个值越大,圆就越圆: 在这里插入图片描述 还有总度数,修改总度数,圆也跟着变化: 在这里插入图片描述 总结一下,需要新建三个脚本: 在这里插入图片描述 然后,新建一个Panel覆盖全屏,在Panel下新建一个空对象,附加DrawCircle脚本: 在这里插入图片描述 因为是实时渲染,可以实时看到效果:

在这里插入图片描述