使用Unity相机确定AI代理的视线范围


本文由 译林军_一梦阿九 翻译。原文链接: Lineof Sight for AI Agent using Camera in Unity

01.gif

2014-4-17 09:52:27 上传
下载附件(11.56 KB)

目前我在用Unity的AI系统做隐蔽类游戏,敌人是秘密潜入的,玩家要防护一个具体位置,比如,一个敌人可能试图窃取的对象。当玩这样一个游戏的时候,我想让人工智能代理像我一样,躲在墙后面,注意听敌人的脚步,当敌人接近时能够逃跑。我希望我的人工智能代理和真实的玩家一样拥有相同的信息。在游戏中有主要两种信息来源:我们所看到的和我们所听到的。本文关注第一个来源。如何通过一种方式让工智能代理知道它看到了什么。


讨论


Unity提供了很多方式来分析游戏世界。它有像Physics.RayCast(…)或Physics.OverlapSphere(…) 这样的函数,它也给我们提供关于边界,网格和渲染器的信息。对我的项目来说,人工智能代理必须能够寻找目的地,可以访问所有他们看到和感兴趣对象。


当我思考什么是视图,以及如何给它一个智能代理时,我考虑到视图属性,它有一个视野,一个面对的方向,一个原点和我们看到的距离。我意识到这个描述是一个很好的跟摄像机的描述类似的描述。所以如果我可以尝试用现有的Unity相机组件的话,我为什么还要做一个类似相机的组件呢。


我试图找出是否有办法知道在Unity的相机视线中出现的每个gameobject。有,但是它太花费时间和内存(我很乐意向您展示怎样做到)。还有其他信息你可能考虑,像使用renderer.isvisible, OnBecameVisible(),OnWillRenderObject(),但你需要一个脚本附加到每个你想让你的AI能够看到的对象上。此外,renderer.isvisible不会告诉你它对哪个相机是可见的,并且这些方法没有一个考虑阻塞。所有这些数据都很难工作,由于我们正在使用多个相机。


了解GameObject是否在AI的视线中


我的想法是为每一个智能代理,viewsensor绑定一个camera。相机的设置有一定的视野,和远平面。Unity有两个用于相机测试的很方便的方法,第一个返回6个截面来定义的摄像头截(camera frustum),第二个告诉一个边界对象是在摄像头截的内部还是外部。


现在我们可以知道一个gameobjet是否在我们的观图内,但不是我们是否可以看到它,因为它可能会被另一个更接近摄影机位置的对象遮挡。所以我使用linecasts告知我们是否可以看到这个对象。但我应该转换哪个位置?对象的中心位置是一个很好的选择,但不一定足够准确。我使用对象网格边界,并遍历了所有的边界位置,当linecast不经过任何东西时停止,然后我知道是否可以看到对象。


最完美的方式是为网格的每个顶点之间做一个linecast,但它将花费太多的时间。


获取所有GameObjects


现在我们有一个函数告诉我们一个特定的对象是否在人工智能的视线内,我只是测试每个对象,由一个相机位置为原点,以相机远平面的距离为半径进行重叠范围检查。我为每个对象调用之前的SeeGameObject函数并将在视线内的对象保存在一个数组中。        

        public bool SeeGameObject(GameObject go)
        {

                // if object has a renderer and visible by any camera and is in this camera frustum
                if(go.renderer != null && go.renderer.isVisible && GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(_camera), go.renderer.bounds))
                {
                        RaycastHit hitInfo;

                        // by default we use the rough renderer bounds
                        Vector3 center = go.renderer.bounds.center;
                        Vector3 extents = go.renderer.bounds.extents;
                        float coefreduc = 0.8f;

                        Vector3[] gobounds; // points to check for linecast from camera

                        MeshFilter meshfilter = go.GetComponent<MeshFilter>();
                        if(meshfilter != null) // Almost every interesting game object that is render has a mesh
                        {
                                center = go.transform.position;
                                extents = meshfilter.mesh.bounds.extents;
                                extents.Scale(go.transform.lossyScale);

                                gobounds = new Vector3[33]{ // We can add more or remove some, it increase precision for not too much time or memory cost
Vector3.zero,
go.transform.TransformDirection(new Vector3(extents.x,extents.y,extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,-extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,-extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,-extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,-extents.z)*0.9f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,-extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,-extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,-extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,-extents.z)*0.5f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,-extents.z)*0.75f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(extents.x,extents.y,-extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(extents.x,-extents.y,-extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(-extents.x,extents.y,-extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,extents.z)*0.25f),
go.transform.TransformDirection(new Vector3(-extents.x,-extents.y,-extents.z)*0.25f)
                                };
                        }
                        else // Only if gameobject has no mesh (= almost never) (Very approximately checking points using the renderer bounds and not the mesh bounds)
                        {
                                gobounds  = new Vector3[9]{
                                        Vector3.zero,
                                        new Vector3(extents.x,extents.y,extents.z)*coefreduc,
                                        new Vector3(extents.x,extents.y,-extents.z)*coefreduc,
                                        new Vector3(extents.x,-extents.y,extents.z)*coefreduc,
                                        new Vector3(extents.x,-extents.y,-extents.z)*coefreduc,
                                        new Vector3(-extents.x,extents.y,extents.z)*coefreduc,
                                        new Vector3(-extents.x,extents.y,-extents.z)*coefreduc,
                                        new Vector3(-extents.x,-extents.y,extents.z)*coefreduc,
                                        new Vector3(-extents.x,-extents.y,-extents.z)*coefreduc
                                };
                        }

                        foreach(Vector3 v in gobounds)
                        {
                                // test if it can see gameobject
                                if(GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(_camera), new Bounds(v+center, Vector3.zero)) // if point in viewing frustrum
                                   && (!Physics.Linecast(transform.position, v+center, out hitInfo) || hitInfo.collider.gameObject == go )) // if nothing between viewing position and point
                                {
                                        if(graphicalDebug)
                                        {
                                                Debug.DrawLine(transform.position,  v+center,Color.red, 0.01f, false);
                                        }
                                        return true;
                                }
                        }
                        
                }
                
                return false;

        }

原文链接:Lineof Sight for AI Agent using Camera in Unity

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值