让我们来终结AIController所要解决的全部问题。我们是一群酷家伙。

1.平滑的调整转向的问题

function Tick(float DeltaTime)

{

  local rotator DesiredRotation;

  super.Tick(DeltaTime);

  if(Pawn!=none&&Pawn.Health>0)

  {

    DesiredRotation=Rotator(GetFocalPoint()-Pawn.Location);

    Pawn.FaceRotation(RLerp(Pawn.Rotation,DesiredRotation,3.125f*DeltaTime,true),DeltaTime);
  }

}

2.使用一种低性能的寻路方式

  先使用FastTrace检测Pawn和目标之间的直线有没有障碍,如果有CanReachDestination直接返回false。检测的线体积是角色的碰撞圆柱。

function bool CanReachDestination(vector CheckDestination)
{
     local Actor HitActor;
     
     local vector HitLocation,HitNormal,pathCollisionExtent;

}

  使用FastTrace这种方式高效检测,然后使用TraceActors

3.刚才收到新华社的最新消息,强制类型转换是一种慢节奏的运行效率。因此使用Interface可以高效的减少该方面导致的性能损耗。在Controller中声明一个变量,这个变量在Possess中指代正在占用的pawn。

 

  要研究一个机制,往往他会和外部一些事物有一些牵连。就像青豆和天吾在冥冥之中有所联系。因此一个类如果和另外的内容有牵连,最好的方法是将这些内容连根拔起看个究竟。

  Factory和Route是重要的一环,其次Interface这个抽象内容也有联系。Interface知道的是划定一下敌人范围,这可能在玩家死亡时剔除场景中的所有敌人有很大的帮助 。我使用的方法是,只要玩家在一个区域内达成一定的要素,再次死亡就不会激活该区域的敌人触发,而敌人是生成器的方式产生的。将生成器通过一种事件来作废,什么事件呢?最后一个敌人或是“看门人”是最好的方法。

  

  可以看到这里的方法并不难,获取Route的位置。

4.接口 

  Pawn中实现接口,需要实现他们能不能攻击或者被攻击。 、

  FireMode.uc使用一个圆柱检测敌人伤害,它最大化的节省了性能,继承自Object而非Projectile。他使用VisibleCollidingActors来遍历碰撞。碰撞遍历的Actor和武器的发射方向。

     有一个AntAttackInterface是这个武器的拥有者,WeaponOwner。

class AntWeaponFireMode extends Object;

var AntAttackInterface WeaponOwner;

function SetOwner(AntAttackInterface NewWeaponOwner)
{
     if(NewWeaponOwner==none)
     return;

     WeaponOwner=NewWeaponOwner;
}

  武器的射击角度

function float GetAttackingAngle()
{
    return 0.95f;
}

  毁灭之,也许我之前的很多代码都造成了内存泄露,在Debug的时候一定要执行清空动作

function Destroy()
{
    StopFire();
    WeaponOwner=none;
}

  StopFire中WeaponOwner接口能一窥GetActo的东西。GetActor推测应该和武器有很大的关系。

function StopFire()
{
     if(WeaponOwner!=none)
    {
        WeaponOwner.GetActor().ClearTimer('Fire'),self);
    }
}

  StartFire也是一个重要的部分,该函数内部有发弹频率和pawn的描述,一会看看具体内容。

function StartFire()
{
   local float FiringRate;
   local AntPawn AntPawn;
    
   if(WeaponOwner!=none)
  {
      Fire();    //what he is doing here?Wait Down There
       AntPawn=AntPawn(WeaponOwner);
      
       if(AntPawn!=none)
     {
           FiringRate=AntPawn.BaseAttackTime;   //`SinceTime kind 
           if(AntPawn.AttackSpeed>-1)
           {
                  FiringRate/=(1.f+AntPawn.AttackSpeed);
            }
                 WeaponOwner.GetActor().SetTimer(FiringRate,true,'Fire',self);
           
     }
     
  }
}

  有一个检索武器是否处于开火的函数,其实就是检测Timer函数是否在执行,用IsTimerActive?

function bool IsFiring()
{
     if(WeaponOwner!=none)
    {
        return WeaponOwner.GetActor().IsTimerActive('Fire',self);
    }
}

  开火函数Fire,在StartFire中被调用。并且在子类中不被继承

final function Fire()
{
    local vector FireLocation;
    local Rotator FireRotation;
    local Actor CurrentEnemy;

    if(WeaponOwner==none)
    return;
    
    CurrentEnemy=WeaponOwner.GetEnemy();
    if(CurrentEnemy==none)
    {
         StopFire();
         return;
     }

     WeaponOwner.GetWeaponFiringLocationAndRotation(FireLocation,FireRotation);

     BeginFire(FireLocation,Rotator(currentEnemy.Location-FireLocation),CurrentEnemy);
}

  BeginFire到底是怎么一回事?这要影响到每一种武器的详细射击模式了,如果他们再次回到了Projectile那就叫人不高兴了