生活随笔
收集整理的這篇文章主要介紹了
bada 2D游戏编程之八——逐帧动画
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
?
bada 2D游戲編程之八——逐幀動(dòng)畫(huà) 游戲就是由一個(gè)個(gè)動(dòng)畫(huà)片段連接而成的,常見(jiàn)的有進(jìn)入游戲時(shí)的加載動(dòng)畫(huà)、游戲過(guò)程中精靈動(dòng)畫(huà)、特效動(dòng)畫(huà)和游戲的各界面之間切換時(shí)的過(guò)渡動(dòng)畫(huà)等。可以說(shuō)動(dòng)畫(huà)在游戲中是無(wú)處不在,這樣在游戲開(kāi)發(fā)中就不得不去實(shí)現(xiàn)各種動(dòng)畫(huà),但是只要了解了動(dòng)畫(huà)的基本原理,實(shí)現(xiàn)起動(dòng)畫(huà)來(lái)就非常方便了。其實(shí)動(dòng)畫(huà)就是通過(guò)以一種連續(xù)貼圖的方式快速播放來(lái)實(shí)現(xiàn)的,同時(shí)根據(jù)貼圖的圖片產(chǎn)生的方式不同,又可以將動(dòng)畫(huà)分為逐幀動(dòng)畫(huà)和關(guān)鍵幀動(dòng)畫(huà)。這篇文章主要對(duì)bada平臺(tái)上提供的逐幀動(dòng)畫(huà)功能進(jìn)行講解。 1,什么是逐幀動(dòng)畫(huà) 逐幀動(dòng)畫(huà)也稱(chēng)為幀動(dòng)畫(huà),這是一種常見(jiàn)的動(dòng)畫(huà)形式,它的主要特點(diǎn)是每一幀都需要提供一張圖片,并將組成動(dòng)畫(huà)所需的一系列圖片分別放在不同的幀當(dāng)中。當(dāng)播放動(dòng)畫(huà)時(shí),是一幀一幀順序播放的,這樣通過(guò)一幀一幀顯示動(dòng)畫(huà)的圖像序列來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果。由于所有的圖片都是人工提供的,所以逐幀動(dòng)畫(huà)具有非常大的靈活性,幾乎可以表現(xiàn)任何想表現(xiàn)的內(nèi)容。但同時(shí)由于每一幀圖片都需要我們動(dòng)手操作產(chǎn)生,所以制作起來(lái)比較麻煩。 拿一個(gè)描述一株向日葵從苗芽狀態(tài)成長(zhǎng)到綻放花朵的過(guò)程動(dòng)畫(huà)來(lái)說(shuō),該向日葵由小變大,因此構(gòu)成該動(dòng)畫(huà)的每一張圖片都是不一樣的,如下圖:
這樣順序播放這組圖片就是實(shí)現(xiàn)所需要的動(dòng)畫(huà)了。 2,相關(guān)類(lèi)和接口 bada平臺(tái)對(duì)實(shí)現(xiàn)逐幀動(dòng)畫(huà)功能提供了很好的支持,主要由Osp::Ui::Controls::Animation,Osp::Ui::Controls::AnimationFrame和Osp::Ui::IAnimationEventListener來(lái)完成。 2.1,Osp::Ui::Controls:: AnimationFrame類(lèi) AnimationFrame表示動(dòng)畫(huà)中的幀,由于逐幀動(dòng)畫(huà)中每一幀都需要提供一張圖片,所以可以為每一幀添加圖片,并設(shè)定幀在屏幕上顯示的時(shí)長(zhǎng)。下面是它的主要函數(shù):
| 函數(shù) | 功能描述 |
| AnimationFrame (void) | 默認(rèn)構(gòu)造函數(shù) |
| AnimationFrame (const Osp::Graphics::Bitmap &frame, long duration) | 傳入位圖和持續(xù)時(shí)間值進(jìn)行構(gòu)造 |
| SetFrame (const Osp::Graphics::Bitmap &frame) | 為幀添加位圖 |
| SetDuration (long duration) | 為幀設(shè)置顯示時(shí)長(zhǎng) |
2.2,Osp::Ui::Controls::Animation類(lèi) Animation類(lèi)用于顯示和控制動(dòng)畫(huà)播放,它將幀序列中的圖片一張一張的顯示出來(lái)形成動(dòng)畫(huà),這個(gè)幀序列是由加入了多個(gè)AnimationFrame的列表類(lèi)來(lái)表示的。可以將Animation理解為動(dòng)畫(huà)播放器,播放的內(nèi)容為一張張的圖片,并可以控制播放過(guò)程。下面是它的主要函數(shù):
| 函數(shù) | 功能描述 |
| Animation (void) | 默認(rèn)構(gòu)造函數(shù) |
| Construct (const Osp::Graphics::Rectangle &rect, const Osp::Base::Collection::IList &aniFrames) | 通過(guò)矩形區(qū)域和幀序列進(jìn)行初始化 |
| AddAnimationEventListener (constOsp::Ui::IAnimationEventListener &listener) | 加入事件監(jiān)聽(tīng)器 |
| Play (void) | 開(kāi)始播放 |
| Pause (void) | 暫停播放 |
| Stop (void) | 停止播放 |
| SetRepeatCount (int count) | 設(shè)置重復(fù)播放次數(shù) |
2.3,Osp::Ui::IAnimationEventListener IAnimationEventListener用于對(duì)Animation的播放過(guò)程進(jìn)行監(jiān)聽(tīng),當(dāng)Animation播放結(jié)束時(shí),通過(guò)IAnimationEventListener將結(jié)束事件通知出去,這樣注冊(cè)了的監(jiān)聽(tīng)器就能夠接到事件通知了。尤其是用于當(dāng)需要在動(dòng)畫(huà)播放結(jié)束時(shí)進(jìn)行相應(yīng)的事件處理的情況下會(huì)用到,例如開(kāi)發(fā)者希望在動(dòng)畫(huà)A播放結(jié)束或緊接著播放動(dòng)畫(huà)B,就可以通過(guò)實(shí)行IAnimationEventListener的接口來(lái)做到。下面是它的主要函數(shù):
| 函數(shù) | 功能描述 |
| OnAnimationStopped (const Osp::Ui::Control &source) | 事件監(jiān)聽(tīng)函數(shù),用于接收動(dòng)畫(huà)結(jié)束事件通知 |
3,動(dòng)畫(huà)實(shí)現(xiàn) 接下來(lái)我們用上面提到的類(lèi)來(lái)實(shí)現(xiàn)一個(gè)人物動(dòng)畫(huà),這個(gè)動(dòng)畫(huà)表現(xiàn)的是人物角色在屏幕上走動(dòng)的效果。 Step 1,準(zhǔn)備動(dòng)畫(huà)圖片 準(zhǔn)備好需要添加到動(dòng)畫(huà)幀中的圖片,每一幀對(duì)應(yīng)一張圖片。
Step 2,解析圖片 將圖片解析成系統(tǒng)支持的位圖。 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,創(chuàng)建動(dòng)畫(huà)幀 通過(guò)AnimationFrame來(lái)創(chuàng)建動(dòng)畫(huà)幀,在其中傳入位圖并設(shè)置持續(xù)時(shí)長(zhǎng)。 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,創(chuàng)建幀序列 通過(guò)將表示動(dòng)畫(huà)幀的AnimationFrame對(duì)象添加到列表中來(lái)實(shí)現(xiàn)幀序列。 __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,創(chuàng)建動(dòng)畫(huà)對(duì)象 由于Animation是一個(gè)控件類(lèi),所以需要為它設(shè)置顯示的坐標(biāo)和區(qū)域,同時(shí)將幀序列傳進(jìn)去,通過(guò)它來(lái)控制幀序列的顯示。 __pAnimation = new Animation(); __pAnimation->Construct(Rectangle(0, 50, 128, 128), *__pFrameArray); __pAnimation->SetRepeatCount(100); __pAnimation->AddAnimationEventListener(*this); AddControl(*__pAnimation); Step 6,控制動(dòng)畫(huà)播放 最后就可以通過(guò)Animation提供的Play(),Pause(),Stop()等函數(shù)來(lái)控制動(dòng)畫(huà)的播放了。 __pAnimation->Play(); Step 7,實(shí)現(xiàn)走動(dòng)效果 實(shí)現(xiàn)完前面的基本,基本的動(dòng)畫(huà)功能就已經(jīng)實(shí)現(xiàn)了。但是此時(shí)的人物是原地踏步的,沒(méi)有進(jìn)行移動(dòng),那么如何實(shí)現(xiàn)移動(dòng)的效果呢?很簡(jiǎn)單,因?yàn)锳nimation是一個(gè)控件類(lèi),所以可以通過(guò)改變它的X軸和Y軸的坐標(biāo)來(lái)實(shí)現(xiàn)移動(dòng)的效果,別忘了刷新屏幕。 結(jié)合我們前面的文章用到的模塊代碼,只需要在UpdateLogic(int frameInterval) 函數(shù)中更新Animation的X軸和Y軸坐標(biāo)就可以了。 下面的代碼是實(shí)現(xiàn)人物按照每個(gè)游戲幀間隔時(shí)間沿著X軸的正方向移動(dòng)2個(gè)像素。 int xPos,yPos; __pAnimation->GetPosition(xPos,yPos); __pAnimation->SetPosition(xPos+2,yPos); 4,不足之處 這樣就實(shí)現(xiàn)了一個(gè)人物移動(dòng)的動(dòng)畫(huà)。但在這里大家可能會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,在這里出現(xiàn)了2個(gè)幀間隔。一個(gè)是給Animation中的幀設(shè)置的間隔,可以稱(chēng)為“動(dòng)畫(huà)幀間隔”,還有一個(gè)是游戲的幀間隔時(shí)間,可以稱(chēng)為“游戲幀間隔”。這兩個(gè)幀間隔會(huì)引入畫(huà)面不同步的問(wèn)題。 (1)動(dòng)畫(huà)幀間隔 > 游戲幀間隔 假定動(dòng)畫(huà)幀間隔為100毫秒,游戲幀間隔為20毫秒。這樣一秒鐘中小人可以移動(dòng)50次,而動(dòng)畫(huà)中的圖片一秒鐘只會(huì)播放10張圖片,這樣游戲中就會(huì)出現(xiàn)動(dòng)畫(huà)中的某一張圖片在移動(dòng)而沒(méi)有伴隨的動(dòng)作的情況,人物的移動(dòng)沒(méi)有和人物的動(dòng)作保持一致。 (2)動(dòng)畫(huà)幀間隔 < 游戲幀間隔 假定動(dòng)畫(huà)幀間隔為20毫秒,游戲幀間隔為100毫秒。這樣一秒鐘中小人可以移動(dòng)10次,而動(dòng)畫(huà)中的圖片一秒鐘只會(huì)播放50張圖片,這種情況下就會(huì)出現(xiàn)動(dòng)畫(huà)中動(dòng)作不連貫的情況發(fā)生,比如第一次移動(dòng)時(shí)人物動(dòng)作是1,而進(jìn)行第二次移動(dòng)時(shí),此時(shí)的動(dòng)作已經(jīng)到第5個(gè)了。這樣中間的動(dòng)作就跳過(guò)了。 那么如果這兩個(gè)幀間隔相等呢?前面的《bada 2D游戲編程之四——設(shè)計(jì)游戲循環(huán)》中也提到過(guò),幀間隔時(shí)間有時(shí)可能會(huì)大于設(shè)定的值,所以這個(gè)也沒(méi)法保證。但是還好一般的游戲不會(huì)要求這么嚴(yán)格,上面提到的問(wèn)題在大都是可以接受的,這樣通過(guò)采用Animation進(jìn)行動(dòng)畫(huà)開(kāi)發(fā)也是個(gè)非常不錯(cuò)的選擇,這樣可以節(jié)省很多工作量。 5,最佳方案 雖然現(xiàn)在我們沒(méi)法看到bada的源代碼,但是可以猜到Animation類(lèi)里面應(yīng)該是有一個(gè)定時(shí)器的,這個(gè)定時(shí)器會(huì)根據(jù)AnimationFrame中設(shè)定的時(shí)長(zhǎng)來(lái)進(jìn)行延時(shí),從而實(shí)現(xiàn)等待多長(zhǎng)時(shí)間后播放下一張圖片,通過(guò)這樣定時(shí)更換幀序列中的圖片就形成了動(dòng)畫(huà)。但正是由于Animation類(lèi)也有自己的定時(shí)器才會(huì)和游戲中的定時(shí)器相沖突,產(chǎn)生出2個(gè)幀間隔的問(wèn)題。所以最好的解決辦法就是自己實(shí)現(xiàn)一個(gè)動(dòng)畫(huà)類(lèi),但這個(gè)動(dòng)畫(huà)類(lèi)不需要自帶定時(shí)器來(lái)進(jìn)行時(shí)間設(shè)定,它直接利用游戲中的幀間隔,讓動(dòng)畫(huà)的播放頻率和游戲的刷新頻率保持一致或者成相應(yīng)的倍數(shù)關(guān)系,這樣就可以完全避免前面出現(xiàn)的問(wèn)題了。
?
轉(zhuǎn)載于:https://blog.51cto.com/badaeva/978564
總結(jié)
以上是生活随笔為你收集整理的bada 2D游戏编程之八——逐帧动画的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。