XNA动画的实现2——动画片段类的实现
在上一篇文章XNA动画的实现1——基本原理中已经实现的动画的代码,这篇文章将要将这些代码封装成一个类,有了前一篇文章的基础,这个类实现起来是非常容易的。这个思路主要参考了《3D Graphics with XNA Game Studio 4.0》(本网站有电子书下载)的9.1 ObjectAnimation一节。
首先新建一个XNA Game项目,然后在项目中添加一个新的类,我命名为SimpleAnimationClip,代码如下:
/// <summary>
/// 动画片段类,这个类根据输入的开始时刻和结束时刻的位置、旋转、缩放和动画持续时间,自动计算此动画片段时间内各时刻的转换矩阵。
/// </summary>
public class SimpleAnimationClip
{
// 开始时刻和结束时刻的位置、旋转、缩放
Vector3 startPosition, endPosition, startRotation, endRotation,startScale, endScale;
Vector3 position,rotation,scale; // 当前时刻的位置、旋转和缩放
TimeSpan duration; // 动画持续时间
TimeSpan elapsedTime = TimeSpan.FromSeconds(0); // 动画播放已流逝的时间
/// <summary>
/// 是否循环播放动画
/// </summary>
public bool Loop{ get;set;}
/// <summary>
/// 变换矩阵
/// </summary>
public Matrix Transform{ get;set;}
/// <summary>
/// 创建一个动画片段,默认不循环播放
/// </summary>
public SimpleAnimationClip(Vector3 StartPosition, Vector3 EndPosition, Vector3 StartRotation, Vector3 EndRotation, Vector3 StartScale,Vector3 EndScale,TimeSpan Duration)
{
startPosition = StartPosition;
endPosition = EndPosition;
startRotation = StartRotation;
endRotation = EndRotation;
startScale = StartScale;
endScale = EndScale;
position = startPosition;
rotation = startRotation;
scale = startScale;
duration = Duration;
Loop = false;
}
public void Update(TimeSpan Elapsed)
{
// 更新动画播放的时间
this.elapsedTime += Elapsed;
// 计算动画流逝的进度,这个值在0和1之间,0表示动画开始时刻,1表示动画结束时刻
float amt = (float)elapsedTime.TotalSeconds / (float)duration.TotalSeconds;
if (Loop)
while (amt > 1)
// 如果循环播放动画则重置amp的值
amt -= 1;
else
// 如果不循环播放动画则将amt的值截取为最后时刻的值
amt = MathHelper.Clamp(amt, 0, 1);
// 通过插值运算更新当前的位置、旋转和缩放
position = Vector3.Lerp(startPosition, endPosition, amt);
rotation = Vector3.Lerp(startRotation, endRotation, amt);
scale =Vector3 .Lerp (startScale, endScale, amt);
Transform = Matrix.CreateScale(scale) * Matrix.CreateFromYawPitchRoll(rotation.Y, rotation.X, tation.Z) * Matrix.CreateTranslation(position);
}
}
原理在上一篇文章已经介绍过了,新的东西只有使用了Lerp方法进行了线性插值运算。
有了这个动画片段类,我们只需在游戏主类中添加这个对象:
SimpleAnimationClip animation;
然后在Initialize方法中初始化这个类即可。要初始化这个类,你需要指定开始和结束时刻的位置、旋转和缩放以及播放时间。
protected override void Initialize()
{
[…]
// 初始化动画类
animation = new SimpleAnimationClip(Vector3.Zero, new Vector3(16, 0, 16), Vector3.Zero, new Vector3(0, MathHelper.ToRadians(180), 0), Vector3.One, new Vector3(3.0f, 3.0f, 3.0f), TimeSpan.FromSeconds(4));
base.Initialize();
}
然后在Update方法中调用动画片段类的Update方法计算变换矩阵,然后将这个矩阵赋予你想施加动画的Bone.Transform。
protected override void Update(GameTime gameTime)
{
[…]
// 更新动画类
animation.Update(gameTime.ElapsedGameTime );
model.Bones["Body"].Transform = animation.Transform * originalBodyTransform;
//model.Bones["Head"].Transform = animation.Transform * originalHeadTransform;
// 下面这行注释的代码效果与上一行代码相同,
// 通过索引访问会比通过Bone名称访问稍微快一些
//model.Bones[2].Transform = animation.Transform * originalHeadTransform;
base.Update(gameTime);
}
这个代码实现的效果与上一篇文章是完全相同的,只不过使用起来更加方便。 如果你使用过Flash,你会发现这其实就是补间动画。如下图所示,我们可以看出,在Flash中我们只需在时间轴上创建两个关键帧,就可以实现这两个位置之间的直线运动。更强大的地方在于Flash还有一个动画编辑器,通过它你可以实现变速运动,曲线运动。

如上图所示,如果要在Flash中让红色小球在时间中点改变运动方向,该怎么办?非常简单,在第15帧再设置一个关键帧即可,如下图所示:

而目前我们的SimpleAnimationClip类只能实现匀速直线运动,因为本质上这个类相当于只能使用初末两个时刻的关键帧,要能中途转弯,必须要加以改进,方法和Flash中是一样的,即添加关键帧类,我们将在下一篇文章中加以讨论。
文件下载(已下载 1171 次)发布时间:2011/8/30 下午2:11:57 阅读次数:6711
