6:《地牢守卫者》代码分析:GoblinPawn,GoblinController

  Goblin是一个近战攻击的敌人,该敌人挥舞自己的棒子思密达,棒子上有一个插槽,再执行动画的时候有一个Script notify跟踪这个插槽的位置判定是否能打到主角。

   既然要获取插槽的位置就得写一个方法来获取  

var name MeleeSwingSocketName;

  function vector GetMeleeSwingSocketLocationAndRotation()

  {

    local vector MeleeSwingLocation; //存储获取插槽的位置

    local rotator MeleeSwingRotation;

    Mesh.GetSocketLocationAndRotation(MeleeSwingSocketName,MeleeSwingLocation,MeleeSwingRotation); //官方提供的获取插槽的好方法

    return MeleeSwingLocation;
  }

  记着在AnimSet中标注的pawn脚步声,用同样的方法,建立一个script notify,

为其命名名字分别为:MeleeSwingStart和MeleeSwingEnd,命名之后将会以event的形式调用

event MeleeSwingStart()

{

  EnemyController(Controller).StartMeleeSwing(); //在动画挥舞放置的notify出会调用该函数
}



event MeleeSwingEnd()

{

  EnemyController(Controller).EndMeleeSwing(); //在动画挥舞定义的结束处会调用此函数
}

Goblin中定义的函数就这些,进入GoblinController中观察

事实上前面的EnemyController已经解决了敌人寻路的基本功能,在以下的类中将根据不同类型的敌人来扩展功能,Goblin扩展了近战Melee的能力,而DarkElf将会实现远战的功能。

  在执行一个攻击动画的时候,扫描了棒子的Extent,然而扫描的时候如果不加限制在碰撞的整个过程中将会给物体造成持续伤害。因此建立了一个列表,在一次攻击动画中将受伤的actor加载到列表上,在动画清空的时候清空列表,记录到列表上的actor将不会产生二次伤害。

  

  var bool IsInMeleeSwing
  var vector PreviousMeleeSwingHitLocation;      //该变量和slapLocation组成扫描插槽区间,设成全局变量用于好几个地方
  function StartMeleeSwing()                 //该函数写在Attacking状态中

  {

    IsInMeleeSwing=true; //用tick来启动获取插槽

    PreviousMeleeSwingHitLocation=AntEnemy(Enemy).GetMeleeSwingLocation(); //赋予插槽
  }

    

  在Attacking状态开始时调用。

function EndMeleeSwing()

  {

    IsInMeleeSwing=false;

    SwingHurtList.Remove(0,SwingHurtList.length);
  }

  添加到列表中

function AddToSwingHurtList(Actor newEntry)

  {

    local int i;

    for(i=0;i<SwingHurtList.length;i++)

    {

      if(newEntry==SwingHurtList[i])

      return false;
    }

      SwingHurtList.addItem(newEntry)

      return true;

  }

  下来是最重要的函数,该函数用于检验攻击碰撞并产生近战攻击伤害。该函数写在Attacking状态内。

  state MeleeAttacking extends Attacking

function DoMeleeSwingTrace()

  {

    local vector HitLocation;

    local vector HitNormal;

    local vector SlapLocation;

    local TraceHitInfo hitInfo

    local Actor Traced;

    slapLocation=GoblinEnemy(pawn).GetMeleeSwingLocation();

    foreach TraceActors(class'Actor',Traced,HitLocation,HitNormal,SlapLocation,PreviousMeleeSwingHitLocation,MeleeSwingExtent)

    {

      if(traced!=self&&AddToSwingHurtList(traced))

traced.TakeDamage(MeleeDamageAmount,self,HitLocation,Normal(Trace.Location-Pawn.Location)*MeleeDamageMomentum,class'DamageType',Pawn);           
    }
    PreviousMeleeSwingHitLocation=SlapHitLocation;
  }

  TraceActors( BaseClass,Actor,HitLoc,HitNorm,End,start, Extent)要跟踪的类,类的变量,攻击位置,攻击发现,追踪末尾点,追踪起始点,体积

红色标注的是插槽,箭头指向的是攻击挥舞的方向,遍历函数TraceActors()来计算一段射线和目标物的碰撞。

这儿的技巧是PreviousMeleeSwingHitLocation=slapLocation看Tick函数他会调用DoMeleeSwingTrace()函数

event Tick(float DeltaTime)

{

  super.Tick(DeltaTime);

  if(IsInMeleeSwing)
  DoMeleeSwingTrace();        //在攻击状态中不断地调用,从而形成slaplocation和PreviousSwingHitLocation插槽扫描区域区间
} 


 以下是在Attacking状态中

Begin:
StopLatentExecution();
EndMeleeSwing();
Goblin(Pawn).PlayAttackAnimation();

PopState(0);
原文地址:https://www.cnblogs.com/NEOCSL/p/2368677.html