Unity 模拟手电筒光源探测器,AI攻击范围检测区域,视锥内检测物体,扇形区域检测,圆形区域检测,圆锥区域检测

Unity光源检测器

扇形区域检测效果:

请添加图片描述

圆形区域检测效果:

请添加图片描述

圆锥区域检测效果:

请添加图片描述
参考文章: Unity AI探测器
文章写的非常的详细,不过根据需求不同,只能检测扇形区域肯定是不够的
我增加了光源边缘检测与光源实体区域检测

面板说明:

显示视野:渲染检测区域
视角网格:区域网格(sphere),可以调整材质
检测模式:根据需求不同,使用不同的检测模式
网格密集度:网格越密集检测的越精细,发射的射线就越多,消耗性能就越多
请添加图片描述
视野角度与视野半径分别控制着扇形模式与圆形,圆锥模式的视野角度
请添加图片描述
视野距离:调整检测距离
目标Tag: 只有这个标签的物体可以被检测

工具面板:

在这里插入图片描述

三种模式检测方法,返回的List就是需要射线发射的点位置
 	/// <summary>
    /// 得到圆形
    /// </summary>
    /// <returns></returns>
    public List<Vector3> GetCircle()
    {
        itemList.Clear();
        float angle = 0;
        for (int i = 0; i <= Points; i++)
        {
            Vector3 Rotation = Quaternion.AngleAxis(angle, transform.forward) * transform.up * FOVRadius;
            Rotation += transform.forward * SightRange;
            itemList.Add(Rotation);
            angle += 360 / Points;
        }
        return itemList;
    }
    /// <summary>
    /// 得到扇形
    /// </summary>
    /// <returns></returns>
    public List<Vector3> GetSectorial()
    {
        itemList.Clear();
        for (int j = 0; j <= Points; j++)
        {
            float Angle = -FOVAngle + (((FOVAngle * 2) / Points) * j);
            if (Angle < 0) Angle = 360 + Angle;
            Vector3 Rotation = Quaternion.AngleAxis(Angle, transform.up) * transform.forward;
            itemList.Add(Rotation);
        }
        return itemList;
    }

圆锥区域需要分散点位,不能越到中心点越密集,需要均匀分布
请添加图片描述

    /// <summary>
    /// 得到圆锥
    /// </summary>
    /// <returns></returns>
    public List<Vector3> GetCircularCone()
    {
        itemList.Clear();
        float goldenRatio = (1 + Mathf.Sqrt(5)) / 2;
        float angleIncrement = Mathf.PI * 2 * goldenRatio;

        for (int i = 0; i < Points; i++)
        {
            float t = (float)i / Points;
            float inclination = Mathf.Acos(1 - 2 * t);
            float azimuth = angleIncrement * i;

            float x = Mathf.Sin(inclination) * Mathf.Cos(azimuth);
            float y = Mathf.Sin(inclination) * Mathf.Sin(azimuth);
            float z = Mathf.Cos(inclination);
            Vector3 Rotation = new Vector3(x, y, z) * FOVRadius;
            Rotation += transform.forward * SightRange;
            itemList.Add(Rotation);
        }
        return itemList;
    }
完整代码:
using System.Collections.Generic;
using UnityEngine;


public class Detetor : MonoBehaviour
{
    [Header("显示视野")]
    public bool ShowLOS = true;
    [Header("视角网格")]
    public MeshFilter FOVMesh;
    [Header("检测模式")]
    public MeshMode meshMode = MeshMode.扇形;
    [Header("网格密集度,精确度")]
    [Range(5f, 1000f)]
    public float Points = 50;
    [Header("视野角度")]
    [Range(1f, 180f)]
    public float FOVAngle = 60f;
    [Header("视野半径")]
    [Range(1f, 50f)]
    public float FOVRadius = 5f;
    [Header("视野距离")]
    public float SightRange = 6f;
    [Header("目标Tag")]
    public string[] DetectionTags;
    bool IsTargetInFOV = true;

    void Start()
    {
        Init();
        this.GetComponent<SphereCollider>().radius = SightRange;
    }
    void Init()
    {
        Light light = GetComponent<Light>();
        if (light)
        {
            if (light.type == LightType.Spot)
            {
                FOVAngle = light.spotAngle / 2;
                FOVRadius = light.spotAngle / 8;
                SightRange = light.range;
            }
        }
    }

    /// <summary>
    /// 生成视线网格线
    /// </summary>
    void GenLOSMesh()
    {
        if (!IsTargetInFOV)
            return;
        this.GetComponent<SphereCollider>().radius = SightRange;
        List<Vector3> newVertices = new List<Vector3>();
        newVertices.Add(Vector3.zero);
        //if (itemList.Count == 0)
        {
            switch (meshMode)
            {
                case MeshMode.扇形:
                    GetSectorial();
                    break;
                case MeshMode.圆形:
                    GetCircle();
                    break;
                case MeshMode.圆锥:
                    GetCircularCone();
                    break;
            }
        }
        foreach (Vector3 item in itemList)
        {
            RaycastHit hit;
            Ray ray = new Ray(transform.position, item);
            if (Physics.Raycast(ray, out hit, SightRange))
            {
                for (int i = 0; i < DetectionTags.Length; i++)
                {
                    if (hit.collider.gameObject.tag == DetectionTags[i])
                    {
                        CallBack(hit.collider.gameObject);
                    }
                }
                newVertices.Add(hit.point - transform.position);
            }
            else
            {
                newVertices.Add(ray.GetPoint(SightRange) - transform.position);
            }
        }

        if (ShowLOS)
        {
            DrawLos(newVertices);
        }
        else
        {
            FOVMesh.mesh.Clear();
        }
    }
    List<Vector3> itemList = new List<Vector3>();
    /// <summary>
    /// 得到圆形
    /// </summary>
    /// <returns></returns>
    public List<Vector3> GetCircle()
    {
        itemList.Clear();
        float angle = 0;
        for (int i = 0; i <= Points; i++)
        {
            Vector3 Rotation = Quaternion.AngleAxis(angle, transform.forward) * transform.up * FOVRadius;
            Rotation += transform.forward * SightRange;
            itemList.Add(Rotation);
            angle += 360 / Points;
        }
        return itemList;
    }
    /// <summary>
    /// 得到扇形
    /// </summary>
    /// <returns></returns>
    public List<Vector3> GetSectorial()
    {
        itemList.Clear();
        for (int j = 0; j <= Points; j++)
        {
            float Angle = -FOVAngle + (((FOVAngle * 2) / Points) * j);
            if (Angle < 0) Angle = 360 + Angle;
            Vector3 Rotation = Quaternion.AngleAxis(Angle, transform.up) * transform.forward;
            itemList.Add(Rotation);
        }
        return itemList;
    }
    /// <summary>
    /// 得到圆锥
    /// </summary>
    /// <returns></returns>
    public List<Vector3> GetCircularCone()
    {
        itemList.Clear();
        float goldenRatio = (1 + Mathf.Sqrt(5)) / 2;
        float angleIncrement = Mathf.PI * 2 * goldenRatio;

        for (int i = 0; i < Points; i++)
        {
            float t = (float)i / Points;
            float inclination = Mathf.Acos(1 - 2 * t);
            float azimuth = angleIncrement * i;

            float x = Mathf.Sin(inclination) * Mathf.Cos(azimuth);
            float y = Mathf.Sin(inclination) * Mathf.Sin(azimuth);
            float z = Mathf.Cos(inclination);
            Vector3 Rotation = new Vector3(x, y, z) * FOVRadius;
            Rotation += transform.forward * SightRange;
            itemList.Add(Rotation);
        }
        return itemList;
    }
    /// <summary>
    /// 回调
    /// </summary>
    /// <param name="obj"></param>
    void CallBack(GameObject obj)
    {
        Debug.Log("发现目标:" + obj.name);
    }
    /// <summary>
    /// 绘制网格
    /// </summary>
    /// <param name="newVertices"></param>
    void DrawLos(List<Vector3> newVertices)
    {
        FOVMesh.mesh.Clear();
        List<Vector2> newUV = new List<Vector2>();
        List<int> newTriangles = new List<int>();
        for (int i = 1; i < newVertices.Count - 1; i++)
        {
            newTriangles.Add(0);
            newTriangles.Add(i);
            newTriangles.Add(i + 1);
        }
        for (int i = 0; i < newVertices.Count; i++)
        {
            newUV.Add(new Vector2(newVertices[i].x, newVertices[i].z));
        }
        FOVMesh.mesh.vertices = newVertices.ToArray();
        FOVMesh.mesh.triangles = newTriangles.ToArray();
        FOVMesh.mesh.uv = newUV.ToArray();
        FOVMesh.transform.rotation = Quaternion.identity;
        FOVMesh.mesh.RecalculateNormals();
        //switch (meshMode)//法线设置
        //{
        //    case MeshMode.平面:
        //        FOVMesh.mesh.RecalculateNormals();
        //        break;
        //    case MeshMode.圆形:
        //        InversionNormal(FOVMesh);
        //        break;
        //    case MeshMode.圆锥:
        //        FOVMesh.mesh.RecalculateNormals();
        //        break;
        //}
        //FOVMesh.gameObject.GetComponent<MeshCollider>().sharedMesh = FOVMesh.mesh;
    }
    /// <summary>
    /// 法线反转
    /// </summary>
    /// <param name="meshFilter"></param>
    void InversionNormal(MeshFilter meshFilter)
    {
        Vector3[] normals = meshFilter.mesh.normals;
        for (int i = 0; i < normals.Length; i++)
        {
            normals[i] = -normals[i];
        }
        meshFilter.mesh.normals = normals;

        int[] triangles = meshFilter.mesh.triangles;
        for (int i = 0; i < triangles.Length; i += 3)
        {
            int t = triangles[i];
            triangles[i] = triangles[i + 2];
            triangles[i + 2] = t;
        }
        meshFilter.mesh.triangles = triangles;
    }

    void OnTriggerStay(Collider col)
    {
        IsTargetInFOV = false;
        for (int i = 0; i < DetectionTags.Length; i++)
        {
            if (col.gameObject.tag == DetectionTags[i])
            {
                IsTargetInFOV = true;
                break;
            }
        }
    }
    public enum MeshMode
    {
        扇形,
        圆形,
        圆锥
    }
    void Update()
    {
        GenLOSMesh();
    }
}

绘制圆形时法线需要处理,后来换成双面材质问题解决,所以代码注掉了.
应用时不要忘记关闭绘制网格,
Demo下载链接: Demo

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Unity 中实现在某区域检测滑动并在手指抬起时检测方向,可以使用以下方法: 1. 在场景中创建一个空对象,并将其命名为 Swipe Detector。 2. 给 Swipe Detector 添加一个 Box Collider 组件,用于检测手指滑动的区域。在 Box Collider 组件中设置 Is Trigger 为 true,这样手指滑动时就不会被 Box Collider 阻挡。 3. 给 Swipe Detector 添加一个脚本,用于检测手指的滑动方向。 4. 在脚本中定义一个变量来保存手指按下时的位置,一个变量来保存手指抬起时的位置,以及一个变量来保存滑动的方向。 5. 在 Update 函数中检测手指的按下和抬起事件,并记录手指按下和抬起的位置。 6. 在 OnMouseDrag 函数中计算手指滑动的方向,并保存到方向变量中。 7. 在 OnMouseUp 函数中判断手指滑动的距离是否超过一定的阈值,如果超过则保存滑动方向。 下面是示例代码: ```csharp public class SwipeDetector : MonoBehaviour { private Vector2 fingerDownPosition; private Vector2 fingerUpPosition; private Vector2 direction; public void OnMouseDrag() { fingerUpPosition = Input.mousePosition; direction = fingerUpPosition - fingerDownPosition; } public void OnMouseUp() { if (direction.magnitude > 50) { Debug.Log(direction.normalized); } } public void Update() { if (Input.GetMouseButtonDown(0)) { fingerDownPosition = Input.mousePosition; fingerUpPosition = Input.mousePosition; } } } ``` 在这个示例代码中,我们使用了 Input.GetMouseButtonDown 和 Input.GetMouseButtonUp 函数来检测手指的按下和抬起事件,在 OnMouseDrag 函数中计算了手指滑动的方向,并在 OnMouseUp 函数中判断手指滑动的距离是否超过了阈值,如果超过则保存滑动方向。你可以根据自己的需求来修改代码,实现更多的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐沢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值