5:《地牢守卫者》代码分析:EnemyController

Posted on 2012-02-25 15:00  neocsl  阅读(615)  评论(0编辑  收藏  举报


  紧接着Enemy将要查看EnemyController,EnemyController继承自AIController。

  一个典型方法让敌人找到玩家

  

var Pawn Enemy;

  event Tick(float DeltaTime)

  {

    local PlayerController PC;

    if(Enemy==none) 

   {

    Foreach LocalPlayerControllers(class'PlayerController',pC)

    {

      if(PC.Pawn!=none)

      Enemy=PC.Pawn;

    }
   }

  }

在foreach中如果找不到玩家的pawn,可以让敌人暂时停下

pawn.Acceleration.x=0;

Pawn.Acceleration.y=0;

有一个官方函数PawnDied(Pawn inpawn),旨在表述pawn死了的执行动作

function PawnDied(pawn inpawn)

{

  if(inpawn==pawn)

  Enemy=none;

  super.PawnDied(inpawn);

}

下来是重点,寻路一直是个有难度的地方。这里提到两个函数

1.MoveTo (vector NewDestination, optional Actor ViewFocus, optional float DestinationOff)

该函数在没有寻路的情况下可以让pawn走到一个坐标位置

2.MoveToward((Actor NewTarget, optional Actor ViewFocus, optional float DestinationOffset)

可以让一个pawn走向一个Actor。

因此最简单的一种方法是在controller中写一个状态

var actor Enemy;

auto state Follow
{
Begin:
Enemy=GetALocalPlayerController().Pawn;
MoveToward(Enemy,Enemy,128);
goto 'Begin'; //因为MoveToward只能执行一次,用该方法循环执行
}

下来这个环节是重要的寻路算法,同时使用了MoveToward和MoveTo两个函数,前者是当寻路成立时可以直接到达目标Actor,后者是在寻路不成立时让该pawn暂时先行前进到临时TempDest目标点。

自动进入Idle然后获取Player.

auto state Idle
{
event SeePlayer(pawn inpawn) //参数是看见的pawn
{
local pawn Player;
if((Player=GetALocalPlayerController().pawn)!=none)
{ super.SeePlayer(Player);
Enemy=Player;
Gotostate('Follow');}
}
Begin:
}

获取了Enemy将进行寻路

state Follow
{
ignores SeePlayer;
//该函数寻路看能否找到目标点
function bool FindNavMeshPath()
{
// Clear cache and constraints (ignore recycling for the moment)
NavigationHandle.PathConstraintList = none;
NavigationHandle.PathGoalList = none;

// Create constraints
class'NavMeshPath_Toward'.static.TowardGoal( NavigationHandle,Enemy ); //寻找Enemy
class'NavMeshGoal_At'.static.AtActor( NavigationHandle, Enemy,32 );

// Find path
return NavigationHandle.FindPath();
}

Begin:
if(NavigationHandle.ActorReachable(Enemy)) //无障碍物,最好的情况就是能找到
{
MoveToward( Enemy,Enemy ); //直接走向敌人 AAAAAAAAAAaaaaAAAAAAAA
}

else if(FindNavMeshPath) //如果有障碍,在寻路状态,则进入临时目标点
{
NavigationHandle.SetFinalDestination(Enemy.Location); //敌人位置

// move to the first node on the path
if( NavigationHandle.GetNextMoveLocation( TempDest, Pawn.GetCollisionRadius()) )
{
MoveTo( TempDest, Enemy ); //先找到临时节点,Enemy是最重要找的对象
}
}

else //最糟的结果是找不到,可能玩家已经死了。也就没必要再找了
{
GotoState('Idle');
}

Goto 'Begin'; //保持了更新查找
}


《求生之路》中有些敌人是在场景中Idle的状态,而有些敌人一生成就会朝玩家涌过来。只要在Idle中不用seePlayer而是直接遍历将会生成涌向玩家的敌人。
在前面的AAAAAAAAAAaaaaAAAAAAAA标记地方修改进入Attacking状态攻击敌人

MoveToward(Enemy,Enemy,300);

if(VSize(Enemy.Location-Location)<500)

GotoState('Attacking');

 以下是攻击状态

 

state Attacking
{
function NotifyTakeHit(Controller InstigatedBy, vector HitLocation, int Damage, class<DamageType> damageType, vector Momentum)
{
PopState();
super.NotifyTakeHit(InstigatedBy, HitLocation, Damage, damageType, Momentum);
}

event BeginState(Name PreviousStateName)
{
super.BeginState(PreviousStateName);
AntEnemy(pawn).StartedAttack();
}

event EndState(Name PreviousStateName)
{
super.EndState(PreviousStateName);
AntEnemy(pawn).EndedAttack();
}

}

攻击状态结束

如果受到伤害将进入受伤状态,在子类中将实现受伤动画播放,在这期间体制所有的latent函数,以及固定敌人角色的位置。这边是硬直的前身。

state Hurt
{
StopLatentExecution(); //停止所有的行为state

Pawn.Acceleration.X=0;
Pawn.Acceleration.Y=0;
Pawn.Acceleration.Z=0;

//播放受伤动画
PopState();
}