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);
 }