在移动设备的Flash / AIR游戏上获得高FPS?

时间:2012-09-05 10:07:47

标签: flash mobile air game-development

我正在开发一款旨在作为“原生”应用和桌面网络浏览器部署在手机上的游戏。

自从在多个平台上工作以来,Flash及其嵌入式AIR似乎是一个非常好的解决方案。但是呃 - 哦。

目前仅使用4-keyframed影片剪辑(将它们添加到舞台,更新每个帧上的位置,最终删除它们)会使游戏在桌面屏幕上显示约30个时减慢,当显示时约20个我的Android(三星i9000 - 2.3.3)。我可能需要更多。

所以我尝试通过重绘我的位图区域,并将我的MovieClip转换为存储在我的Flash库中的bitmapDatas spritesheets来进行blittering。桌面上的结果很棒,动画完美,流畅,即使有数百个对象也是如此。但是移动设备上的结果非常糟糕,即使屏幕,CPU或GPU上只显示一个对象,FPS也会下降到15。

因为我的游戏在“旧”设备上工作显然会很好,如果我想达到接近或超过50的帧速率,那么目前使用Flash和AIR是一个坏主意吗?

使用闪存开发手机游戏时是否需要使用任何提示或不可或缺的做法?在这种情况下,我们必须避免任何常见的错误吗?

2 个答案:

答案 0 :(得分:1)

使用非常复杂的Flash矢量动画,您实际上可以在Adobe Air中获得30fps到50fps。

什么不该做:

  1. 不要使用预制的"缓存作为位图"任何动画的复选框。当应用于静态矢量图像时,这是一个很好的功能,因为它将其转换为静态位图。如果动画以除了在x或y轴上平移影片剪辑之外的任何方式进行动画处理,则动画实际上将是SLOWER,并且缓存为位图打开。

  2. 不要做blitting。 Blitting可以让游戏在Flash中快速发展,但在Adobe Air上它会使它们变慢。你想要的是放置在舞台上的位图对象,而不是在舞台上嵌入的bitmapData对象。

  3. 所以,你可以做的是抓取swf或Movieclip,并运行对象的每一帧并将每个帧转换为位图。然后,将每个位图保存到一个数组中。然后,要播放动画,请从数组中检索位图并将它们按顺序放在舞台上。在我的测试中,我能够以超过40fps的速度在Android平板电脑上运行全屏,24帧动画。

    代码示例如下。它将缓慢缓存位图,完成,然后立即开始以更高的速率播放。如果需要,您可以在缓存时隐藏动画。当你不再需要动画时,清除阵列以释放内存。

    package scripts.animation{
        import flash.display.MovieClip;
        import flash.events.*;
        import flash.display.Stage;
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.*;
        import flash.events.Event;
    
    
        public class spriteSheetMaker extends MovieClip {
            private var pWidth:int=0;
            private var pHeight:int=0;
            private var regX:int=0;
            private var regY:int=0;
            private var swfObj:MovieClip = null;
            private var pFrame:int=0;
            private var pFrames:int=0;
            private var pSheetArray:Array=[];
            private var pSheetInfo:Array=[];
            private var pAnimating:Boolean = false;
            private var pAnimationCycle:int = 0;
            //-------------------------------------------------------
            //-------------------------------------------------------
            //init
            //-------------------------------------------------------
            //-------------------------------------------------------
            public function spriteSheetMaker ():void {
                startGrab();
            }
            //-------------------------------------------------------
            //-------------------------------------------------------
            //swf is loaded, find out how many frames are in, dimentions etc, and start animation
            //-------------------------------------------------------
            //-------------------------------------------------------
            public function startGrab ():void {
                swfObj=this.animation;
                swfObj.x = 0;
                //swfObj.y = 0;
                pFrames=swfObj.totalFrames;
                pFrame=0;
                pSheetInfo=[this.name,pWidth,pHeight];
                pSheetArray.push (pSheetInfo);
                pAnimating = false;
                this.addEventListener (Event.ENTER_FRAME,cycleSwfAnim);
            }
            //-------------------------------------------------------
            //-------------------------------------------------------
            //load the next frame of the animation and convert it
            //-------------------------------------------------------
            //-------------------------------------------------------
            private function cycleSwfAnim (event:Event):void {
                pFrame++;
                if (pFrame < pFrames + 2) {
                    swfObj.gotoAndStop (pFrame);
                    grabBitmap ();
                } else {
                    stopGrab ();
                }
            }
            //
            private function stopGrab():void{
                this.removeEventListener (Event.ENTER_FRAME,cycleSwfAnim);
                trace("Sheet = " + pSheetArray);
                swfObj.parent.removeChild(swfObj);
                swfObj=null;
                startAnimationPlayback();
            }
            //-------------------------------------------------------
            //-------------------------------------------------------
            //Convert fram (vector, bitmap, whatever is on the frame) into a bitmadata object
            //-------------------------------------------------------
            //-------------------------------------------------------
            private function grabBitmap ():void {
                pWidth=this.width;
                pHeight=this.height;
                var bmd:BitmapData=new BitmapData(pWidth,pHeight,true,0x00FFFFFF);
                bmd.draw (swfObj);
                var bm:Bitmap = new Bitmap();
                bm.bitmapData = bmd;
                pSheetArray.push (bm);
            }
            //-------------------------------------------------------
            //-------------------------------------------------------
            //Play animation
            //-------------------------------------------------------
            //-------------------------------------------------------
            private function startAnimationPlayback():void{
                this.addEventListener (Event.ENTER_FRAME,animate);
                pFrame =0;
            }
            //
            private function animate(event:Event):void{
                pFrame++;
                if (pFrame>pSheetArray.length){
                    pFrame = 1;
                }
                var bm:Bitmap = pSheetArray[pFrame];
                if (bm != null){
                    if (this.numChildren>0){
                        this.removeChildAt(0);
                    }
                    this.addChild(bm);
                }
            }
        }
    }
    

答案 1 :(得分:0)

你可以通过cacheAsBitmap和cacheAsBitmapMatrix与GPU渲染相结合来获得一些改进,但是对于任何远程复杂的东西来说,仍有可能无法让你接近60fps。

如果您想在移动设备上获得真正的性能,您可能需要查看Starling框架(http://gamua.com/starling/)。它完全将合成和渲染移动到GPU,同时保持对象模型和显示列表非常接近标准Flash等价物。即使在一代或两个旧硬件上,性能也非常快(60fps容易实现)。