动画操作
在class Dynamic创建函数OnPostCreate()中初始化:
protected override void OnPostCreate( bool loaded )
{
...
CreateAnimationController();
...
}
其中class MeshObjectAnimationController和class AnimationItem都不是引擎部分的,都是游戏部分的。
在class Dynamic的刷新函数中更新动画:
void OnRenderFrame()
{
...
animationController.DoRenderFrame(); // 更新动画帧
...
if( forceAnimationRemainingTime == 0 ) // 设置默认动画
OnUpdateBaseAnimation();
}
当forceAnimationRemainingTime为0时,就为物体设置默认动画,这个函数在class Dynamic中没有实现,放到了具体的子类中实现,比如class GameCharacter中:
protected override void OnUpdateBaseAnimation()
{
base.OnUpdateBaseAnimation();
//walk animation
if( IsOnGround() && GroundRelativeVelocity.ToVec2().LengthSqr() > .3f )
{
float velocity = ( Rotation.GetInverse() * GroundRelativeVelocity ).X *
Type.WalkAnimationVelocityMultiplier;
UpdateBaseAnimation( Type.WalkAnimationName, true, true, velocity );
return;
}
//idle animation
{
UpdateBaseAnimation( Type.IdleAnimationName, true, true, 1 );
return;
}
}
根据速度,设置默认动画是idle或者walk。
当角色做了一个动作,比如跳时,需要设置一个临时的跳的动画来代替默认动画,
在class Dynamic function SetForceAnimation中:
public void SetForceAnimation( string animationBaseName, bool allowRandomAnimationNumber )
{
...
//activate new animation
currentAnimationItem = animationController.Add( animationBaseName,
allowRandomAnimationNumber, false );
if( currentAnimationItem != null )
forceAnimationRemainingTime = currentAnimationItem.Length;
}
forceAnimationRemainingTime 作为临时动画的时间长度,在上面的function OnRenderFrame中,如果forceAnimationRemainingTime 为0,表示临时动画结束,就需要还原成默认动画了。
在function OnTick()中来更新临时动画的时间:
protected override void OnTick()
{
...
if( animationController != null )
TickForceAnimationRemainingTime();
}
void TickForceAnimationRemainingTime()
{
if( forceAnimationRemainingTime != 0 )
{
forceAnimationRemainingTime -= TickDelta;
if( forceAnimationRemainingTime < 0 )
forceAnimationRemainingTime = 0;
}
}
由于自己开发的需要,添加一个功能:添加多个动画,组成一个动画串,单个动画之间可以设置延时。
在class Dynamic里面添加一个结构定义和一个列表:
// for delay animation
struct DelayAnimationItem
{
public float delayTime;
public string animationName;
}
List<DelayAnimationItem> delayAnimationList = new List<DelayAnimationItem>();
增加一个添加动画函数:
public void AppendForceAnimation(string animationBaseName, float delayTime)
{
//!!!!!should to disable animation for disabled renderer
if (animationController == null)
return;
if (delayTime <= 0.0f)
{
return;
}
DelayAnimationItem item = new DelayAnimationItem();
item.delayTime = delayTime;
item.animationName = animationBaseName;
delayAnimationList.Add(item);
}
暂时将动画保存到列表中,不支持从多个动画中随机选择,不支持循环播放的动画。
然后在function OnTick()函数中判断是否有等待播放的动画:
OnTick() --> TickForceAnimationRemainingTime()
修改TickForceAnimationRemainingTime()为如下:
void TickForceAnimationRemainingTime()
{
if (delayAnimationList.Count > 0)
{
DelayAnimationItem item = delayAnimationList[0];
item.delayTime -= TickDelta;
if (item.delayTime <= 0.0f)
{
SetForceAnimation(item.animationName, false);
delayAnimationList.RemoveAt(0);
}
else
{
delayAnimationList[0] = item;
}
}
else if( forceAnimationRemainingTime != 0 )
{
forceAnimationRemainingTime -= TickDelta;
if( forceAnimationRemainingTime < 0 )
forceAnimationRemainingTime = 0;
}
}
因为对延时精度要求不高,所以在OnTick中调用。
在一个动画播放完毕之后,需要判断是否有其他动画等待播放,如果有,则减小延时,播放动画,如果没有,则回到默认动画。
修改function OnRenderFrame()为如下:
protected override void OnRenderFrame()
{
...
//animation management
if( animationController != null )
{
if( EntitySystemWorld.Instance.Simulation &&
!EntitySystemWorld.Instance.SystemPauseOfSimulation )
{
if (0 == delayAnimationList.Count || 0 < forceAnimationRemainingTime)
animationController.DoRenderFrame();
if( currentAnimationItem != null && currentAnimationItem.Removed )
currentAnimationItem = null;
if( forceAnimationRemainingTime != 0 && currentAnimationItem == null )
forceAnimationRemainingTime = 0;
if (forceAnimationRemainingTime == 0 && 0 == delayAnimationList.Count)
OnUpdateBaseAnimation();
}
}
}
当临时动画播放完,并且有下一个临时动画等待播放时,不更新动画;当临时动画播放完,并且没有其他临时动画等待执行时,才返回到默认动画。