UE4简单AI
首先做个小小的声明把,由于俺之前也没接触过AI ,所以有一些专业的词汇可能翻译存在各种问题,如果你发现的话,还是希望能够提出来哦,我们一起进步。 记住配合视频食用更佳哦~ 视频连接:http://www.unrealedu.org/course/15/learn#lesson/79 此外,我也在翻译官方那本C++的教程,已经读完,想着还是用视频的方式来准备,大家如果有什么意见希望可以提出来。好了废话不多说,开译!
第一篇:简单了解AI并创建NavMesh
嗨,大家好,我是PeterNew,谢谢大家收看我的AI NewMesh(自动寻路)演示教程。接下来的五段视频主要会接触到UE4的nevMesh自动寻路,当然也有行为树(Behavior Tree),那将会成为处理AI最有效的办法。好的,接下来呢,我们将会创建一个NevMesh,创建一个AI角色,创建一个控制器,并且创建WayPoint(导航点),数据资源(data assets),bot状态枚举,创建用来控制bots的行为树,我们接下来将会针对行为树创建一些任务,装饰器和服务? 接下来我将会详细的讲述这些组件功能。那现在我们就开始吧。
首先我要给你们展示一下到目前为止,我做出来的功能,这也是你们今天要做的。正如你所看到的,现在有一些我添加的任务他决定了AI可以接下来做啥,有很多不同的导航点,1,2,3...on,这个家伙开始向我攻击,哦,他让我掉了下来,你可以发现,这家伙他可以正常工作,但总是给我惹一些麻烦。好的,这里有很多我定义的动作,你会发现AI角色慢慢的从导航点1一直移动到6,好吧,他又一次看到了我。没有什么可以阻挡他,走到设置的导航点那里。好吧,那我们就正式开始吧。好的,正如你所看到的,我刚刚仅仅把之前的关卡在这里复制了一份,当然,我忘了一件事,我的名字。我从不开玩笑o(╯□╰)o。
好的,接下来我们添加自动寻路的区域边界(NavMeshBoundsVolume),(这几个点,移动一下,这几个点,移动一下o(╯□╰)o,接下来就是调整边界的大小)。注意,这个自动寻路的区域一定要包裹住整个你想要生成自动寻路能够到达的所有地方,好了,就像你看到的,它已经包围住了所有的东西。接下来要创建自动寻路Buid NavMesh,好了,我们已经创建好了NavMesh,如果想要编辑你的navMesh。
你可以搜索一下RecastNav(编辑NavMesh),你会在这里发现一些设置,有很多选择可以控制你的NavMesh究竟如何工作,这里呢,我就使用默认的了,要想创建你的AIbot,我们需要使用一个经常使用的角色,添加一些资源,做一点简单的修改。我们经常会看到这个蓝色的男人,但这里我将会使用一个不同的角色,如果你对这个角色很熟悉的话,没错,他就包含在虚幻四的那个Content的项目中,我给他添加了一把枪,添加了一些例子效果(比如...和拖尾)。
然后,你创建两个事件,一个用来通知acotr发现了敌人,一个用来通知actor敌人已经消失,好,首先创建第一个事件:发现敌人(EnemyFound),第二个敌人消失(EnemyLost),作为演示,这就是我主要使用的actor,好吧,发现敌人就开始攻击,敌人消失就停止攻击,把两个事件拖放到场景中,创建事件,我简单给你演示一下怎么改变actor 的动画,首先获得Mesh->播放动画->选择动画资源。接下来说第二种,当发现敌人的时候,它开始播放,当敌人消失的时候,你将会充值动画,让他还原到默认状态。GetMesh->SetAnimationMode,然后就可以使用动画蓝图了,这样就可以重置动画到任何你已经存好的状态了。好了保存,编译。
接下来,我们需要创建AI 控制器,创建蓝图类,父类选择AIController,命名为botAI。然后你会发现这里有一些不用的组件。在图表中,输入事件BeginPlay-》RunBehaviorTree(运行行为树)。现在我们还没有行为树,保存编译一下,接下来我们要创建一个枚举,用来定义状态和转换,创建枚举,(译者注:注意,我这里最新版的UE4枚举是在“蓝图”里面)命名为botState,添加一个Patrol,Search,和Attack。接下来我们要创建的是数据资源(deadAssets),数据资源类别选择Blackboard,取名为botData,在这里我们创建一些函数可以引用到的信息。接下来我们要创建的第一个都给就是目标点,这将告诉我们的角色它要去的下一个地方,KeyType为BlackBoardKyeType_Vector。接下来创建AI的状态,KeyType为枚举Enum,选中我们刚刚创建好的botState枚举。接下来创建敌人,取名为EnemyActor,KeyType为Object。接下来我们创建路线(Route),KeyType为int。这样就都创建完毕了。
接下来我们就要创建AIbot 了,在这之前,这个选项还不能找到,我们需要设置一下。点击编辑--编辑器偏好设置--实验性功能--勾选BehaviorTreeEditor(译者注:我用的4.7版本的UE4已经没有这一项了)。好了,接下来就创建一个BehaviorTree(其他--行为树),取名为botAITree,打开它。你要注意的第一项内容是blackboard,这里我们要选择botData,这将会告诉bot在运行的access thing and reference thing整个过程里要做什么(?)。接下来要创建的是AI way point(航路点),新建一个蓝图类,父类为TargetPoint,取名为botWayPoint,打开它,添加一个变量,取名为Position,int类型,让他变成可以被编辑的(共有的),保存编译。接下来就要定义一些导航点了,如果你还记得之前的演示的话,这里有一个,那里有一个....1,2,3,4,5,6。观察我的工程你将会发现有6个标记,从1-6 Position的值由0变到5。
好的,接下来我们要创建的是任务task,第一个任务是角色走的由慢变成快,回到botCharacter蓝图,创建一个Tick事件,GetCharacterMoment->SetMaxWalkSpeed,创建两个变量,一个是SpeedRate和SpeedVariable,都是int,编译。SpeedVariable的默认值为150,speedRate的默认值为1。SpeedVariable * SpeedRate 结果作为输入连接到MaxWalkSpeed。把这个拖放下来,连起来,这就是我们要的。这里的所有东西就是我的射击逻辑了。保存编译。
接下来我想做的是改变行走的速度,创建一个蓝图类,父类为BTTask_BlueprintBase,取名为BTT_BotWalkSpeed,到目前为止,我们还没有创建一个行为树的任务,你需要右键添加一个叫做EventReceiveExecute的事件节点,给他添加一个注释:BeginExecute,下一个创建FinishExcute(完成执行),建立这两个节点的原因是为了让行为树之间沟通,一开始,你通知这个BeginExecute,接下来当你完成以后,你使用finishe这个节点告诉行为树,完成了。整个过程其实很简单。acotor会被行为树控制立刻执行,如视频当中连接,把otherActor转换为botAI->GetControlledPawn->CastToBotCharactor,这样的话,我们就可以访问WalkSpeed的变量了,>SetSpeedRate,把这个节点连接到FinishExecute上,我们给这一段添加一个注释:改变BOt的行走速度。我们需要另外一个变量以便可以在行为树里面更改行走的速度,新建变量WalkRate,类型为float,并且设置为可以被编辑的(公有变量),把它获得并连接到这里,编译,保存,默认值设置为1。保存一下。既然现在你可以编辑你的第一个行为树的任务,接下来,我们将会在下一段视频中介绍怎么让bot四处巡逻起来~
第二篇:了解AI Navigation
现在是教程的第2/5部分,我们将会给敌人创建行为树任务,和导航bot 完成 do the rounts(路),我们将可以导航bot走向敌人,好了,,创建蓝图类,父类为BTTask_BlueprintBase,取名为BTT_botNextRoute,打开它,在这个任务里我们需要添加两个BlackboardKeySelector变量,首先创建TargetPoint,类型为BlackboardKeySelector,创建另一个,Route。接下来我们要创建另外一个变量,maxRoutes,它定义了AI要寻找有多少条路,即使我们在这里创建了导航点,我们也有可能需要我们的AI角色控制你的任务,所有把这三个变量全部变成共有可编辑的,保存。然后,和之前一样,我们要添加两个事件:事件ReceiveExecute(4.7中文版本),和FinishExecute并给他们添加注释:开始执行、结束执行。接下来首先获得Route->GetBlackboardValueAsInt(以int型获得黑板值),并且和maxRoute做比较,如果大于等于maxRoute,则把黑板值设置为0,然后获得所有botWayPoint类的对象,然后或得到数组里面的每一个元素,使用ForEachWIthBreak节点,把complete端口,连接到finish的入口处,把finish执行事件节点稍微往后拖放一下,接下来我们把数组中的元素转换为botWayPoint,获得每一个的位置,复制一下左边的节点,比较他们是否相等,接下来我们要做的是把黑板值blackboardvalue值设置成vector,所以,我们先或得到TargetPoint的变量,把它设置为vector,我们先把finish节点拖放下来,位置信息是来源于这里,所以,获得数组中物体的位置,把他们赋值给TargetPoint,保存编译一下。
接下来我们要回到AI行为树,来完成下面要做的,点击节点,就像我们图表里面节点一样,获得选择器(selector),选择器将会调用位于他下面的所有事情,还有一个节点叫做序列(Sequence),而这个节点只在当之前的函数被成功调用后,调用下一个函数,所以这边是按照顺序来执行的,这就是sequence,而selector会调用所有的。还有一个节点叫做SimpleParallel,这个节点允许你调用一个函数,而它调用另外一个函数,所以这边可以是BTT_WalkSpeed,而另一边可是调用MoveTo,这两个任务是同时调用的。而在这里,我们想做的是,创建另一个选择器(selector),接下来调用BTT_botWalkSpeed,接下来我们还要调用BTT BotNextRoute,最后一个要调用的函数是MoveTo,这里就是这些函数了,改一下节点的名字,“ChangeWalkSpeed”,这样就更容易被编辑,第二个节点的名字改为FindRoute,第三个MoveToRoute。第一个节点这里问可以看到之前定义的变量WalkRate行走速度,我们把它改为2,第二个节点,这边有几个变量,TargetPoint和Route都是共有的,首先根节点告诉你要开始行走了,接下来,这两个值告诉你应该从哪里走到哪里,所以我们的TargetPoint变量的值为TargetPoint对象,而Route的值为Route对象,MoveToRoute这里需要一个黑板值,所以它需要做导航,所以Blackboard这里要选择TargetPoint。
接下来我们为选择器节点添加另外一个东西,这样他就可以正确的选择了,右键点击,添加一个装饰器,值为Blackboard,选择添加的这个黑板值,把它的名字改为巡逻(patrol),它的黑板值为State,KeyQuery为isEqualTo,(查询类型为是否等于)值为巡逻,好了,所以这一部分正常发挥作用的前提是,bot的状态为巡逻。我们在另一边创建另外一个选择器,做同样的事情,添加黑板blackboard装饰器,改名为搜寻并且攻击(Search & Attack ),选择blackboard的值为state,查询类型为大于等于,值为Search或者attack,所以只有当攻击或者搜寻的时候,才会调用这边。我们给他自动排列一下。search&Attack 这个装饰器和之前的有点不同,你可以创建自己的装饰器,装饰器是一些加在任务上的一些条件,我们来快速浏览一下这些装饰器们,这里有ForceSuccess、循环、限时、达到目标,这些装饰器可以多个用来额外的添加到任务上,所以你可以同时限制forceSuccess或者超时等等你想要的条件。
好了,接下来我们回到内容浏览器。我要添加另外一个任务叫做MoveToEnemy(向敌人移动),同样创建一个父类为BTTask_BlueprintBase的蓝图类,取名为BTT_botMoveToEnemy,我们首先创建两个黑板类的变量,一个是路(route),一个是状态(state),第一个取名为敌人物体(enemyActor),另外一个是State,接下来我们创建一个半径(Radius),用来判断到敌人的距离(?And This is simply allow you to minite delate,the subtance radios from the move to the actor),把这些变量都改成公有的。接下来创建事件ReceiveExecute节点,把actor 转换为botAI,我们想要获得他的状态,以枚举的方式获得黑板值,然后我们想要通过boteState的状态来做出选择,如图连接,把这两个往上移动一下,把state节点往下移动一下,腾出更多的空间,我们想要或得到敌人物体(enemyActor),以object的类型获得他的黑板值,把这个object转换成角色Character,从search的端口连接过来,接下来我们设置ai的焦点(?),我想做另外一件事,设置物体的旋转信息,所有我们或得到botAI被控制的pawn,设置它的旋转信息,或得到角色的位置,然后获得AIbot到玩家的LookAt对应角度,把角度的三个值分离,制作一个旋转值,仅仅只改变yaw,接下来继续获得物体的旋转信息,使用RInterTo节点,制作好的Rot作为目标值,得到的信息作为当前值,使用GetWorldDeltaSeconds节点,把插入速度改为6,来更新旋转信息。
接下来控制botAI 使用MoveToActor节点,把Radios值作为AcceptanceRadios,关闭CanStrafe,把你的目的actor转换为节点当中的目标端口值,往下走两行,我们来设置物体的旋转信息,从attack的输出端口连过来,把新得到的旋转值放到这里,这意味着当角色正在被攻击的时候,他是可以被吸引的(engaged)。
最后我们要做的是,添加完成执行节点,从这里连接过来,当转换失败时,意味着没有敌人,我们也要完成完成执行,当然,巡逻状态下,也要连接到完成执行节点。这个任务的三个选择最后都要连接到finishExecute节点,因为我们需要这个节点来时外面的序列继续执行,勾选success,我们最后要添加一个东西来结束这次的视频,(要做的就是处理错误的情况),我们从MoveToActor的输出端口连线,到Gate节点,添加EventReceiveTick事件,把它连接到Enter端口,把MoveToActor的输出连接到Open口,然后要做的是添加一个分支节点,继续添加FinishExecute节点,bSuccess为真,接着把它的输出连接到Gate的Close节点。如果是false的情况,添加一个SwithchOnEPathFollowingStatus节点,然后我们要得到当前的AI的状态,我们要从botAI连接,获得MoveStatus,作为Switch的输入,获得状态,设置为枚举,val值为2,连接到idle,把这些稍微往后放一下,连接刚刚的到的枚举和FinishExecute节点,这样的话,我们就把执行的操作完成了。
最后添加注释,给两个finishExecute添加注释,这样我们就很容易找到结束的位置, 对中间的逻辑部分添加注释:朝着敌人移动。这期我们能够导航AI找到敌人,下一期我们将攻击敌人!
|