Unity不同形狀區域的檢測

一:圓形區域檢測


需要判斷一點:
——發起檢測的物體位置與目標位置的距離是否小於圓形半徑

using UnityEngine;

public class AreaDetection : MonoBehaviour
{
    public Transform targetTrans;//目標位置(敵人位置)

    public float attackDis;//圓形的半徑

    void Update()
    {
        float dis = Vector3.Distance(transform.position, targetTrans.position);
        if (dis <= attackDis )
        {
            Debug.Log("進入攻擊區域");
        }
        else
        {
            Debug.Log("離開攻擊區域");
        }
    }
}

二:扇形區域檢測


需要判斷兩點:
——發起檢測的物體位置與目標位置的距離是否小於扇形半徑
——發起檢測的物體與目標的夾角是否小於扇形角度的二分之一

using UnityEngine;

public class AreaDetection : MonoBehaviour
{
    public float attackDis;//扇形的半徑
    public float attackAngle;//扇形的角度

    public Transform targetTrans;//目標位置(敵人位置)

    private void Update()
    {
        float dis = Vector3.Distance(transform.position, targetTrans.position);
        float angle = Vector3.Angle(transform.forward, targetTrans.position - transform.position);

        if (dis <= attackDis && angle <= attackAngle / 2)
        {
            Debug.Log("進入攻擊區域");
        }
        else
        {
            Debug.Log("離開攻擊區域");
        }
    }
}

得到兩個向量的夾角可以用另一種方法:

float _angle = Mathf.Acos(Vector3.Dot(transform.forward.normalized, (targetTrans.position - transform.position).normalized)) * Mathf.Rad2Deg;

三:矩形區域檢測


需要判斷三點:
——發起檢測的物體與目標是否小於等於90度
——發起檢測的物體位置到目標位置的向量在發起檢測物體前方向向量上的投影是否小於矩形的長度
——發起檢測的物體位置到目標位置的向量在發起檢測物體右方向向量上的投影是否小於矩形的一半寬度

using UnityEngine;

public class AreaDetection : MonoBehaviour
{
    public float attackDis_forward;//矩形的長度
    public float attackDis_right;//矩形的寬度一半

    public Transform targetTrans;//目標位置(敵人位置)

    private void Update()
    {
        Vector3 v = targetTrans.position - transform.position;

        float projectionDis_forward = Vector3.Dot(transform.forward, v) / 1;
        float projectionDis_right = Vector3.Dot(transform.right, v) / 1;
        if ((projectionDis_forward > 0 && projectionDis_forward <= attackDis_forward)
            && (Mathf.Abs(projectionDis_right) < attackDis_right))
        {
            Debug.Log("進入攻擊區域");
        }
        else
        {
            Debug.Log("離開攻擊區域");
        }
    }
}

四:繪製可視的檢測區域圖形

將腳本掛載到發起檢測的物體(與AreaDetection腳本掛載到同一物體身上)

using System.Collections.Generic;
using UnityEngine;

public class DrawShape : MonoBehaviour
{
    private AreaDetection _area;//區域檢測的腳本

    public static GameObject go;
    public static MeshFilter mf;
    public static MeshRenderer mr;
    public static Shader shader;

    private void Awake()
    {
        _area = GetComponent<AreaDetection>();
    }

    void Update()
    {
        //DrawCircleArea(transform, transform.localPosition, _area.attackDis);
        //DrawSectorArea(transform, transform.localPosition, _area.attackAngle, _area.attackDis);
        //DrawRectangleArea(transform, transform.localPosition, _area.attackDis_forward, _area.attackDis_right);
    }

    /// <summary>
    /// 繪製圓形區域
    /// </summary>
    /// <param name="t">圓形參考物</param>
    /// <param name="center">圓形的中心</param>
    /// <param name="radius">圓形的半徑</param>
    public static void DrawCircleArea(Transform t, Vector3 center, float radius)
    {
        int pointAmount = 100;//點的數目,值越大麴線越平滑   
        float eachAngle = 360f / pointAmount;
        Vector3 forward = t.forward;

        List<Vector3> vertices = new List<Vector3>();
        for (int i = 0; i < pointAmount; i++)
        {
            Vector3 pos = Quaternion.Euler(0f, eachAngle * i, 0f) * forward * radius + center;
            vertices.Add(pos);
        }
        CreateMesh(vertices);
    }

    /// <summary>
    /// 繪製扇形區域
    /// </summary>
    /// <param name="t">扇形參考物</param>
    /// <param name="center">扇形的中心</param>
    /// <param name="angle">扇形的角度</param>
    /// <param name="radius">扇形的半徑</param>
    public static void DrawSectorArea(Transform t, Vector3 center, float angle, float radius)
    {
        int pointAmount = 100;//點的數目,值越大麴線越平滑   
        float eachAngle = angle / pointAmount;
        Vector3 forward = t.forward;

        List<Vector3> vertices = new List<Vector3>();
        vertices.Add(center);
        for (int i = 1; i < pointAmount - 1; i++)
        {
            Vector3 pos = Quaternion.Euler(0f, -angle / 2 + eachAngle * (i - 1), 0f) * forward * radius + center;
            vertices.Add(pos);
        }
        CreateMesh(vertices);
    }

    /// <summary>
    /// 繪製矩形區域
    /// </summary>
    /// <param name="t">矩形參考物</param>
    /// <param name="bottomMiddle">矩形的中心點</param>
    /// <param name="length">矩形的長度</param>
    /// <param name="width">矩形的寬度一半</param>
    public static void DrawRectangleArea(Transform t, Vector3 bottomMiddle, float length, float width)
    {
        List<Vector3> vertices = new List<Vector3>();
        vertices.Add(bottomMiddle - t.right * width);
        vertices.Add(bottomMiddle - t.right * width + t.forward * length);
        vertices.Add(bottomMiddle + t.right * width + t.forward * length);
        vertices.Add(bottomMiddle + t.right * width);

        CreateMesh(vertices);
    }

    /// <summary>
    /// 創建Mesh
    /// </summary>
    /// <param name="vertices">存儲頂點的列表</param>
    /// <returns></returns>
    private static GameObject CreateMesh(List<Vector3> vertices)
    {
        int[] triangles;
        Mesh mesh = new Mesh();
        int triangleAmount = vertices.Count - 2;
        triangles = new int[3 * triangleAmount];

        //根據三角形的個數,來計算繪製三角形的頂點順序(索引)   
        //順序必須爲順時針或者逆時針      
        for (int i = 0; i < triangleAmount; i++)
        {
            triangles[3 * i] = 0;//固定第一個點      
            triangles[3 * i + 1] = i + 1;
            triangles[3 * i + 2] = i + 2;
        }

        if (go == null)
        {
            go = new GameObject("DetectionArea");
            go.transform.position = new Vector3(0, 0.1f, 0);//讓繪製的圖形上升一點,防止被地面遮擋  
            mf = go.AddComponent<MeshFilter>();
            mr = go.AddComponent<MeshRenderer>();
            shader = Shader.Find("Unlit/Color");
        }
        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles;
        mf.mesh = mesh;
        mr.material.shader = shader;
        mr.material.color = Color.red;
        return go;
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章