7:《地牢守卫者》代码分析:DarkElf,DrakElfController

  DarkElf是远战敌人,该敌人能射出一支箭从而对玩家产生伤害。在执行装箭动画的过程中动态的让箭创建出来并连接到手的插槽上。

  动画情况是这样:DarkElf从后背拿出一支箭,这时候动态生成该箭的模型,当在MeleeSwingEnd的时候(预备实际发出射弹的时候将该Component销毁)

  有两个重要的函数Mesh.DetachComponent(component); //将一个组件从模型上剔除     

   Mesh.AttachComponentToSocket(component,socket);  //将一个组件连接到一个插槽上

  var name ProjectileSocketName;                              //生成的箭射弹插槽

  var name AttachmentSocketName;                         //拿在手上动画插槽

  var vector ArrowLocation;               

  var rotator ArrowRotation;

  var SkeletalMesh ArrowMesh;      

  var vector ArrowMeshScale;

  var transient SkeletalMeshComponent ArrowMeshComponent;

   以上是一些定义在DarkElf中的变量。

  event MeleeSwingEnd()

{

  if(ArrowMeshComponent!=none)

  {

    Mesh.DetachComponent(ArrowMeshComponent);

    ArrowMeshComponent=none; //当把裝箭动作执行完的时候就把该组件给弄消失

  }

  DarkElfController(Controller).FireProjectile(); //这里生成射出的箭
}

   起始攻击动作

 event MeleeSwingStart()

{

  if(ArrowMeshComponent!=none)

  {

    Mesh.DetachComponent(ArrowMeshComponent);

    ArrowMeshComponent=none; //当把裝箭动作执行完的时候就把该组件给弄消失

  }

  if(!controller.IsInState(EnemyController(controller).AttackStateName)) //检测该动作是否在攻击状态中执行

  return;



  ArrowMeshComponent=new class'SkeletalMeshComponent' //新生成一个共箭的组件

  ArrowMeshComponent.SetSkeletalMesh(ArrowMesh);

  ArrowMeshComponent.SetTranslation(ArrowLocation);

  ArrowMeshComponent.SetDrawScale(ArrowMeshScale);

  ArrowMeshComponent.SetRotation(ArrowRotation);

  Mesh.AttachComponentToSocket(ArrowMeshComponent,AttachmentSocketName);
}

  前面讲过GetSocketWorldLocationAndRotation(name,out_location,out_rotation)可以看出不用返回,因为参数是out型

  

function GetProjectileFireOrientation(out vector out_location,out rotator out_rotation)

  {

    Mesh.GetSocketWorldLocationAndRotation(ProjectileSocketName,out_Location,out_rotation);
  }

  这里获取了射弹的方向和位置,稍后再看该函数在哪里进行调用。

  

  现在进入DrakElfController类

   插一个话题,如何使用最简单的方法生成一个火箭炮攻击玩家呢?

  function Fire()

{  

  local UTProj_Rocket MyRocket; //这是火箭筒的射弹

  MyRocket = spawn(class'UTProj_Rocket', self,, Location); //生成是当然的

  MyRocket.Init(normal(Enemy.Location - Location));     //初始化函数Init指定敌人的方向,将会攻击敌人

}

   controller类只不过是将上述程序复杂化了,当然功能和安全性将会更完善。

   

local AntProjectile SpawnProjectileTemplate;

  function FireProjectile(); //在攻击状态外面声明一下该函数

    随后进入攻击状态

  state ShootAttacking extends Attacking

{

   

function FireProjectile()

  {

    local AntProjectile theProjectile; //看看简化函数就明白了

    local vector SpawnProjectileLocation;

    local rotator SpawnProjectileRotation;

      

    DarkElf(pawn).GetProjectileFireOrientation(SpawnProjectileLocation,SpawnProjectileRotation);

    if(VSize(SpawnProjectileLocation)==0) //如果获取不到插槽位置就用pawn.location来替代,这样使代码更为健壮

    SpawnProjectileLocation=pawn.location;

    

    theProjectile=Spawn(SpawnProjectileTemplate,,,SpawnProjectielLocation,SpawnProjectileRotation,SpawnProjectileTemplate,true);

    theProjectile.ProjectileInit(vector(SpawnProjectileRotation),pawn); ////重写了Init函数,为了使用偏差使用
  }


   

 Begin:

      //先播动画,在动画的notify中自然会调用发射事件

      

      StopLatentExecution();

      // if we have an attack animation...
     if(DunDefEnemy(Pawn).PlayAttackAnimation() > 0)
  {
   // sleep and hold position until we're finished playing the attack animation
  // -- anim notifies will presumably take care of actually triggering the firing the projectile while we're waiting
   while(DunDefEnemy(Pawn).IsCurrentlyPlayingAttackAnimation())
   {
   Pawn.Acceleration.X = 0;
   Pawn.Acceleration.Y = 0;
   Pawn.Acceleration.Z = 0;

  Focus=none;
  Sleep(0);
   }
  }
   else //in case we have no animation, just wait a small time and then fire
   {
   Pawn.Acceleration.X = 0;
   Pawn.Acceleration.Y = 0;
   Pawn.Acceleration.Z = 0;
   Focus=none;
  Sleep(1.5);
   FireProjectile();
   }

   PopState();

      
  }

这样所有的pawn和controller相关的内容结束,下来我将进入武器和射弹类的研究。
   

原文地址:https://www.cnblogs.com/NEOCSL/p/2370086.html