分析了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'