繼續我們的XNA之旅...
上周,我們簡單的介紹了XNA的相關控制器,並且實現了鼠標和鍵盤對屏幕內的 某個Sprite(精靈)進行簡單的位置控制.
但是,美中不足的,我們並沒有實現Sprite人物的移動動作,即Animation.
現在,我們繼續上周所講的, 實現簡單的動畫.
關於Animation
對動畫有所了解的朋友對於逐幀動畫一定不會陌生.其以最簡單的形式,將各 動畫元件相鄰單位時間的動作位置記錄在每個幀裡.這樣,當我們
一幀幀播放時,由於視覺暫留現象,我們便能看到相對"運動"的動畫了.我們通 常看到的GIF動畫,就是基於這個原理的.
回來說們的游戲,由於在一般游戲內Sprite的"動作"都是有限可枚舉得,我們 便同樣可以用類似的方案來記錄Sprite的所有動作.
我們現在嘗試用上面的GIF來實現我們的移動動畫.
由於原生的XNA不支持直接從GIF動畫中讀取各幀圖象,即不能直接從Content 中Load到GIf動畫或其相關幀圖像
雖然從技術上而言,由於有很多開源項目支持如何讀取或生成GIF(有興趣的 朋友可以看看這裡),我們完全可以通過之自己加載Gif動畫的某幀來實現游戲 動畫。
但這裡,我們老老實實的將各幀拆開,得到以下的圖像。
這樣,我們只要通過加載不同的同一圖像的不同位置,便可實現人物的”運 動“了 。
加載動畫
我們回到這個系列的第一篇
在sprite的Draw時候,我們提供以下重載參數
其中我們就可以通過設置sourceRectangle的值來顯示texture2D的一部分了 。
經過計算,我們得知每個單獨人物的尺寸為60X110
這樣,我們便用以下方法來動態顯示不同“幀”的人物動畫了
protected override void Update(GameTime gameTime)
{
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方法改成如下結構
protected override void Update(GameTime gameTime)
{
timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
if (timeSinceLastFrame > millisecondsPerFrame)
{
timeSinceLastFrame -= millisecondsPerFrame;
//TODO
}
}
其中,int millisecondsPerFrame = 50;就是我們設定的閥值。
經過以上修改,我們就會發現幀速明顯下降,當然,CPU使用率也下去了。
一些細節/P>
或許大家發現,人物不動時還在原地跑步,只需我們加上類似下文邏輯即可 。
if (isActive)
{
m_frameIndex = m_frameIndex + 1 > 5 ? 0 : m_frameIndex + 1;
}
else
{
m_frameIndex = 0;
}
總結
本文主要簡單介紹了逐幀動畫及其在XNA中的實現。並且引入了幀速的控制。 相信各位看完本文,便會對XNA的簡單2D動畫有了一個全面的了解。
本例源代碼:http://files.cnblogs.com/edwin1986/WindowsGame3.rar