用UGUI的Image画面积图

本文介绍如何使用Unity的UGUI Image组件绘制面积图。通过覆盖OnPopulateMesh方法并自定义顶点信息来实现动态面积图效果。文章提供了一个具体的代码实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用UGUI的Image画面积图


哈哈,本大猫又回来了,新的工作,新的生活。愿自己和看到这段话的你们,生活越来越辛福美满!


唔,先上图:
这里写图片描述


1. 参考引用:

[1] https://www.cnblogs.com/jeason1997/p/5130413.html 在Unity中使用UGUI修改Mesh绘制几何图形 (作者:Jeason1997)


2. 实现思路:
UGUI的Image实现方式和一般的Mesh一样,都是通过顶点描绘出来的。通过察看Image这个类的代码,发现它提供了虚函数,需要用到的关键函数是OnPopulateMesh(VertexHelper toFill)。


3. 好像也没啥需要多说的,就是给出顶点(位置,颜色,VU),然后一个一个三角形按照顺时针方向连起来。emmmm,上代码~


1)核心代码:

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

public class DrawAreaDiagram : Image {
    private List<float> percentArray = new List<float>();//百分比数组
    private float brokenLineWidth = 3f;//折线的宽度
    private Vector3 origin;//绘图区域的原点
    private Vector2 area;//宽高范围
    private Color[] lineColors;//折线
    private Color[] imageTopColors;//顶部
    private Color[] imageButtomColors;//底部
    private Vector3[] vertPositions;
    private int times = 3;

    private float pointQuadlength = 6f;//节点的边长
    private Vector3[] pointQuadPositions;//节点的位置
    private int quadSides = 4;//节点的边数

    private void Update()
    {
        SetVerticesDirty();//刷新
    }

    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        if (percentArray.Count == 0)
        {
            base.OnPopulateMesh(toFill);
        }
        else
        {
            toFill.Clear();
            for (int i = 0; i < percentArray.Count; i++)
            {
                toFill.AddVert(vertPositions[i * times], imageButtomColors[i], new Vector2((float)i / percentArray.Count, 0));//下
                toFill.AddVert(vertPositions[i * times + 1], imageTopColors[i], new Vector2((float)i / percentArray.Count, 0.25f));//上
                toFill.AddVert(vertPositions[i * times + 1], lineColors[i], new Vector2((float)i / percentArray.Count, 0.25f));//上
                toFill.AddVert(vertPositions[i * times + 2], lineColors[i], new Vector2((float)i / percentArray.Count, 0.5f));//顶
            }

            for (int i = 0; i < percentArray.Count; i++)
            {
                toFill.AddVert(pointQuadPositions[i * quadSides], lineColors[i], new Vector2((float)i / percentArray.Count, 0.5f));//下
                toFill.AddVert(pointQuadPositions[i * quadSides + 1], lineColors[i], new Vector2((float)i / percentArray.Count, 1f));//上
                toFill.AddVert(pointQuadPositions[i * quadSides + 2], lineColors[i], new Vector2((float)i / percentArray.Count, 0.5f));//上
                toFill.AddVert(pointQuadPositions[i * quadSides + 3], lineColors[i], new Vector2((float)i / percentArray.Count, 1f));//顶
            }

            for (int i = 0; i < percentArray.Count - 1; i++)
            {
                toFill.AddTriangle(i * 4 + 0, i * 4 + 1, i * 4 + 4);
                toFill.AddTriangle(i * 4 + 1, i * 4 + 5, i * 4 + 4);

                toFill.AddTriangle(i * 4 + 2, i * 4 + 3, i * 4 + 6);
                toFill.AddTriangle(i * 4 + 3, i * 4 + 7, i * 4 + 6);
            }

            for (int i = percentArray.Count; i < percentArray.Count * 2; i++)
            {
                toFill.AddTriangle(i * 4 + 0, i * 4 + 1, i * 4 + 2);
                toFill.AddTriangle(i * 4 + 1, i * 4 + 3, i * 4 + 2);
            }
        }
    }

    public void InitDrawingParam(float _pointQuadlength,float buttomAlpha,float topAplha, float lineWidth,Color[] colors,List<float> _percentArray)
    {
        if (colors.Length != _percentArray.Count)
        {
            Debug.LogError("ArrayList is Wrong!");
            return;
        }
        pointQuadlength = _pointQuadlength;
        percentArray = _percentArray;//百分比数组
        brokenLineWidth = lineWidth;//折线的宽

        GetDrawArea();//得到绘图区域
        CreateVertPositions(_percentArray);//获取到每个顶点的坐标

        lineColors = new Color[colors.Length];
        imageTopColors = new Color[colors.Length];
        imageButtomColors = new Color[colors.Length];
        //颜色
        for (int i = 0; i < colors.Length; i++)
        {
            lineColors[i] = colors[i];
            imageTopColors[i] = colors[i];
            imageButtomColors[i] = colors[i];
            //透明度
            lineColors[i].a = 1;
            imageTopColors[i].a = _percentArray[i] * topAplha;
            imageButtomColors[i].a = buttomAlpha;
        }   
    }
    private void CreateVertPositions(List<float> _percentArray)
    {
        vertPositions = new Vector3[_percentArray.Count * times];//折线顶,折线底,图片底
        pointQuadPositions = new Vector3[_percentArray.Count * quadSides];//节点
        int arrayCount = _percentArray.Count - 1;
        for (int i = 0; i < arrayCount + 1; i++)
        {
            vertPositions[times * i] = origin + new Vector3(area.x * i / arrayCount, 0, 0);//图片底
            vertPositions[times * i + 1] = vertPositions[times * i] + new Vector3(0, area.y * _percentArray[i] - brokenLineWidth / 2);//折线底
            vertPositions[times * i + 2] = vertPositions[times * i + 1] + new Vector3(0, brokenLineWidth);//折线顶

            pointQuadPositions[quadSides * i] = origin + new Vector3(area.x * i / arrayCount - pointQuadlength / 2, area.y * _percentArray[i] - pointQuadlength / 2);//节点左下
            pointQuadPositions[quadSides * i + 1] = origin + new Vector3(area.x * i / arrayCount - pointQuadlength / 2, area.y * _percentArray[i] + pointQuadlength / 2);//节点左上
            pointQuadPositions[quadSides * i + 2] = origin + new Vector3(area.x * i / arrayCount + pointQuadlength / 2, area.y * _percentArray[i] - pointQuadlength / 2);//节点右下
            pointQuadPositions[quadSides * i + 3] = origin + new Vector3(area.x * i / arrayCount + pointQuadlength / 2, area.y * _percentArray[i] + pointQuadlength / 2);//节点右上
        } 
    }
    //原点,宽,高
    private void GetDrawArea()
    {
        area = rectTransform.rect.size;
        origin = -(Vector3)area / 2;
    }
} 

2)测试代码:

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

public class DrawTest : MonoBehaviour {
    private DrawAreaDiagram areaDiagram;
    # region 测试代码
    protected void Start()
    {
        areaDiagram = GetComponentInChildren<DrawAreaDiagram>(true);
        StartCoroutine(FreshImage());
    }

    IEnumerator FreshImage()
    {
        while (true)
        {
            yield return new WaitForSeconds(0.9f);
            Test();
        }
    }
    protected void Test()
    {
        Color[] colors = new Color[19];
        List<float> _percentArray = new List<float>();
        for (int i = 0; i < colors.Length; i++)
        {
            colors[i] = new Color(Random.Range(0.1f, 1f), Random.Range(0.1f, 1f), Random.Range(0.1f, 1f), 1);
            _percentArray.Add(Random.Range(0.1f, 1f));
        }
        areaDiagram.InitDrawingParam(29f, 0f, 0.9f, 5f, colors, _percentArray);
    }
    #endregion

}

4. 使用大概是这样子的:(父节点挂测试代码)
这里写图片描述

### 饼状 UI 的制作方法 要在 Unity3D 中创建饼状 UI,可以通过 UGUI 系统来实现。以下是详细的说明以及示例代码。 #### 使用 Canvas 和 Image 组件构建饼状 Unity 提供了强大的 UGUI 系统,其中 `Image` 组件支持多种显示模式,包括填充模式(Fill Amount)。通过动态调整填充值并结合旋转角度,可以轻松模拟饼状的效果[^1]。 #### 创建基本结构 首先,在场景中添加一个 `Canvas` 并设置其渲染模式为 Screen Space - Overlay 或 Camera。接着,向该 Canvas 添加两个圆形像作为背景和前景部分: 1. **背景圆**:用于表示整个饼状的范围。 2. **前景圆**:用于绘制实际的数据比例,并启用切片填充效果。 #### 设置属性 对于前景圆,需将其 Type 属性设为 Filled,并调节 Fill Method 为 Radial 360°。这样可以根据数值变化控制扇形区域大小[^2]。 #### 动态更新逻辑 编写脚本来管理不同数据项对应的百分比值及其颜色样式。下面是一个简单的 C# 脚本例子演示如何操作这些参数: ```csharp using UnityEngine; using UnityEngine.UI; public class PieChartController : MonoBehaviour { public Image slice; // 前景圆 (即代表当前数据片段) private float percentageValue = 0f; void Start() { UpdateSlice(75); // 初始化为75% } /// <summary> /// 更新指定分片的角度占比 /// </summary> /// <param name="percent">新的百分比</param> public void UpdateSlice(float percent) { if(slice != null && percent >=0 && percent<=100){ this.percentageValue = percent / 100f ; slice.fillAmount=this.percentageValue ; } } } ``` 此脚本允许开发者通过调用 `UpdateSlice()` 方法传入不同的百分比从而改变特定扇区所占面的比例[^1]。 #### 多层复杂饼扩展 如果希望展示多个独立的部分,则需要重复上述过程多次,每次实例化一个新的 GameObject 来承载额外的一片弧度。注意合理安排各元素间的层级关系以防遮挡问题发生。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值