XNA入门教程----(三) 简单的动画 XNA入门教程----(一) XNA入门教程----(二) 移动控制XNA入门教程----(三) 简单的动画
继续我们的XNA之旅…
上周,我们简单的介绍了XNA的相关控制器,并且实现了鼠标和键盘对屏幕内的某个Sprite(精灵)进行简单的位置控制.
但是,美中不足的,我们并没有实现Sprite人物的移动动作,即Animation.
现在,我们继续上周所讲的, 实现简单的动画.
继续我们的XNA之旅…
上周,我们简单的介绍了XNA的相关控制器,并且实现了鼠标和键盘对屏幕内的某个Sprite(精灵)进行简单的位置控制.
但是,美中不足的,我们并没有实现Sprite人物的移动动作,即Animation.
现在,我们继续上周所讲的, 实现简单的动画.
关于Animation
对动画有所了解的朋友对于逐帧动画一定不会陌生.其以最简单的形式,将各动画元件相邻单位时间的动作位置记录在每个帧里.这样,当我们
一帧帧播放时,由于视觉暂留现象,我们便能看到相对”运动”的动画了.我们通常看到的GIF动画,就是基于这个原理的.
回来说们的游戏,由于在一般游戏内Sprite的”动作”都是有限可枚举得,我们便同样可以用类似的方案来记录Sprite的所有动作.
我们现在尝试用上面的GIF来实现我们的移动动画.
由于原生的XNA不支持直接从GIF动画中读取各帧图象,即不能直接从Content中Load到GIf动画或其相关帧图像
虽然从技术上而言,由于有很多开源项目支持如何读取或生成GIF(有兴趣的朋友可以看看这里),我们完全可以通过之自己加载Gif动画的某帧来实现游戏动画。
但这里,我们老老实实的将各帧拆开,得到以下的图像。
这样,我们只要通过加载不同的同一图像的不同位置,便可实现人物的”运动“了 。
加载动画
我们回到这个系列的第一篇
在sprite的Draw时候,我们提供以下重载参数
其中我们就可以通过设置sourceRectangle的值来显示texture2D的一部分了。
经过计算,我们得知每个单独人物的尺寸为60X110
这样,我们便用以下方法来动态显示不同“帧”的人物动画了
{
KeyboardState state = Keyboard.GetState();
if (state.IsKeyDown(Keys.Up))
{
this.Position.Y -= 10;
}
if (state.IsKeyDown(Keys.Down))
{
this.Position.Y +=10;
}
if (state.IsKeyDown(Keys.Left))
{
this.Position.X -= 10;
}
if (state.IsKeyDown(Keys.Right))
{
this.Position.X += 10;
}
MouseState state1 = Mouse.GetState();
if (state1.LeftButton == ButtonState.Pressed)
{
IPathFinder pathFinder = new PathFinderFast(m_matrix);
pathFinder.Formula = HeuristicFormula.Manhattan;
pathFinder.SearchLimit = 2000;
m_path = pathFinder.FindPath(new Vector2((int)this.Position.X, (int)this.Position.Y), new Vector2(state1.X , state1.Y ));
}
if (this.m_path != null && this.m_path.Count() != 0)
{
int index = this.m_path.Count() – 1;
this.Position = new Vector2(this.m_path[index].X, this.m_path[index].Y);
this.m_path.RemoveAt(index);
return;
}
m_frameIndex = m_frameIndex + 1 > 5 ? 0 : m_frameIndex + 1;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
this.spriteBatch.Draw(this.img, new Vector2(this.Position.X, this.Position.Y), new Rectangle(m_frameIndex * m_frameSize.X, 0, m_frameSize.X, m_frameSize.Y), Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);
spriteBatch.End();
base.Draw(gameTime);
}
其中,m_frameSize 便是我们每个单独动作的尺寸 Point m_frameSize = new Point(60, 110);
编译后,我们 便能看到“动”的人物了。
调节动画的“速度”
我们很快发现,用这个方法显示的逐帧动画很暴走。即动画帧变化速度太快了。
这其实是由于我们的动画变帧逻辑在Update方法中,而通常,update的调用是基于游戏内置循环的,即根据XNA的默认刷新率—60fps(Frame/Second)。
如果直接用默认速度的帧循环速度,一则CPU使用率太高,二则也没有这个必要。这里,我们决心“降低”帧数。
我们知道,在XNA中,我们可以通过gameTime.ElapsedGameTime得到自从上次循环结束后到现在的时间。
因此,我们可以将我们的Update方法改成如下结构
{
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
if (timeSinceLastFrame > millisecondsPerFrame)
{
timeSinceLastFrame -= millisecondsPerFrame;
//TODO
}
}
其中,int millisecondsPerFrame = 50;就是我们设定的阀值。
经过以上修改,我们就会发现帧速明显下降,当然,CPU使用率也下去了。
一些细节
或许大家发现,人物不动时还在原地跑步,只需我们加上类似下文逻辑即可。
{
m_frameIndex = m_frameIndex + 1 > 5 ? 0 : m_frameIndex + 1;
}
else
{
m_frameIndex = 0;
}
总结
本文主要简单介绍了逐帧动画及其在XNA中的实现。并且引入了帧速的控制。相信各位看完本文,便会对XNA的简单2D动画有了一个全面的了解。
To Be Continue….
本系列列表