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相关的内容结束,下来我将进入武器和射弹类的研究。