RVO避开agent

         A* Pathfinding Project 3.1.4                         RVO的使用

 

         大家好!今天想给大家安利一个避开agent的方法。性能也是棒棒哒!其实自己之前也写过避开agent的算法,但使用了大量的射线,其实在agent数量比较少的情况下效果还不错,但面临大量agent时,射线这个方法就不适用了。这也促使我去寻找更好的解决方案,这不,RVO(Reciprocal Velocity Obstacles),之前百度发现关于它的介绍并不多,后面有找到关于这个算法的论文,本来打算看完实现一下,后面感觉一堆堆英文,一堆堆公式,有点可怕,现在又有点赶进度,所以就想要找更方便的方法了。后面发现A*寻路插件里面有RVO算法可以直接拿来使用,所以就偷懒啦!

       在这里,我把官方文档给翻译过来,有需要的小伙伴们看过来哦!这里虽然写的是3.1.4版本的,但就RVO这一部分,基本含有RVO的A*插件使用RVO的方法都是类似的,只是A*插件之前由于一些版权的问题没有使用RVO,直到后续版本才可以使用,而且必须是专业版,大家需要的话就在CSDN上面搜索下载,例如3.6.0版本的,以及4.1.16版本的。后面我会把在unity里面调用的方法整理分享,感兴趣的欢迎戳哈!

 


 

局部避免

(说明:因为A* Pathfinding Project是一个可以直接放在unity中使用的插件,本文就将其保留为英文,不做翻译,把它理解成一个插件就可以啦。)

      如何使用A* Pathfinding Project中的局部避免。

     基于RVO的A* Pathfinding Project包含局部避免-相互速度障碍(Reciprocal Velocity Obstacles)和ORCA-最佳相互避免碰撞(Optimal Reciprocal Collision Avoidance)。它本身很大程度上基于RVO2库,但已经扩展了很多功能来处理不同级别的agent(例如,建筑物中不同楼层的agent不应该发生碰撞)。    

 

A*专业版本的功能:

这是A* Pathfinding Project专业版本特有的功能。它拥有的函数/类/变量在免费版本的A* Pathfinding Project中可能没有,免费版本的功能也可能是有限的。

您可以点击这里进行购买

如果想要获得更深入的信息,请点击这里:Writing RVO Colliders

 

数字运算

那么这个系统有多快,您可能会想。它的非常高的性能。特别是如果您考虑到局部避免模拟不需要在非常高的fps下运行,那只会浪费了CPU周期。我已经能够在我的笔记本电脑上模拟5000个agents处于比较好的fps。局部避免模拟运行在大约10个fps,游戏运行在25-35 fps,最低fps大约15。这个模拟的可视化是通过创建一个网格来完成的,该网格为每个agent保存一个正方形。原因是,在如此高的数字下,为每个agent创建一个GameObject是非常缓慢的,我认为创建这么多agent只需要10秒。这些agent被设置成一个圆圈,试图到达它们的对映点。所以基本上是尽可能的拥挤。

 

在我的另一台功率稍大一点的计算机(i7处理器)上,我可以模拟10000个agent,游戏运行速度为60帧/秒,rvo模拟运行速度为30帧/秒。

但是,不要指望在游戏中拥有这么多agents。 这些例子非常轻量级,在游戏中通常会有很多其他东西的开销。

 

概述

出于这个原因,Unity可以成为一个限制因素,系统分为两部分。 首先是核心模拟代码。 它完全独立于Unity特定对象,如GameObjects和MonoBehaviours。 它使用的唯一真正的Unity特定类是Vector3和Vector2结构,它们可以轻松互换。 该核心处理rvo(局部避免)agents的所有模拟。

 

第二部分是Unity接口。这些类中的许多只是相应核心类的包装类。例如,RVOSimulator类只是Pathfinding.RVO.Simulator。Unity接口还包含帮助类,以便更容易地进行局部避免集成。其中之一就是RVOController,您可能会经常用到它。它被编写成几乎可以直接替代Unity的Character Controller,支持诸如Move之类的功能,并且具有速度等属性,您可以轻松访问。

 

Unity接口部分的所有脚本都对如何设置场景有相同的假设:在场景中应该总是有一个RVOSimulator,其他脚本会查找它并获取核心模拟器实例,它是一个包装类。您可以简单地将它添加到任何GameObject中,如果您想的话,您可以编辑一些设置,它就会工作。您的RVOSimulator最好不多于一个,所有查找它的脚本都使用FindObjectOfType,而且没有简单的方法来精确地控制它将返回的多个RVOSimulators中的哪一个,因此为了简单起见,请将其保留为一个。

 

集成

好的,您现在知道它是如何构造的,让我们构建一个小的具体例子,这样您就可以看到它是如何工作的。

 

首先创建一个新场景,添加一个plane作为地面(位置(0,0,0),比例(10,10,10))。 然后添加一个新的GameObject,将其命名为“Simulator”。 现在添加组件RVOSimulator,您可以在Components -> Local Avoidance -> RVO Simulator中找到它。 您可以看到它有几个选项,但您现在可以将它们保留为默认设置。 但是我建议您稍后阅读RVOSimulator的类文档,因为性能非常依赖于这些设置。 该组件将处理我们的agents的模拟以及存储我们添加的任何动态障碍(稍后将详细介绍)。

 

现在我们想要AI走动。 这将是一个非常简单的AI,它基本上会向前走。 首先在场景中添加一个新的Cylinder(GameObject - > Create Other - > Cylinder)。在场景中的某处创建一个高度为2个单位的Cylinder,将其置于我们之前添加的plane上方可见的位置。 给这个GaneObject添加组件RVOController,您可以在 Components -> Local Avoidance -> RVO Controller中找到它。 这个组件被设计成几乎可以直接替换Unity的Character Controller,因此如果您使用过character controller,您将会觉得它很熟悉。 由于显而易见的原因,它不支持某些碰撞特定的东西,比如碰撞标志,但它非常相似。 由于我们的Cylinder高2个单位,因此将RVOController上的高度变量设置为2。

 

现在按播放! 如果一切顺利,您的Cylinder很可能会飞向空中。 这是预料之中的,我会告诉您如何避免它。 如果您没有从您的Cylinder中看到这种行为,那么浮点数学就是美好的一天。 将Cylinder移动一点,您可能会看到它。

 

那么是什么导致了这种情况呢?为了能够将agent定位在正确的Y坐标,并且由于没有使用colldiers,RVOController使用了光线投射。基本上,它从agent的中心向下发射一条射线,看它击中哪里,然后把agent的脚放在那一点。这里的问题是,Cylinder上有一个capsule collider,所以射线会击中capsule,并且脚本将使探测器从其先前位置向上一小段距离定位。下一帧,它将再次找到capsule collider,并将其放置在更高的位置,因此它继续并产生Cylinder飞向空中的效果。解决方案很简单,要么您从agent中移除capsule collider,这是最直接的事情,因为它将不再需要,或者如果您真的想要它,您可以将agent放在另一个层中,并编辑RVOController组件上的“mask”变量。 我不会在这里完成RVOController组件的所有设置,请查看类文档以供参考。

 

现在我们已经让AI站在了地面上,我们想告诉它做一些事情:所以启动你最喜欢的文本编辑器并创建一个名为SimpleRVOAI.cs的脚本。 这是它应该包含的内容:

using UnityEngine;
using System.Collections;
public class SimpleRVOAI : MonoBehaviour {
    
    RVOController controller;
    
    // Use this for initialization
    void Start () {
        controller = GetComponent<RVOController>();
    }
    
    // Update is called once per frame
    void Update () {
        controller.Move (transform.forward * 10);
    }
}

这并不需要一个专业的程序员去了解它的作用。我们只需要在开始时得到RVOController,每一帧我们都将期望的速度设定为向前方向的10m / s,就这么简单。如果您将此脚本添加到您的cylinder并按play,那么它应该在一个稳定的阶段向前移动。

现在是有趣的部分。复制cylinder,将其置于第一个cylinder的前面,然后旋转,使它们面向对方。按下play。cylinder应该互相靠近,在碰撞前,避免相互碰撞!不是,太棒了!

 

A* Pathfinding Project包含的AI脚本(AIPath)可以直接使用RVOController,只需将RVOController添加到带有AIPath组件的GameObject,并确保它没有其他移动组件(rigidbody or character controller),它将检测到RVOController。

 

障碍

可以在模拟中添加动态和静态障碍。 第一部分将讨论navmeshes,第二部分将更广泛地讨论obstacles。

 

导航网格

如果您使用的是基于导航的图形,您很可能希望您的agent不去外面,甚至可能避免图的边界。幸运的是,编写了一个简单的脚本就可以做到这一点。它被称为RVONavmesh,可以在Components - > Local Avoidance - > RVO Navmesh中找到。 将其添加到场景中的任何GameObject,当扫描或加载图形时,它会将其边界添加为RVO障碍。

 

注意:对网格图的支持将包含在将来的更新中,现在只有基于导航网格的图才有支持。

障碍

障碍可以添加到模拟中。agent将无法通过它们(除非相对于fps以非常高的速度移动)并且agent也可以通过基本的局部避免来避免它们,但RVOController也可以通过基于力避免墙,因为这样AI没有碰到墙壁时,它往往看起来更好。

 

在Components -> Local Avoidance中可以找到一些内置colliders。如果你想编写自定义colliders,请查看页面(Writing RVO Colliders)。

 

内置collisers可以根据需要移动,并且可以适当更新。但仅仅因为它们可以在它周围移动并不意味着它们可以被用来推动agents。事实上,它们很不擅长。只要它们移动得非常慢,它就可以工作,但是如果它们移动太快,agents就会卡在里面。

 

colliders共同的一个变量是障碍模式字段。Writing RVO Colliders 教程中解释了它的内部工作原理,但它非常基础。 KeepOut将阻止agents进入障碍物,但不会阻止它们在障碍物内离开障碍物,KeepIn会反其道而行,两者都会阻止他们越过边界。

 


                                                                                       

本篇只翻译了local avoidance这一部分的内容,主要还是希望有更多的小伙伴们可以知道这个很好的避开agent的方法,如果翻译中有什么不恰当的地方欢迎小伙伴们留言,我会及时更正。

 

原文链接:

https://arongranberg.com/astar/docs_beta/local-avoidance.html

 

 

猜你喜欢

转载自blog.csdn.net/Kathy_unity/article/details/81211208
RVO