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 阅读次数:6168