当前位置: 首页 > news >正文

unity 做一个圆形分比图

// 在其他脚本中控制多段进度
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public MultiCircleProgress circleProgress;

    void Start()
    {
        // 初始化数据
        circleProgress.segments = new List<MultiCircleProgress.ProgressSegment>{
            new MultiCircleProgress.ProgressSegment{
                name = "",
                progress = 0.2f,
                color = Color.red
            },
            new MultiCircleProgress.ProgressSegment{
                name = "",
                progress = 0.3f,
                color = Color.blue
            },
            new MultiCircleProgress.ProgressSegment{
                name = "",
                progress = 0.3f,
                color = Color.green
            },
            new MultiCircleProgress.ProgressSegment{
                name = "",
                progress = 0.1f,
                color = Color.black
            },
            new MultiCircleProgress.ProgressSegment{
                name = "",
                progress = 0.1f,
                color = Color.cyan
            }
        };

        circleProgress.CreateSegments();
    }

    void UpdatePlayerStats(float health, float mana, float stamina)
    {
        circleProgress.UpdateSegment(0, health);
        circleProgress.UpdateSegment(1, mana);
        circleProgress.UpdateSegment(2, stamina);
    }
}```
脚本挂到场景中一个模型上,脚本可以设置生成得比例

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

public class MultiCircleProgress : MonoBehaviour
{
    [System.Serializable]
    public class ProgressSegment
    {
        public string name;
        [Range(0, 1)] public float progress;
        public Color color;
        [HideInInspector] public Image fillImage;
        [HideInInspector] public Text textComponent;
    }

    [Header("UI Elements")]
    public List<ProgressSegment> segments = new List<ProgressSegment>();
    public GameObject segmentPrefab;
    public Text percentTextTemplate;
    public Transform textContainer;

    [Header("Text Positioning")]
    public float textDistanceFromCenter = 0.7f; // 基于半径的比例 (0.5=边缘, 1.0=两倍半径)
    public float textOffsetAngle = 0f;
    public float textMinDistance = 30f;
    public float textMaxDistance = 200f;

    private RectTransform baseRectTransform;
    private float baseRadius;

    void Start()
    {
        InitializeComponents();
        CreateSegments();
    }

    void InitializeComponents()
    {
        baseRectTransform = GetComponent<RectTransform>();
        baseRadius = Mathf.Min(baseRectTransform.rect.width, baseRectTransform.rect.height) / 2f;
    }

    public void CreateSegments()
    {
        ClearExistingSegments();
        ClearExistingTexts();

        float currentRotation = 0f;
        for (int i = 0; i < segments.Count; i++)
        {
            CreateSegment(i, ref currentRotation);
        }
    }

    void ClearExistingSegments()
    {
        foreach (Transform child in transform)
        {
            if (child != textContainer) Destroy(child.gameObject);
        }
    }

    void ClearExistingTexts()
    {
        if (textContainer != null)
        {
            foreach (Transform child in textContainer)
            {
                Destroy(child.gameObject);
            }
        }
    }

    void CreateSegment(int index, ref float currentRotation)
    {
        // 创建进度段
        GameObject segmentObj = Instantiate(segmentPrefab, transform);
        segments[index].fillImage = segmentObj.GetComponent<Image>();

        // 配置段属性
        ConfigureSegment(index, currentRotation);

        // 创建并定位文本
        if (percentTextTemplate != null && textContainer != null)
        {
            CreateSegmentText(index, currentRotation);
        }

        currentRotation += segments[index].progress * 360f;
    }

    void ConfigureSegment(int index, float rotation)
    {
        segments[index].fillImage.color = segments[index].color;
        segments[index].fillImage.type = Image.Type.Filled;
        segments[index].fillImage.fillMethod = Image.FillMethod.Radial360;
        segments[index].fillImage.fillOrigin = (int)Image.Origin360.Top;
        segments[index].fillImage.fillClockwise = true;
        segments[index].fillImage.transform.rotation = Quaternion.Euler(0, 0, -rotation);
        segments[index].fillImage.fillAmount = segments[index].progress;
    }

    void CreateSegmentText(int index, float segmentStartRotation)
    {
        Text textObj = Instantiate(percentTextTemplate, textContainer);
        textObj.gameObject.SetActive(true);
        segments[index].textComponent = textObj;

        textObj.text = $"{segments[index].name} {Mathf.RoundToInt(segments[index].progress * 100)}%";
        textObj.color = segments[index].color;

        PositionTextOutsideCircle(index, segmentStartRotation);
    }

    void PositionTextOutsideCircle(int index, float segmentStartRotation)
    {
        if (segments[index].textComponent == null) return;

        // 计算当前半径
        float currentRadius = Mathf.Min(
            Mathf.Max(baseRectTransform.rect.width, baseRectTransform.rect.height) / 2f,
            textMaxDistance
        );

        // 计算有效文本距离 (基于比例但限制在最小/最大值之间)
        float effectiveTextDistance = Mathf.Max(
            currentRadius * textDistanceFromCenter,
            textMinDistance
        );

        // 计算扇形中心角度
        float midAngle = segmentStartRotation + (segments[index].progress * 180f) + textOffsetAngle;

        // 计算文本位置 (圆形中心向外延伸)
        Vector3 textDirection = Quaternion.Euler(0, 0, -midAngle) * Vector3.up;
        segments[index].textComponent.rectTransform.anchoredPosition = textDirection * effectiveTextDistance;

        // 保持文本水平
        segments[index].textComponent.rectTransform.localRotation = Quaternion.identity;

        // 设置文本锚点为中心,方便定位
        segments[index].textComponent.rectTransform.anchorMin =
        segments[index].textComponent.rectTransform.anchorMax =
        segments[index].textComponent.rectTransform.pivot = new Vector2(0.5f, 0.5f);
    }

    public void UpdateAllProgress()
    {
        float currentRotation = 0f;
        for (int i = 0; i < segments.Count; i++)
        {
            segments[i].progress = Mathf.Clamp01(segments[i].progress);

            // 更新填充和旋转
            if (segments[i].fillImage != null)
            {
                segments[i].fillImage.transform.rotation = Quaternion.Euler(0, 0, -currentRotation);
                segments[i].fillImage.fillAmount = segments[i].progress;
            }

            // 更新文本
            if (segments[i].textComponent != null)
            {
                segments[i].textComponent.text = $"{segments[i].name}: {Mathf.RoundToInt(segments[i].progress * 100)}%";
                PositionTextOutsideCircle(i, currentRotation);
            }

            currentRotation += segments[i].progress * 360f;
        }
    }

    public void UpdateSegment(int index, float progress)
    {
        if (index >= 0 && index < segments.Count)
        {
            segments[index].progress = Mathf.Clamp01(progress);
            UpdateAllProgress();
        }
    }

#if UNITY_EDITOR
    void OnValidate()
    {
        if (baseRectTransform == null)
            baseRectTransform = GetComponent<RectTransform>();

        if (!Application.isPlaying && baseRectTransform != null)
        {
            UnityEditor.EditorApplication.delayCall += () => {
                if (this != null) UpdateAllProgress();
            };
        }
    }
#endif
}

创建UI结构:

创建 Canvas

在 Canvas 下创建空对象 “MultiProgress”

创建空对象 “TextContainer” 作为文本父对象

准备预制体:

创建 Image 对象,命名为 “SegmentPrefab”

设置为 Filled 类型,Fill Method 为 Radial 360

将其做成预制体

准备文本模板:

创建 Text 对象,设置好字体样式

初始设置为非激活状态

命名为 “PercentTextTemplate”

添加组件:

给 “MultiProgress” 对象添加 MultiCircleProgress 脚本

将预制体和文本模板拖拽到脚本对应字段

在 Inspector 中添加和配置各个段

相关文章:

  • RAG技术的进化:RQ-RAG查询优化/化繁为简Adaptive-RAG智能分类/精准出击
  • 力扣HOT100之普通数组:189. 轮转数组
  • 算法250327题目
  • C语言 —— 此去经年梦浪荡魂音 - 深入理解指针(卷五)
  • 如何快速对比两个不同的excel文件中的单元格的数据是否完全相同 并把不同的单元格的背景颜色更改为红色?
  • MySQL索引优化与应用指南
  • 【电子通识】铅笔硬度简史:从石墨到工业标准
  • 香港QILSTE/旗光 H6-108QLB高亮LED灯珠
  • AnimateCC技术教学:使用后台JavaScript修改ballObj实例的填充色为径向渐变色-由DeepSeek产生
  • 【踩坑系列】使用httpclient调用第三方接口返回javax.net.ssl.SSLHandshakeException异常
  • 【位运算】268. 丢失的数字
  • 深度讨论Python for循环
  • SQL Server安装过程中提示 .NET Framework 4.8 缺失
  • 【cocos creator 3.x】3Dui创建,模型遮挡ui效果
  • RocketMQ 底层原理
  • 什么是uv 和pip的区别是什么
  • 深入掌握Linux ip命令:网络配置与管理的瑞士军刀
  • Scala基础语法与简介
  • [OS_4] 数学视角 | 多状态 | 模型检查器 | 程序验证(math)
  • 掌握文件权限:理解Linux chmod
  • 某购物网站建设方案/如何建立网站平台
  • 计量检测网站平台建设方案/seo外包费用
  • 山东建设网站广告/个人seo外包
  • 网站建设大作业论文/泉州百度竞价公司
  • 做网站需要什么代码/网站优化技术
  • 网络营销运营推广方案下载/短视频seo营销系统