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个帧间隔的问题。因此最好的解决办法就是本身实现一个动画类,但这个动画类不须要自带定时器来进行时间设定,它直接利用游戏中的帧间隔,让动画的播放频率和游戏的刷新频率保持一致或者成相应的倍数关系,这样就能够彻底避免前面出现的问题了。