我们要做的2D和3D游戏离不开动画,那么在XNA中如何实现动画了?
首先,我们来看最简单的动画 —— 移动。
要移动一个Sprite非常简单,我们只需要在Game1.Update()方法中改变Sprite的位置坐标,在下次 Game1.Draw()方法被调用时,屏幕上显示的Sprite就被移动了。
接下来,我们看复杂一点的动画,比如炸弹的爆炸效果,我们可以这样来实现,制作一系列的图片, 每张图片都是爆炸过程中某一状态的表现,如下所示:
上面的20个小图片表现了一个爆炸从初始到结束的所有状态,在实际制作时,我们通常将这些图片按 顺序制作在一张大图中,并且保证大图中每个小图的尺寸是完全一样的。我们称这样的大图为精灵帧序列 图Sprite Sheets。
有了爆炸的Sprite Sheets,我们可以通过在Game1.Update()方法中改变下一个要显示的小图片的索 引(比如[2,3]),再根据索引以及小图片的尺寸计算出该将要显示的小图片在Sprite Sheets中的相对位 置,这样我们就可以在Game1.Draw()方法中将Sprite Sheets中的目标小图片的那块区域绘制出来。你 应该还记得上一篇文章中讲到的Game1.Draw()方法的第三个参数sourceRectangle,用它可以指定我们 要绘制Sprite Sheets的目标区域。
看来,实现一个动画并非难事,真正困难的地方在于如何控制每个动画可以有自己不同的刷新速度, 如何使同一个动画在不同配置的机器上表现相同。这就涉及到帧率问题。
所谓帧率Frame Rate,指的是一秒钟内重新绘制屏幕的次数。XNA框架为我们设置的默认帧率是60fps 。为什么选择60了?因为这是在人的眼睛感觉不到闪烁的情况下显示器最低的刷新频率。我们可以通过基 类Microsoft.Xna.Framework.Game的属性TargetElapsedTime来重新设置它。比如:
base.TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 10);
这表示每隔10ms就重绘一次,即帧率为100fps。
设置帧率为100fps,并不表示就真的会达到100fps的速度,这要看机器的配置如何。当机器的配置不 够时,XNA会自动跳过某些次绘制——即不调用Game1.Draw()方法。我们可以通过GameTime(你还记得 Update和Draw方法都有一个该类型的参数)的IsRunningSlowly属性来检测实际的帧率是否比我们设定的 要小。