2:《地牢守卫者》代码分析:Pawn

Posted on 2012-02-23 22:41  neocsl  阅读(568)  评论(0编辑  收藏  举报

  分析了PlayerController自然而然就得研究Pawn了,第一步研究的pawn是基础pawn,通过该pawn要继承以后的PlayerPawn和EnemyPawn。在研究该pawn的过程中应该学会动画树的混合AnimTree Blend甚至于节点的重新书写。地牢守卫者的作者重写了一个DunDefAnimNodeScaleRateBySpeed节点。我并不操心他写的内容,我也暂时不用重写自己的动画节点。

  做一个动画树实例:

var array<name> CustomAnimNames;
var AnimNodePlayCustomAnim CustomAnimNode;


simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
{
CustomAnimNode=AnimNodePlayCustomAnim(SkelComp.FindAnimNode('NodeName'));
}


simulated event Destroyed()
{
super.Desroyed();
CustomAnimNode=none;
}

event Tick(float DeltaTime)
{
super.Tick(DeltaTime);
if(CustomAnimNode!=none&&!CustomAnimNode.bIsPlayingCustomAnim)
{
CustomAnimNode.PlayCustomAnim(CustomAnimNames[Rand(CustomAnimNames.length)],1.f,1.f,false,true);
}

}

这里生成了一个动画树节点,AnimNodePlayCustomAnim,然后初始化,并且在最后关闭的时候将其销毁。使用时让其调用动画并使用动画播放函数PlayCustomAnim即可非常方便。以下是动画书混合示例:

从以上示例看来,共有三个重要因素1.AnimNodePlayCustomAnim这是节点,2.FindAnimNode('nodename');中nodename就是前面节点的名字。3.就是customAnimNames,这些其实是动画树中的AnimTree.

因此pawn中大概以上述三类划分了动画树相关变量

var array<name> CustomAnimNodeNames;    //编辑器
var array<AnimNodePlayCustomAnim>CustomAnimNodes; //node

var name CustomAnimBlenderName; //编辑器
var AnimNodeBlend CustomAnimBlender; //node

var int LastCustomAnimNodePlayIndex; //上次的动画序列

////////////////////////
//
一下将会是动画播放序列

var name AnimJump;
var array<name>HurtAnimations;
var name DeathAnimation;

 

 

 pawn中非常重要的功能便是执行角色动画了,角色受到伤害并且产生受伤动画和声音

var array<SoundCue> HurtSounds;

var array<name> HurtAnims;

var name LastHurtAnim;

//产生伤害

event TakeDamage(int DamageAmount, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{

super.TakeDamage(DamageAmount,EventInstigator,HitLocation,Momentum,DamageType,HitInfo,DamageCauser);

  NotifyTakeHit();
}

//提示受到伤害

function NotifyTakeHit(Controller InstigatedBy, vector HitLocation, int Damage, class<DamageType> DamageType, vector Momentum)
{

super.NotifyTakeHit(InstigatedBy,HitLocation,Damage,DamageType,Momentum);
  PlayHurtAnimation();
}



function PlayHurtAnimation()

{

  if(HurtSounds.length!=none)

  PlaySound(HurtSounds[Rand(HurtSounds.lengtg)]);

  LastHurtAnim=HurtAnims[Rand(HurtAnims.length)];

  PlayCustomAnim(LastHurtAnim);
}

 既然提到动画就有几个重要的属性需要牢记

1.前面的bIsPlayingCustomAnim是bool型,判定当前是否在播放动画。

2.Mesh.bPauseAnim=true; 也是一个bool型,他可以让动画不再播放。如玩家死亡后,否则就会看到恐怖的诈尸;p效果.

 

simulated function PlayDying()
{
if(DeathSouds.length>0)
PlaySound(DeathSounds[Rand(DeathSounds.length)]); //播放了死亡声音
SetTimer(PlayCutomAnim(DeathAnimation,0.2,false,1,0),false,'PauseAnimationAfterDeath');
Gotostate('Dying');
bReplicateMovement = false;
bTearOff = true;
Velocity += TearOffMomentum;
SetPhysics(PHYS_Falling);
bPlayedDeath = true;
}

function PauseAnimationAfterDeath()
{
Mesh.bPauseAnim=true;
}

最开始的时候InitPostAnim中初始化了动画节点,在PostBeginPlay也可以初始化。

 

记着在PlayerController的Possess中CreateInventoryFromTemplate为玩家创建了符合等级的武器。这里将会重载他,原始的在AntInventoryManager中

官方有个函数叫CreateInventory现在只是改了一下名字,参数并未有任何变化

event final CreateInventoryFromTemplate(class<Inventory> NewInventoryItemClass, optional bool bDoNotActivate)
{
if(InvManager!=none) //每个pawn中都有一个InvManager参数
AntInventory(InvManager)=CreateInventoryFromTemplate(NewInventoryItemClass,bDoNotActive);

return none;
}

 

 InvManager就像Controller中定义的myHUD一样。

 function TakeFallingDamge()是官方提供的解决玩家掉落伤害的函数,预留下来将不会产生任何摔伤。

 

pawn的defaultproperties中留下这么几个组件

InventoryManagerClass=class'antInventoryManger'