Unity自定义起始和结束角度的环形填充Image

效果演示如下:

当我们需要进行Image的环形加载时,需要将Image的ImageType设为Filled,但是起始角度只能选择上下左右四个点位,此外只能选择360°满圆周环形。

试想一下,当我们需要一个起始位置在斜向45°,且只有320°的环形加载时,问题会变得很棘手。全网也没有类似需求和方案,于是咱写了一个还算用得了的组件。

  • 先设置起始角度CustomFillOrigin,组件设有两条辅助线分别是起始线和终点线。

  • 然后设置图片填充的总角度数CustomFillMaxAngle。

  • 然后选择填充方向Clockwise(顺时针或逆时针),此外可以设置辅助线长度,其他功能需求可以自行更改组件代码。

组件继承自Image,组件脚本代码如下:

CustomFillOriginImage

// ******************************************************************
//@file         CustomFillOriginImage.cs
//@brief        自定义起始填充角度的image
//@author       yufulao, yufulao@qq.com
//@createTime   2024.07.22 01:24:49
// ******************************************************************

using UnityEngine;
using UnityEngine.UI;

namespace Yu
{
    public class CustomFillOriginImage : Image
    {
        [SerializeField] private float customFillOrigin = 0f; // 自定义起始角度,范围0-360
        [SerializeField] private float customFillMaxAngle = 360f; // 自定义最大角度,范围0-360
        [SerializeField] private bool clockwise = true; // 填充方向:顺时针或逆时针
        [SerializeField] private float lineLength = 100f; // 线段长度

        public float CustomFillOrigin
        {
            get => customFillOrigin;
            set
            {
                customFillOrigin = Mathf.Clamp(value, 0f, 360f);
                SetVerticesDirty();
            }
        }

        public float CustomFillMaxAngle
        {
            get => customFillMaxAngle;
            set
            {
                customFillMaxAngle = Mathf.Clamp(value, 0f, 360f);
                SetVerticesDirty();
            }
        }

        public bool Clockwise
        {
            get => clockwise;
            set
            {
                clockwise = value;
                SetVerticesDirty();
            }
        }

        public float LineLength
        {
            get => lineLength;
            set
            {
                lineLength = Mathf.Max(0f, value);
                SetVerticesDirty();
            }
        }

        protected override void OnPopulateMesh(VertexHelper vh)
        {
            vh.Clear();
            if (overrideSprite == null)
            {
                return;
            }

            var rect = GetPixelAdjustedRect();
            var v = new Vector4(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
            var center = new Vector2((v.x + v.z) / 2, (v.y + v.w) / 2);
            var radius = (v.z - v.x) / 2;
            var startAngle = customFillOrigin * Mathf.Deg2Rad;
            startAngle -= Mathf.PI / 2;
            vh.AddVert(center, color, new Vector2(0.5f, 0.5f));
            var fillAmountInDegrees = customFillMaxAngle * fillAmount;
            var steps = Mathf.CeilToInt(fillAmountInDegrees);
            if (clockwise)
            {
                for (var i = 0; i <= steps; i++)
                {
                    var currentAngle = startAngle + (i * Mathf.Deg2Rad);
                    var dir = new Vector2(Mathf.Cos(currentAngle), Mathf.Sin(currentAngle));
                    var pos = center + dir * radius;
                    var uv = new Vector2(0.5f + dir.x * 0.5f, 0.5f + dir.y * 0.5f);
                    vh.AddVert(pos, color, uv);
                }
            }
            else
            {
                for (var i = 0; i <= steps; i++)
                {
                    var currentAngle = startAngle - (i * Mathf.Deg2Rad);
                    var dir = new Vector2(Mathf.Cos(currentAngle), Mathf.Sin(currentAngle));
                    var pos = center + dir * radius;
                    var uv = new Vector2(0.5f + dir.x * 0.5f, 0.5f + dir.y * 0.5f);
                    vh.AddVert(pos, color, uv);
                }
            }

            for (var i = 1; i < vh.currentVertCount - 1; i++)
            {
                vh.AddTriangle(0, i, i + 1);
            }
        }
    }
}

Editor类:

// ******************************************************************
//@file         CustomFillOriginImageEditor.cs
//@brief        CustomFillOriginImage的Editor类
//@author       yufulao, yufulao@qq.com
//@createTime   2024.07.22 01:36:22
// ******************************************************************

using UnityEditor;
using UnityEngine;

namespace Yu
{
    [CustomEditor(typeof(CustomFillOriginImage))]
    public class CustomFillOriginImageEditor : Editor
    {
        private SerializedProperty _customFillOriginProperty;
        private SerializedProperty _customFillMaxAngleProperty;
        private SerializedProperty _clockwiseProperty;
        private SerializedProperty _lineLengthProperty;
        private SerializedProperty _fillOriginProperty;
        private SerializedProperty _fillClockwiseProperty;
        private SerializedProperty _typeProperty;
        private SerializedProperty _fillMethodProperty;

        private void OnEnable()
        {
            _customFillOriginProperty = serializedObject.FindProperty("customFillOrigin");
            _customFillMaxAngleProperty = serializedObject.FindProperty("customFillMaxAngle");
            _clockwiseProperty = serializedObject.FindProperty("clockwise");
            _lineLengthProperty = serializedObject.FindProperty("lineLength");
            
            _fillOriginProperty = serializedObject.FindProperty("m_FillOrigin");
            _fillClockwiseProperty = serializedObject.FindProperty("m_FillClockwise");
            _typeProperty = serializedObject.FindProperty("m_Type");
            _fillMethodProperty = serializedObject.FindProperty("m_FillMethod");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            _fillOriginProperty.isExpanded = false;
            _fillClockwiseProperty.isExpanded = false;
            _typeProperty.isExpanded = false;
            _fillMethodProperty.isExpanded = false;
            DrawPropertiesExcluding(serializedObject, "customFillOrigin", "customFillMaxAngle", "clockwise", "lineLength", "m_FillOrigin", "m_FillClockwise", "m_Type", "m_FillMethod");
            EditorGUILayout.Slider(_customFillOriginProperty, 0f, 360f, new GUIContent("Custom Fill Origin"));
            EditorGUILayout.Slider(_customFillMaxAngleProperty, 0f, 360f, new GUIContent("Custom Fill Max Angle"));
            EditorGUILayout.PropertyField(_clockwiseProperty, new GUIContent("Clockwise"));
            EditorGUILayout.PropertyField(_lineLengthProperty, new GUIContent("Line Length"));
            serializedObject.ApplyModifiedProperties();
        }

        private void OnSceneGUI()
        {
            var customFilledImage = (CustomFillOriginImage) target;
            if (!customFilledImage)
            {
                return;
            }
            
            var transform = customFilledImage.transform;
            //起始角度和最大角度的计算
            var startAngle = customFilledImage.CustomFillOrigin;
            var maxAngle = customFilledImage.CustomFillMaxAngle;
            var endAngle = customFilledImage.Clockwise ? startAngle + maxAngle : startAngle - maxAngle;
            //计算起始角度和结束角度的弧度值
            var startRad = (startAngle - 90) * Mathf.Deg2Rad;
            var endRad = (endAngle - 90) * Mathf.Deg2Rad;
            //计算起始点和终点的世界坐标
            var position = transform.position;
            var startPoint = position + new Vector3(Mathf.Cos(startRad), Mathf.Sin(startRad)) * customFilledImage.LineLength;
            var endPoint = position + new Vector3(Mathf.Cos(endRad), Mathf.Sin(endRad)) * customFilledImage.LineLength;
            Handles.color = Color.red;
            Handles.DrawLine(position, startPoint); //绘制起始线段
            Handles.DrawLine(position, endPoint); //绘制终点线段
        }
    }
}

(真正的神明诹访子保佑我和大伙的项目顺风顺水~)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值