美文网首页
Unity中,2D扇形区域的范围检测和显示

Unity中,2D扇形区域的范围检测和显示

作者: 全新的饭 | 来源:发表于2023-10-29 11:20 被阅读0次

    说明

    具体需实现

    1. 显示扇形区域
    2. 检测目标点是否在该区域内

    使用示意

    用SectorArea表示扇形,用SectorAreaView来显示。


    扇形区域.gif

    实现

    核心

    显示:创建扇形Sprite,设置为spriteRenderer的sprite

        public void CreateSprite(float radius, float angle, Color color)
        {
            var size = (int)(radius * 2 * 100);
            var actualRadius = size / 2;
            var halfAngle = angle / 2;
            Texture2D texture2D = new Texture2D(size, size);
            Vector2 centerPixel = Vector2.one * size / 2;
    
            // 绘制
            var emptyColor = Color.clear;
            Vector2 tempPixel;
            float tempAngle;
            float tempDisSqr;
            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    tempPixel.x = x - centerPixel.x;
                    tempPixel.y = y - centerPixel.y;
    
                    tempDisSqr = tempPixel.sqrMagnitude;
                    if (tempDisSqr <= actualRadius * actualRadius)
                    {
                        tempAngle = Vector2.Angle(Vector2.right, tempPixel);
                        if (tempAngle < halfAngle || tempAngle > 360 - halfAngle)
                        {
                            //设置像素色值
                            texture2D.SetPixel(x, y, color);
                            continue;
                        }
                    }
                    texture2D.SetPixel(x, y, emptyColor);
                }
            }
    
            texture2D.Apply();
            _renderer.sprite = Sprite.Create(texture2D, new Rect(0, 0, size, size), Vector2.one * 0.5f);
        }
    

    检测目标点是否在扇形区域内

        public bool IsInArea(Vector2 pos)
        {
            var ret = false;
            if (Vector2.Distance(CenterPos, pos) < _radius)
            {
                var halfAngle = _angles / 2;
                var dir = (pos - CenterPos).normalized;
                var curAngle = Vector2.Angle(Dir, dir);
                if (curAngle < halfAngle || curAngle > 360 - halfAngle)
                {
                    ret = true;
                }
            }
            return ret;
        }
    
        // 在范围内是否能找到指定层的对象
        public bool CanFindTarget(LayerMask targetLayer, out Transform target)
        {
            var ret = CanFindTargets(targetLayer, out Transform[] targets);
            target = ret ? targets[0] : null;
            return ret;
        }
        public bool CanFindTargets(LayerMask targetLayer, out Transform[] targets)
        {
            var ret = false;
            var targetList = new List<Transform>();
            var cols = Physics2D.OverlapCircleAll(CenterPos, _radius, targetLayer);
            if (cols != null)
            {
                foreach (var col in cols)
                {
                    Vector2 pos = col.transform.position;
                    if (IsInArea(pos))
                    {
                        targetList.Add(col.transform);
                    }
                }
            }
    
            ret = targetList.Count > 0;
            targets = targetList.ToArray();
    
            return ret;
        }
    

    完整代码

    SectorArea.cs

    using System.Collections.Generic;
    using UnityEngine;
    public class SectorArea : MonoBehaviour
    {
        [SerializeField]
        private Transform _centerTrans;
        public Vector2 CenterPos { get { return _centerTrans.position; } }
        [SerializeField]
        private Transform _dirTrans;
        public Vector2 Dir { get { return _dirTrans.right; } }
        [SerializeField, Range(1, 359)]
        private float _angles;
        [SerializeField, Range(0.1f, 15)]
        private float _radius;
    
        [SerializeField]
        private SectorAreaView _view;
        [SerializeField]
        private Color _viewColor = Color.red;
    
        public void Init()
        {
            RefreshView();
        }
        public void MyDestroy()
        {
    
        }
    
        public bool IsInArea(Vector2 pos)
        {
            var ret = false;
            if (Vector2.Distance(CenterPos, pos) < _radius)
            {
                var halfAngle = _angles / 2;
                var dir = (pos - CenterPos).normalized;
                var curAngle = Vector2.Angle(Dir, dir);
                if (curAngle < halfAngle || curAngle > 360 - halfAngle)
                {
                    ret = true;
                }
            }
            return ret;
        }
    
        // 在范围内是否能找到指定层的对象
        public bool CanFindTarget(LayerMask targetLayer, out Transform target)
        {
            var ret = CanFindTargets(targetLayer, out Transform[] targets);
            target = ret ? targets[0] : null;
            return ret;
        }
        public bool CanFindTargets(LayerMask targetLayer, out Transform[] targets)
        {
            var ret = false;
            var targetList = new List<Transform>();
            var cols = Physics2D.OverlapCircleAll(CenterPos, _radius, targetLayer);
            if (cols != null)
            {
                foreach (var col in cols)
                {
                    Vector2 pos = col.transform.position;
                    if (IsInArea(pos))
                    {
                        targetList.Add(col.transform);
                    }
                }
            }
    
            ret = targetList.Count > 0;
            targets = targetList.ToArray();
    
            return ret;
        }
    
    
        [ContextMenu("刷新扇形面积的展示")]
        private void RefreshView()
        {
            _view.CreateSprite(_radius, _angles, _viewColor);
        }
    }
    

    SectorAreaView.cs

    using UnityEngine;
    
    public class SectorAreaView : MonoBehaviour
    {
        [SerializeField]
        private SpriteRenderer _renderer;
        public void CreateSprite(float radius, float angle, Color color)
        {
            var size = (int)(radius * 2 * 100);
            var actualRadius = size / 2;
            var halfAngle = angle / 2;
            Texture2D texture2D = new Texture2D(size, size);
            Vector2 centerPixel = Vector2.one * size / 2;
    
            // 绘制
            var emptyColor = Color.clear;
            Vector2 tempPixel;
            float tempAngle;
            float tempDisSqr;
            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    tempPixel.x = x - centerPixel.x;
                    tempPixel.y = y - centerPixel.y;
    
                    tempDisSqr = tempPixel.sqrMagnitude;
                    if (tempDisSqr <= actualRadius * actualRadius)
                    {
                        tempAngle = Vector2.Angle(Vector2.right, tempPixel);
                        if (tempAngle < halfAngle || tempAngle > 360 - halfAngle)
                        {
                            //设置像素色值
                            texture2D.SetPixel(x, y, color);
                            continue;
                        }
                    }
                    texture2D.SetPixel(x, y, emptyColor);
                }
            }
    
            texture2D.Apply();
            _renderer.sprite = Sprite.Create(texture2D, new Rect(0, 0, size, size), Vector2.one * 0.5f);
        }
    }
    

    相关文章

      网友评论

          本文标题:Unity中,2D扇形区域的范围检测和显示

          本文链接:https://www.haomeiwen.com/subject/zfhvidtx.html