Unity中用到的物理(为自己)

Unity 检测对象是否在相机的视锥体范围内

  1. using System.Collections;

  2. using System.Collections.Generic;

  3. using UnityEngine;

  4. using Stopwatch = System.Diagnostics.Stopwatch;

  5. [RequireComponent(typeof(MeshRenderer))]

  6. public class TestInCamera : MonoBehaviour {

  7. private Camera m_cam;

  8. private MeshRenderer m_meshRenderer;

  9. private Stopwatch m_sw;

  10. private void Start() {

  11. m_cam = Camera.main;

  12. m_meshRenderer = GetComponent<MeshRenderer>();

  13. // 采用给定摄像机的视椎体,然后返回形成此视椎体的六个平面。

  14. // 排序:[0] = 左、[1] = 右、[2] = 下、[3] = 上、[4] = 近、[5] = 远

  15. Plane[] planes = GeometryUtility.CalculateFrustumPlanes(m_cam);

  16. for (int i = 0; i < 6; ++i) {

  17. GameObject p = GameObject.CreatePrimitive(PrimitiveType.Plane);

  18. p.name = "Plane " + i.ToString();

  19. p.transform.position = -planes[i].normal * planes[i].distance;

  20. p.transform.rotation = Quaternion.FromToRotation(Vector3.up, planes[i].normal);

  21. }

  22. }

  23. void Update() {

  24. if (m_sw == null) {

  25. m_sw = new Stopwatch();

  26. }

  27. m_sw.Restart();

  28. Plane[] planes = GeometryUtility.CalculateFrustumPlanes(m_cam);

  29. bool inside = GeometryUtility.TestPlanesAABB(planes, m_meshRenderer.bounds);

  30. m_sw.Stop();

  31. //Debug.Log($"time:{m_sw.ElapsedMilliseconds} ms, inside:{inside}");

  32. }

  33. }

Unity3D检测目标身体是否在椎体视野范围内

public GameObject srcPos;
    public GameObject endPos;
    public GameObject buttonPos;
    public float Dic;
    public float angle;
    public Transform[] pHead;
    public Transform[] pFoot;
 
    private void Start()
    {
        angle = Vector3.Angle(srcPos.transform.forward, endPos.transform.position - srcPos.transform.position);
        Dic = Vector3.Distance(srcPos.transform.position, endPos.transform.position);
    }
 
    void Update ()
    {
        for(int i=0;i<pHead.Length;i++)
        {
            if (IsTargetBodyInSectorRange(srcPos.transform.position, srcPos.transform.forward,
                angle, Dic, pHead[i].position, pFoot[i].position))
            {
                Debug.DrawLine(pHead[i].position, pFoot[i].position,Color.red);
            }
            else
                Debug.DrawLine(pHead[i].position, pFoot[i].position, Color.green);
        }     
    }
 
 
    public static bool IsTargetInSectorRange(Vector3 srcPos, Vector3 srcDir, float srcAngle, float srcDist,
        Vector3 tarPos)
    {
        Vector3 toTarVec = tarPos - srcPos;
        float deltaAngle = Vector3.Angle(srcDir, toTarVec);
        if (deltaAngle < srcAngle)
        {
            float dist = Vector3.Distance(srcPos, tarPos);
            if (dist < srcDist)
            {
                return true;
            }
        }
        return false;
    }
 
    public static bool IsTargetBodyInSectorRange(Vector3 srcPos, Vector3 srcDir, float srcAngle, float srcDist,
        Vector3 tarHeadPos, Vector3 tarFootPos)
    {
        if (IsTargetInSectorRange(srcPos, srcDir, srcAngle, srcDist, tarHeadPos))
            return true;
        if (IsTargetInSectorRange(srcPos, srcDir, srcAngle, srcDist, tarFootPos))
            return true;
        if (tarFootPos.y <= srcPos.y && srcPos.y <= tarHeadPos.y &&
           IsTargetInSectorRange(srcPos, srcDir, srcAngle, srcDist, new Vector3(tarFootPos.x, srcPos.y, tarFootPos.z)))
            return true;
        return false;
    }

如何实现 AI 的视觉检测

1.RayCast

只使用射线检测的好处是简单易用,但仅适用于 2D 或者对高度没有要求的俯视角游戏,很多场景并不适用

2.角度判断 + RayCast

判断看向目标的向量与自身正前方向量的角度,若小于设定的角度,再向目标打出射线,若命中,则说明目标与自身之间没有阻碍,且角度,距离都正确

可以适用于 3D 场景,但问题在于必须指定目标,并且单一射线目标不适于所有场景

3.Sphere Collider + RayCast + 角度判断

当有碰撞体进入时进行角度判断,再进行射线检测,相较于2方法,无需指定目标

4.视锥检测

方法一  AABB包围盒

使用 TestPlanesAABB(Plane[] planes, Bounds bounds) 方法

使用 GeometryUtility.CalculateFrustumPlanes 方法从 Camera 组件上获取到视锥体的六个 Plane

这个方法有两个弊端,一是必须挂载 Camera 组件来使用,二是必须指定两个 AABB 盒才能进行判断,不适合使用

方法二 视锥形碰撞体

根据 Fov、near、far 等信息计算视锥顶点与三角面信息,手动绘制 Mesh,传入 MeshFilter,再由 MeshCollider 转化为碰撞体

顶点计算逻辑:Mathf.Tan(fov / 2 * Mathf.Deg2Rad);

使用起来与普通的碰撞体一样

5.扇形遮挡剔除

向指定角度打出若干射线,根据射线检测是否碰撞,若碰撞则返回碰撞点位置,没有碰撞则返回正常位置,根据位置信息绘制平面,实现剔除效果

缺点:不必要的 RayCast 太多,造成性能浪费

优化版:2d Visibility

只向更近的物体顶点打出射线

其他游戏视觉检测设计

《THE LAST OF US》 中的视线检测

早期沿用了神海的简单的锥体和射线来检测阻挡,但这样会导致贴AI的玩家不会被AI发现,而站在远处却会被敌人发现。

修改了视锥,如图,使近距离的可视范围较大,并且让可视角度大小随距离延长逐渐变小。

视觉检测方式

AI会对视觉范围内的玩家做射线检测(阻挡检测),起初检测乔尔身体的每个关节,每个关节都有各自的权重,当检测到的权重之和达到阈值,就会认为乔尔被看到了。

但是由于计算太复杂,玩家无法预测哪些掩体是安全的。

在经过一些尝试之后,顽皮狗最终决定只用一个点来做检测,这个点会根据敌人的状态而变化。
当玩家没被发现,也就是处在潜行状态的时候,AI只检测乔尔胸部中心点的位置,而当玩家和AI处于战斗状态的时候,AI就检测玩家的头顶。(如下图所示)

全境封锁的视觉检测

其中有三个颜色的区域用作视觉刺激

黄:该区域的玩家将会被缓慢发现

橙:该区域的玩家将会被迅速发现

为了防止玩家跑到 AI 身后,设置了一圈红色区域

红:该区域的玩家会被立刻发现

//

///

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值