• 自己使用顶点描绘圆形图片


    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Sprites;
    using UnityEngine.UI;
    
    //保证图片的宽高比与Image的宽高比一致,方便图像uv与物体的对应关系,否则图片会变形
    public class CircleImage : Image
    {
        /// <summary>
        /// 圆形有多少个面
        /// </summary>
        public int segments = 100;
        public float fillPrecent = 1f;
        private List<Vector3> listVertex;
    
        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            toFill.Clear();
            float width = rectTransform.rect.width;
            float height = rectTransform.rect.height;
            if (width == 0 || height == 0 || segments == 0)
            {
                return;
            }
            Color32 col = new Color32(60, 60, 60, 255);
            /*  1.获得uv
             *  2.计算uv宽高,中心点,uv与物体宽高的换算系数
             *  3.计算每个三角面的弧度,圆的半径
             *  4.计算各个三角面的顶点
             *  5.生成三角形
            //*/
            //获得uv
            Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
            
            //计算uv宽高,中心点,uv与物体宽高的换算系数
            float uvW = uv.z - uv.x;
            float uvH = uv.w - uv.y;
            Vector2 uvCenter = new Vector2(uvW * 0.5f, uvH * 0.5f);
            Vector2 converRatio = new Vector2(uvW / width, uvH / height);
    
            //计算每个三角面的弧度,圆的半径
            float radian = (2 * Mathf.PI) / segments;
            float radius = width < height ? width * 0.5f : height * 0.5f;
    
            //计算各个三角面的顶点
            Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
            Vector2 vertPos = Vector2.zero;
            UIVertex originVert = new UIVertex(); //中心点顶点
            byte temp = (byte)(255 * fillPrecent);
            originVert.color = new Color32(temp, temp, temp, 255);
            originVert.position = originPos;
            originVert.uv0 = new Vector2(vertPos.x * converRatio.x + uvCenter.x, vertPos.y * converRatio.y + uvCenter.y);
            toFill.AddVert(originVert);
            //计算圆边缘的顶点
            int realSegment = (int)(fillPrecent * segments) + 1;
            int vertCount = segments + 1;
            float curRadian = 0;
            listVertex = new List<Vector3>(vertCount);
            for (int i = 0; i < vertCount; i++)
            {
                float x = Mathf.Cos(curRadian) * radius;
                float y = Mathf.Sin(curRadian) * radius;
                curRadian += radian;
                UIVertex vertTemp = new UIVertex();
                if (i < realSegment && fillPrecent > 0)
                {
                    vertTemp.color = color;
                }
                else 
                {
                    vertTemp.color = col;
                }
                vertPos = new Vector2(x, y);
                vertTemp.position = vertPos + originPos;
                vertTemp.uv0 = new Vector2(vertPos.x * converRatio.x + uvCenter.x, vertPos.y * converRatio.y + uvCenter.y);
                toFill.AddVert(vertTemp);
                listVertex.Add(vertPos + originPos);
            }
    
            //生成三角形
            int id = 1;
            for (int i = 0; i < segments; i++)
            {
                toFill.AddTriangle(id, 0, id + 1);
                id++;
            }
        }
    
        //判断点击是否有效
        public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out Vector2 localPoint);
            return MIsRaycastLocationValid(localPoint, listVertex);
        }
        //判断方法:从点击点位置向右画线,查看与相邻顶点组成的线段的交点个数是奇数还是偶数,奇数在范围内,偶数不在范围内
        private bool MIsRaycastLocationValid(Vector2 point, List<Vector3> listVert)
        {
            int count = 0;
            //遍历所有相邻顶点组成的线段
            for (int i = 0; i < listVert.Count; i++)
            {
                Vector3 v1 = listVert[i];
                Vector3 v2 = listVert[(i + 1) % listVert.Count];
                if (v1.x == v2.x && v1.y == v2.y)
                {
                    continue;
                }
                //获取有效范围内的线段
                if (IsYRange(v1, v2, point))
                {
                    count++;
                }
            }
            Debug.Log(count);
            return (count % 2) == 1;
        }
        //用来判断y是否在v1,v2的线段内
        private bool IsYRange(Vector3 v1, Vector3 v2, Vector2 point)
        {
            if (v1.y > v2.y)
            {
                if (point.y >= v2.y && point.y <= v1.y)
                {
                    return IsRectangleContainsScreenPoint(v1, v2, point);
                }
            }
            else
            {
                if (point.y >= v1.y && point.y <= v2.y)
                {
                    return IsRectangleContainsScreenPoint(v1, v2, point);
                }
            }
            return false;
        }
    
        //判断point点向右画线是否与v1、v2的线段相交
        private bool IsRectangleContainsScreenPoint(Vector3 v1, Vector3 v2, Vector2 point)
        {
            //y=kx+b, k = (y2-y1)/(x2-x1)
            float k = (v1.y - v2.y) / (v1.x - v2.x);
            float x = v1.x - (v1.y - point.y) / k;
            return point.x <= x;
        }
    }
  • 相关阅读:
    springBoot单元测试-模拟MVC测试
    springBoot单元测试-基础单元测试
    java使用HttpClient 发送get、pot请求
    定时任务框架-quartz 时间配置
    定时任务框架-quartz
    java接入极光推送
    实现自动解析properties文件并装配到Bean
    Redis-NoSql 概述,NoSql的优点
    springboot
    JAVA常见集合类
  • 原文地址:https://www.cnblogs.com/luoyanghao/p/15130235.html
Copyright © 2020-2023  润新知