bada 2D游戏编程之八――逐帧动画

 

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

 

你可能感兴趣的:(ios,android,game,phone,Bada,2d,SMART)