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

2023-10-29  本文已影响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);
    }
}
上一篇 下一篇

猜你喜欢

热点阅读