Chicken的代码解剖 :3 ChickenAIController_Fox(寻路部分)
Posted on 2012-11-08 17:37 neocsl 阅读(414) 评论(0) 编辑 收藏 举报在上一节的AIController中,徘徊寻路的程序已经对Chicken绰绰有余了,但是难点出来了。狐狸要觅食,他们饥不择食的抓小鸡吃!所以得单独的写狐狸抓小鸡的寻路。让我想想在AntGame中是怎么去使用这个技术呢,AntGame中的机器人在发现主角的时候会开枪攻击,但这里的狐狸根本就是视域360°,他们会把周围出现的小鸡都扫描到。因此这种机制可以帮我策划一个新的内容,一种巡逻小型机械警察,或是Boss。谁知道呢,只要有技术我就能想办法运用!这时候我立马修改了自己的qq签名“技术支撑想法!”我觉得这句话很不错,那么就伴随着得意洋洋继续往下走吧。
先研究变量
//狐狸在一开始的时候不带有任何侵略性,让他在场子上热热身 var float MinNonAggressiveTime; //在被抓起放下后得等他回过神来,才能继续狩猎 var float RestartHuntDelay; //捕猎的时间间隔 var float HuntSearchInterval; //当前的猎物以及被抓住的鸡 var actor currentPrey,currentGrabbedPrey;
下来弄函数,基本上我们会跟着类的执行流程走,而不是压行去看代码。天呢那样很傻不是吗;)
event PostBeginPlay() { super.PostBeginPlay(); //上边的变量中说过一开始没有攻击性,在该函数最好不过了,然后进入捕猎函数BeginHunt SetTimer(MinNonAggressiveTime,false,'BeginHunt'); }
那么就进入BeginHunt函数一探究竟吧。
function BeginHunt() { //早预感到这个类不单纯,还得根据fox的AllowHuntBegin函数来判断执行是否prey。那么FoxPawn是在什么情况下允许捕猎呢? if(ChickenPawn_Fox(pawn).AllowHuntBegin()) { GotoState('HuntPrey'); return; } //不能狩猎那就自己循环,直到FoxPawn做好准备为止 SetTimer(HuntSearchInterval,false,'BeginHunt'); }
Ok,接下来我们进入HuntPrey状态。我们既然按流程走当然不从函数定义开始,从begin走,遇到函数进去。好了活体编译器们,让我们冲吧。
begin: if(currentPrey==none&&!FindPrey()) { GotoState('Wander'); }
FindPrey是一个定义在外部的函数。有一些定义在pawn中的函数暂时不去研究。
function bool FindPrey() { //目标 local Actor checkTarget; //最近的距离,当前检测目标的距离 local float closestDistance,currentCheckDistance; //当前最佳目标 local actor currentBestTarget; //初始值取最大,待取值的时候再缩进 closestDistance=9999; //遍历所有的actors,当然这里还有一个Interface_DraggableItem也就是接口,可以更加缩进遍历范围 foreach DynamicActors(class'Actor',checkTarget,class'Interface_DraggableItem') { //先要检测场景里面是否有狐狸 ,我想应该是小鸡才对! if(ChickenPawn_Fox(checkTarget)!=none||ChickenPlayerController(ChickenPawn(checkTarget).controller)!=none) continue; //还没有探讨到拖拽以及接口的内容,我们先绕过这里 if(Interface_DraggableItem(checkTarget).AllowDragging(self)==none||ChickenPawn_Chicken(checkTarget).currentTimeOutStage==TO_STAGE_THREE) { continue; } //同样的走进Pawn才能判断到底是怎么回事 if(ChickenPawn(checkTarget)!=none&&ChickenPawn(checkTarget).TargetedBy!=none) continue; //当前检测的距离 currentCheckDistance=VSize(checkTarget.Location-pawn.location); if(currentCheckDistance<closestDistance) { closestDistance=currentCheckDistance; //这是要找的最重要变量 currentBestTarget=checkTarget; } } if(currentBestTarget!=none) { if(ChickenPawn(currentBestTarget)!=none) { //在pawn的函数中具体是什么样子我还不得而知setTargeted(self) ChickenPawn(currentBestTarget).SetTargeted(self); } currentPrey=currentBestTarget; return true; } return false; }
让我们把记忆闪回到HuntPrey状态中找明真象。
if(!IsPreyValid()) { GotoState('Wander'); }
又是一个讨厌的函数,如果猎物无效了就得回到徘徊状态中。当然这是很安全并且自然地处理方式。我们看看IsPreyValid()函数。
//该函数用于检测狐狸当前的猎物是否有效,被抓起或是被destroy了 function IsPreyValid() { local bool prePendingDestroy; //currentPrey一个actor,actor中有两个属性bPendingDelete和bDeleteMe分别是将要被删除的属性,将两个相或就是别让这种可能发生。 preyPendingDestroy=currentPrey.bPendingDelete||currentPrey.bDeleteMe; //至于接口的内容我确实很头疼,但第二个或的意思是只要没被拖动,第三个是猎物不要是自己 return !prePendingDestroy&&Interface_DraggableItem(currentPrey).AllowingDragging(self)!=none&&ChickenPawn(currentPrey).TargetedBy==self; }
那么看看到达猎物的生成路径
//尝试生成路径 if(GeneratePathToActor(currentPrey,Pawn.GetCollisionRadius())) { //如果生成路径成功,尝试到达目标 if(NavigationHandle.ActorReachable(currentPrey)) { MoveToward(currentPrey,currentPrey); } //如果到不了 else { //到不了就重新到达一个附近点 if(NavigationHandle.GetNextMoveLocation(NextMovePoint,Pawn.GetCollisionRadius())) { //给一个建议点 if(!NavigationHandle.SuggestMovePreparation(NextMovePoint,self)) { MoveTo(NextMovePoint); } } } } else { GoteState('Wander'); } sleep(0.1f); goto'Begin'; }
我们一直看到每次搜寻猎物失败就会进入Wander状态,也许你很好奇,那么现在就来一探究竟吧。
auto State Wander { simulated event BeginState(name PreviousStateName) { //如果不在BeginHunt的状态那就重启BeginHunt。好像狐狸就一直追小鸡吃。 if(!IsTimerActive('BeginHunt')) SetTimer(RestartHuntDelay,false,'BeginHunt'); super.BeginState(PreviousStateName); } simulated event EndState(name NextStateName) { StopLatentExecution(); //将徘徊路径设为假,这样就能继续找路径 bHasWanderPoint = false; ClearTimer('BeginHunt'); } }
再次回到HuntPrey状态中,他的BeginState和EndState使我们不能忽略的内容。分别在进入状态的时候便会执行。
simulated event BeginState(name PreviousStateName) { //寻找猎物 FindPrey(); //当前角色所在的位置 PreviousStandLocation=Pawn.Location; //检测卡住时间 SetTimer(StuckTimerCheckDelay,true,'CheckStuckTimer'); } simulated event EndState(name NextStatName) { if(ChickenPawn(currentPrey)!=none) { //如果当前的目标非空,那么将其设为空。一定要在pawn中好好看看SetTargeted ChickenPawn(currentPrey).SetTargeted(none); }