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

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 中添加和配置各个段


http://www.kler.cn/a/613991.html

相关文章:

  • 内网服务器无法通过公网地址访问映射到公网的内网服务
  • 使用事件监听器来处理并发环境中RabbitMQ的同步响应问题
  • 代码随想录算法训练营--打卡day1
  • maxDataPointsPerRollingArg must be at least 1
  • vue(1-45)
  • 方法指南:利用边缘计算实现低延迟直播流媒体服务
  • 如何用Java拆分PDF文件(教程)
  • 【C++数据库】SQLite3数据库连接与操作
  • 循环神经网络 - 给网络增加记忆能力
  • Avro 批量转换成 Json 文件
  • Python爬虫实战:批量获取中国知网(CNKI)文献摘要教程
  • 大型语言模型的秘密:思考链长度与提示格式的魔力
  • Css vertical-align与line-height
  • Windows下VSCode的安装
  • 在Cesium中使用ThreeJs材质(不是场景融合哦)
  • Transformer:破局山地暴雨预测的「地形诅咒」--AI智能体开发与大语言模型的本地化部署、优化技术
  • 深入解析铸铁测量平台的多面魅力——北重安装
  • 关于deepseek
  • 《白帽子讲 Web 安全》之跨站请求伪造
  • STM32通用定时器结构框图