bada 2D
遊戲編程之八——逐幀動畫
遊戲就是由一個個動畫片斷鏈接而成的,常見的有進入遊戲時的加載動畫、遊戲過程當中精靈動畫、特效動畫和遊戲的各界面之間切換時的過渡動畫等。能夠說動畫在遊戲中是無處不在,這樣在遊戲開發中就不得不去實現各類動畫,可是隻要了解了動畫的基本原理,實現起動畫來就很是方便了。其實動畫就是經過以一種連續貼圖的方式快速播放來實現的,同時根據貼圖的圖片產生的方式不一樣,又能夠將動畫分爲逐幀動畫和關鍵幀動畫。這篇文章主要對bada平臺上提供的逐幀動畫功能進行講解。
1,
什麼是逐幀動畫
逐幀動畫也稱爲幀動畫,這是一種常見的動畫形式,它的主要特色是每一幀都須要提供一張圖片,並將組成動畫所需的一系列圖片分別放在不一樣的幀當中。當播放動畫時,是一幀一幀順序播放的,這樣經過一幀一幀顯示動畫的圖像序列來實現動畫效果。因爲全部的圖片都是人工提供的,因此逐幀動畫具備很是大的靈活性,幾乎能夠表現任何想表現的內容。但同時因爲每一幀圖片都須要咱們動手操做產生,因此製做起來比較麻煩。
拿一個描述一株向日葵從苗芽狀態成長到綻開花朵的過程動畫來講,該向日葵由小變大,所以構成該動畫的每一張圖片都是不同的,以下圖:
這樣順序播放這組圖片就是實現所須要的動畫了。
2,
相關類和接口
bada平臺對實現逐幀動畫功能提供了很好的支持,主要由Osp::Ui::Controls::Animation,Osp::Ui::Controls::AnimationFrame和Osp::Ui::IAnimationEventListener來完成。
2.1,Osp::Ui::Controls:: AnimationFrame類
AnimationFrame表示動畫中的幀,因爲逐幀動畫中每一幀都須要提供一張圖片,因此能夠爲每一幀添加圖片,並設定幀在屏幕上顯示的時長。下面是它的主要函數:
函數
|
功能描述
|
AnimationFrame (void)
|
默認構造函數
|
AnimationFrame (const
Osp::Graphics::Bitmap &frame, long duration)
|
傳入位圖和持續時間值進行構造
|
SetFrame (const
Osp::Graphics::Bitmap &frame)
|
爲幀添加位圖
|
SetDuration (long duration)
|
爲幀設置顯示時長
|
2.2,Osp::Ui::Controls::Animation類
Animation類用於顯示和控制動畫播放,它將幀序列中的圖片一張一張的顯示出來造成動畫,這個幀序列是由加入了多個AnimationFrame的列表類來表示的。能夠將Animation理解爲動畫播放器,播放的內容爲一張張的圖片,並能夠控制播放過程。下面是它的主要函數:
函數
|
功能描述
|
Animation (void)
|
默認構造函數
|
Construct (const
Osp::Graphics::Rectangle &rect, const
Osp::Base::Collection::IList &aniFrames)
|
經過矩形區域和幀序列進行初始化
|
AddAnimationEventListener (const
Osp::Ui::IAnimationEventListener &listener)
|
加入事件監聽器
|
Play (void)
|
開始播放
|
Pause (void)
|
暫停播放
|
Stop (void)
|
中止播放
|
SetRepeatCount (int count)
|
設置重複播放次數
|
2.3,Osp::Ui::IAnimationEventListener
IAnimationEventListener用於對Animation的播放過程進行監聽,當Animation播放結束時,經過IAnimationEventListener將結束事件通知出去,這樣註冊了的監聽器就可以接到事件通知了。尤爲是用於當須要在動畫播放結束時進行相應的事件處理的狀況下會用到,例如開發者但願在動畫A播放結束或緊接着播放動畫B,就能夠經過實行IAnimationEventListener的接口來作到。下面是它的主要函數:
函數
|
功能描述
|
OnAnimationStopped (const
Osp::Ui::Control &source)
|
事件監聽函數,用於接收動畫結束事件通知
|
3,
動畫實現
接下來咱們用上面提到的類來實現一我的物動畫,這個動畫表現的是人物角色在屏幕上走動的效果。
Step 1,準備動畫圖片
準備好須要添加到動畫幀中的圖片,每一幀對應一張圖片。
Step 2,解析圖片
將圖片解析成系統支持的位圖。
Bitmap* pBitmap1 = pAppRes->
GetBitmapN("grossini_1.
png");
Bitmap* pBitmap2 = pAppRes->
GetBitmapN("grossini_2.
png");
Bitmap* pBitmap3 = pAppRes->
GetBitmapN("grossini_3.
png");
Bitmap* pBitmap4 = pAppRes->
GetBitmapN("grossini_4.
png");
Bitmap* pBitmap5 = pAppRes->
GetBitmapN("grossini_5.
png");
Bitmap* pBitmap6 = pAppRes->
GetBitmapN("grossini_6.
png");
Step 3,建立動畫幀
經過AnimationFrame來建立動畫幀,在其中傳入位圖並設置持續時長。
AnimationFrame* pAniFrame1 =
new
AnimationFrame(*pBitmap1, 100) ;
AnimationFrame* pAniFrame2 =
new
AnimationFrame(*pBitmap2, 100) ;
AnimationFrame* pAniFrame3 =
new
AnimationFrame(*pBitmap3, 100) ;
AnimationFrame* pAniFrame4 =
new
AnimationFrame(*pBitmap4, 100) ;
AnimationFrame* pAniFrame5 =
new
AnimationFrame(*pBitmap5, 100) ;
AnimationFrame* pAniFrame6 =
new
AnimationFrame(*pBitmap6, 100) ;
Step 4,建立幀序列
經過將表示動畫幀的AnimationFrame對象添加到列表中來實現幀序列。
__pFrameArray =
new
ArrayList();
__pFrameArray->
Construct();
__pFrameArray->
Add(*pAniFrame1);
__pFrameArray->
Add(*pAniFrame2);
__pFrameArray->
Add(*pAniFrame3);
__pFrameArray->
Add(*pAniFrame4);
__pFrameArray->
Add(*pAniFrame5);
__pFrameArray->
Add(*pAniFrame6);
Step 5,建立動畫對象
因爲Animation是一個控件類,因此須要爲它設置顯示的座標和區域,同時將幀序列傳進去,經過它來控制幀序列的顯示。
__pAnimation =
new
Animation();
__pAnimation->
Construct(
Rectangle(0, 50, 128, 128), *__pFrameArray);
__pAnimation->
SetRepeatCount(100);
__pAnimation->
AddAnimationEventListener(*
this);
AddControl(*__pAnimation);
Step 6,控制動畫播放
最後就能夠經過Animation提供的Play(),Pause(),Stop()等函數來控制動畫的播放了。
__pAnimation->
Play();
Step 7,實現走動效果
實現完前面的基本,基本的動畫功能就已經實現了。可是此時的人物是原地踏步的,沒有進行移動,那麼如何實現移動的效果呢?很簡單,由於Animation是一個控件類,因此能夠經過改變它的X軸和Y軸的座標來實現移動的效果,別忘了刷新屏幕。
結合咱們前面的文章用到的模塊代碼,只須要在
UpdateLogic(
int frameInterval) 函數中更新Animation的X軸和Y軸座標就能夠了。
下面的代碼是實現人物按照每一個遊戲幀間隔時間沿着X軸的正方向移動2個像素。
int xPos,yPos;
__pAnimation->
GetPosition(xPos,yPos);
__pAnimation->
SetPosition(xPos+2,yPos);
4,
不足之處
這樣就實現了一我的物移動的動畫。但在這裏你們可能會發現一個問題,在這裏出現了2個幀間隔。一個是給Animation中的幀設置的間隔,能夠稱爲「動畫幀間隔」,還有一個是遊戲的幀間隔時間,能夠稱爲「遊戲幀間隔」。這兩個幀間隔會引入畫面不一樣步的問題。
(1)動畫幀間隔 > 遊戲幀間隔
假定動畫幀間隔爲100毫秒,遊戲幀間隔爲20毫秒。這樣一秒鐘中小人能夠移動50次,而動畫中的圖片一秒鐘只會播放10張圖片,這樣遊戲中就會出現動畫中的某一張圖片在移動而沒有伴隨的動做的狀況,人物的移動沒有和人物的動做保持一致。
(2)動畫幀間隔 < 遊戲幀間隔
假定動畫幀間隔爲20毫秒,遊戲幀間隔爲100毫秒。這樣一秒鐘中小人能夠移動10次,而動畫中的圖片一秒鐘只會播放50張圖片,這種狀況下就會出現動畫中動做不連貫的狀況發生,好比第一次移動時人物動做是1,而進行第二次移動時,此時的動做已經到第5個了。這樣中間的動做就跳過了。
那麼若是這兩個幀間隔相等呢?前面的
《bada 2D遊戲編程之四——設計遊戲循環》中也提到過,幀間隔時間有時可能會大於設定的值,因此這個也無法保證。可是還好通常的遊戲不會要求這麼嚴格,上面提到的問題在大都是能夠接受的,這樣經過採用Animation進行動畫開發也是個很是不錯的選擇,這樣能夠節省不少工做量。
5,
最佳方案
雖然如今咱們無法看到bada的源代碼,可是能夠猜到Animation類裏面應該是有一個定時器的,這個定時器會根據AnimationFrame中設定的時長來進行延時,從而實現等待多長時間後播放下一張圖片,經過這樣定時更換幀序列中的圖片就造成了動畫。但正是因爲Animation類也有本身的定時器纔會和遊戲中的定時器相沖突,產生出2個幀間隔的問題。因此最好的解決辦法就是本身實現一個動畫類,但這個動畫類不須要自帶定時器來進行時間設定,它直接利用遊戲中的幀間隔,讓動畫的播放頻率和遊戲的刷新頻率保持一致或者成相應的倍數關係,這樣就能夠徹底避免前面出現的問題了。