1.实现自己的圆形图片组件

UGUI实现的圆形图片

(1)添加一个image,添加圆形的Sprite,添加mask组件。
在这里插入图片描述
(2)在image下添加一个image作为子物体,添加如以下的图片:
在这里插入图片描述
效果如图:
在这里插入图片描述
缺点:
锯齿严重,mask增加了Draw Call的调用,降低性能。禁用mask会明显看到Draw Call调用减少。
在这里插入图片描述

实现

原理:由多个三角形面片组成
在这里插入图片描述
UV:
在这里插入图片描述

代码:

using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;

public class CircleImage : Image
{

    [SerializeField]
    private int segements = 100;//拼成块数
    [SerializeField]
    private float showPercent =1;//显示百分比
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        if (segements > 10000) return;
        vh.Clear();
        //overrideSprite是否为null
        Vector4 uv = overrideSprite!=null?DataUtility.GetOuterUV(overrideSprite):Vector4.zero;
        //求出uv中心点
        float uvWidth = uv.z - uv.x;
        float uvHeight = uv.w - uv.y;
        Vector2 uvCenter = new Vector2(0.5f*uvWidth,0.5f*uvHeight);

        //uv与实际显示大小转换比例
        float width = rectTransform.rect.width;
        float height = rectTransform.rect.height;
        Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);

        //每一块三角片的弧度
        float radian = (2 * Mathf.PI) / segements;
        //显示半径
        float radius = width * 0.5f;

        //圆点
        UIVertex origin = new UIVertex();
        origin.color = color;
        //rect中的位置
        origin.position = Vector3.zero;
        float uvX = origin.position.x * convertRatio.x + uvCenter.x;
        float uvY = origin.position.y * convertRatio.y + uvCenter.y;
        //对应uv坐标
        origin.uv0 = new Vector2(uvX, uvY);
        vh.AddVert(origin);

        //其他点
        int realSegements = (int)(segements * showPercent);//真实三角面数
        int vertexCount = realSegements + 1;
        //当前弧度
        float curRadian = 0;
        for (int i = 0; i < vertexCount; i++)
        {
            float x = Mathf.Cos(curRadian) * radius;
            float y = Mathf.Sin(curRadian) * radius;
            curRadian += radian;

            UIVertex vertexTemp = new UIVertex();
            vertexTemp.color = color;
            vertexTemp.position = new Vector2(x, y);
            float _uvX = vertexTemp.position.x * convertRatio.x + uvCenter.x;
            float _uvY = vertexTemp.position.y * convertRatio.y + uvCenter.y;
            vertexTemp.uv0 = new Vector2(_uvX, _uvY);
            vh.AddVert(vertexTemp);
        }
        //三角面,顺时针传入顶点,否则背面剔除
        for (int i = 1; i <= realSegements; i++)
        {
            vh.AddTriangle(i, 0, i+1);
        }
    }
}

效果图:
在这里插入图片描述

将属性序列化显示在Inspector面板上

原始:

[SerializeField]
private int segements = 100;//拼成块数
[SerializeField]
private float showPercent =1;//显示百分比

上面两个属性并没有显示在Inspector面板上
在这里插入图片描述
代码实现:

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

[CustomEditor(typeof(CircleImage), true)]
[CanEditMultipleObjects]
public class CircleImageEditor : ImageEditor
{
    SerializedProperty _fillPercent;
    SerializedProperty _segements;

    private void OnEnable()
    {
        base.OnEnable();
        _fillPercent = serializedObject.FindProperty("showPercent");
        _segements = serializedObject.FindProperty("segements");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();绘制原本的信息//
        // Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
        serializedObject.Update();
        // Show the custom GUI controls.--显示自定义GUI控件
        EditorGUILayout.Slider(_fillPercent, 0, 1, new GUIContent("showPercent"));

        EditorGUILayout.PropertyField(_segements);

        // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
        serializedObject.ApplyModifiedProperties();

        if (GUI.changed)
        {
            EditorUtility.SetDirty(target);
        }

    }
}

效果:
在这里插入图片描述
在这里插入图片描述

实现技能灰色效果

在这里插入图片描述
代码修改:

//其他点
        float tmp = segements * showPercent;
        int realSegements = (int)tmp;//真实三角面数
        int vertexCount = realSegements==0?0:realSegements + 1;
        Debug.Log("realSegements="+ realSegements);
        //当前弧度
        float curRadian = 0;
        for (int i = 0; i < segements +1; i++)
        {
            float x = Mathf.Cos(curRadian) * radius;
            float y = Mathf.Sin(curRadian) * radius;
            curRadian += radian;

            UIVertex vertexTemp = new UIVertex();
            if (i < vertexCount)
            {
                vertexTemp.color = color;
            }
            else
            {
                vertexTemp.color = new Color32(60,60,60,255);
            }
            
            vertexTemp.position = new Vector2(x, y);
            float _uvX = vertexTemp.position.x * convertRatio.x + uvCenter.x;
            float _uvY = vertexTemp.position.y * convertRatio.y + uvCenter.y;
            vertexTemp.uv0 = new Vector2(_uvX, _uvY);
            vh.AddVert(vertexTemp);
        }
修改圆心高亮的问题

因为三角面片的颜色由三个点渐变而成,而圆心的颜色始终为origin.color = color,导致圆心在realSegements为0时,仍然高亮
在这里插入图片描述
代码修改:
随showPercent渐变

	private readonly Color32 GRAY_COLOR = new Color32(60, 60, 60, 255);
    private Color32 GetOriginColor()
    {
        Color32 colorTmp = (Color.white - GRAY_COLOR) * showPercent;
        return new Color32(
            (byte)(GRAY_COLOR.r + colorTmp.r),
            (byte)(GRAY_COLOR.g + colorTmp.g),
            (byte)(GRAY_COLOR.b + colorTmp.b),
            255);
    }

效果:
在这里插入图片描述

解决 pivot改变,图片随之移动和uv不正确的问题
 //圆心位置,一直处于rect中心,不随pivot改变
        Vector2 originPos = new Vector2((0.5f- rectTransform.pivot.x) * width, (0.5f- rectTransform.pivot.y) * height);
        float uvX = uvCenter.x;
        float uvY = uvCenter.y;
        //对应uv坐标
        origin.uv0 = new Vector2(uvX, uvY);
        vh.AddVert(origin);
for (int i = 0; i < segements +1; i++)
        {
            float x = Mathf.Cos(curRadian) * radius;
            float y = Mathf.Sin(curRadian) * radius;
            curRadian += radian;

            UIVertex vertexTemp = new UIVertex();
            if (i < vertexCount)
            {
                vertexTemp.color = color;
            }
            else
            {
                vertexTemp.color = new Color32(60,60,60,255);
            }

            vertexTemp.position = new Vector2(x, y)+ originPos;
            
            float _uvX = x * convertRatio.x + uvCenter.x;
            float _uvY = y * convertRatio.y + uvCenter.y;
            vertexTemp.uv0 = new Vector2(_uvX, _uvY);
            vh.AddVert(vertexTemp);
        }

完整代码如下:
图片不随pivot改变而移动

using UnityEngine;
using UnityEngine.Sprites;
using UnityEngine.UI;

public class CircleImage : Image
{

    [SerializeField]
    private int segements = 100;//拼成块数
    [SerializeField]
    private float showPercent =1f;//显示百分比
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        if (segements > 10000) return;
        vh.Clear();
        //overrideSprite是否为null
        Vector4 uv = overrideSprite!=null?DataUtility.GetOuterUV(overrideSprite):Vector4.zero;
        //求出uv中心点
        float uvWidth = uv.z - uv.x;
        float uvHeight = uv.w - uv.y;
        Vector2 uvCenter = new Vector2(0.5f*uvWidth,0.5f*uvHeight);

        //uv与实际显示大小转换比例
        float width = rectTransform.rect.width;
        float height = rectTransform.rect.height;
        Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);

        //每一块三角片的弧度
        float radian = (2 * Mathf.PI) / segements;
        //显示半径
        float radius = width * 0.5f;

        //圆点
        UIVertex origin = new UIVertex();

        //byte temp = (byte)(255 * showPercent);
        //origin.color = new Color32(temp, temp, temp, 255);
        origin.color = GetOriginColor();

        //圆心位置,一直处于rect中心,不随pivot改变
        Vector2 originPos = new Vector2((0.5f- rectTransform.pivot.x) * width, (0.5f- rectTransform.pivot.y) * height);
        float uvX = uvCenter.x;
        float uvY = uvCenter.y;
        //对应uv坐标
        origin.uv0 = new Vector2(uvX, uvY);
        vh.AddVert(origin);

        //其他点
        float tmp = segements * showPercent;
        int realSegements = (int)tmp;//真实三角面数
        int vertexCount = realSegements==0?0:realSegements + 1;
        Debug.Log("realSegements="+ realSegements);
        //当前弧度
        float curRadian = 0;
        for (int i = 0; i < segements +1; i++)
        {
            float x = Mathf.Cos(curRadian) * radius;
            float y = Mathf.Sin(curRadian) * radius;
            curRadian += radian;

            UIVertex vertexTemp = new UIVertex();
            if (i < vertexCount)
            {
                vertexTemp.color = color;
            }
            else
            {
                vertexTemp.color = new Color32(60,60,60,255);
            }

            vertexTemp.position = new Vector2(x, y)+ originPos;
            
            float _uvX = x * convertRatio.x + uvCenter.x;
            float _uvY = y * convertRatio.y + uvCenter.y;
            vertexTemp.uv0 = new Vector2(_uvX, _uvY);
            vh.AddVert(vertexTemp);
        }
        //三角面,顺时针传入顶点
        for (int i = 1; i <= segements; i++)
        {
            vh.AddTriangle(i, 0, i+1);
        }
    }
    private readonly Color32 GRAY_COLOR = new Color32(60, 60, 60, 255);
    private Color32 GetOriginColor()
    {
        Color32 colorTmp = (Color.white - GRAY_COLOR) * showPercent;
        return new Color32(
            (byte)(GRAY_COLOR.r + colorTmp.r),
            (byte)(GRAY_COLOR.g + colorTmp.g),
            (byte)(GRAY_COLOR.b + colorTmp.b),
            255);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值