在手机Flash/AIR游戏中获得高FPS?

在手机Flash/AIR游戏中获得高FPS?,flash,mobile,air,game-development,Flash,Mobile,Air,Game Development,我正在开发一款游戏,旨在将其作为“本地”应用程序和桌面web浏览器部署在手机上 由于在多个平台上工作,Flash及其嵌入式AIR似乎是一个不错的解决方案。但是呢,哦 目前只使用4个关键帧的movieclips(将它们添加到舞台上,更新它们在每一帧上的位置,并最终移除它们),这使得游戏在桌面屏幕上显示大约30个时变慢,在我的Android(三星i9000-2.3.3)上显示大约20个时变慢。我可能还需要更多 所以我尝试了Blitter,通过重新绘制位图区域,并将我的MovieClips转换为Bit

我正在开发一款游戏,旨在将其作为“本地”应用程序和桌面web浏览器部署在手机上

由于在多个平台上工作,Flash及其嵌入式AIR似乎是一个不错的解决方案。但是呢,哦

目前只使用4个关键帧的movieclips(将它们添加到舞台上,更新它们在每一帧上的位置,并最终移除它们),这使得游戏在桌面屏幕上显示大约30个时变慢,在我的Android(三星i9000-2.3.3)上显示大约20个时变慢。我可能还需要更多

所以我尝试了Blitter,通过重新绘制位图区域,并将我的MovieClips转换为BitMapData SpriteSheet,存储在我的Flash库中。桌面上的效果非常好,有完美、平滑的动画,甚至有数百个对象。但在移动设备上的结果很糟糕,即使只有一个对象显示在屏幕上,CPU或GPU渲染,FPS也会下降到15

因为我的游戏在“旧”设备上运行显然是件好事,如果我想达到接近或高于50的帧速率,那么现在使用Flash和AIR是个坏主意吗


在使用flash开发手机游戏时,是否需要使用一些技巧或必不可少的实践?在这种情况下,我们是否必须避免任何常见错误?

您可以使用cacheAsBitmap和cacheAsBitmapMatrix,并结合GPU渲染,获得一些改进,但很可能对于任何远程复杂的情况,仍然无法获得接近60fps的速度


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

您可以使用cacheAsBitmap和cacheAsBitmapMatrix,并结合GPU渲染,获得一些改进,但对于任何远程复杂的内容,仍然无法达到接近60 fps的速度


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

在AdobeAIR中,通过非常复杂的Flash矢量动画,您实际上可以获得30 fps到50 fps的速度

不要做什么:

  • 不要对任何动画使用预先制作的“缓存为位图”复选框。当应用于静态矢量图像时,这是一个很好的特性,因为它将其转换为静态位图。如果动画以除在x轴或y轴上平移电影剪辑以外的任何方式设置动画,则启用“缓存为位图”后,动画实际上会变慢

  • 不要做闪电游戏。Blitting可以让游戏在Flash中快速燃烧,但在AdobeAIR上会让游戏变得更慢。您需要的是放置在舞台上的位图对象,而不是将bitmapData对象点显到舞台上

  • 所以,您可以抓取swf或Movieclip,遍历对象的每一帧,并将每一帧转换为位图。然后,将每个位图保存到数组中。然后,要播放动画,请从阵列中检索位图并将其顺序放置在舞台上。在我的测试中,我能够在Android平板电脑上以超过40fps的速度运行全屏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);
                }
            }
        }
    }
    
    package scripts.animation{
    导入flash.display.MovieClip;
    导入flash.events.*;
    导入flash.display.Stage;
    导入flash.display.Bitmap;
    导入flash.display.BitmapData;
    导入flash.display.*;
    导入flash.events.Event;
    公共类spriteSheetMaker扩展MovieClip{
    私有变量pWidth:int=0;
    私有变量pHeight:int=0;
    私有变量regX:int=0;
    私有变量regY:int=0;
    私有变量swfObj:MovieClip=null;
    私有变量pFrame:int=0;
    私有var参数:int=0;
    私有变量pSheetArray:Array=[];
    私有变量pSheetInfo:Array=[];
    private-var-pAnimating:Boolean=false;
    私有变量pAnimationCycle:int=0;
    //-------------------------------------------------------
    //-------------------------------------------------------
    //初始化
    //-------------------------------------------------------
    //-------------------------------------------------------
    公共函数spriteSheetMaker():void{
    startGrab();
    }
    //-------------------------------------------------------
    //-------------------------------------------------------
    //加载swf后,找出有多少帧在其中,尺寸等,然后开始动画
    //-------------------------------------------------------
    //-------------------------------------------------------
    公共函数startGrab():void{
    swfObj=this.animation;
    swfObj.x=0;
    //swfObj.y=0;
    pFrames=swfObj.totalFrames;
    pFrame=0;
    pSheetInfo=[this.name,pWidth,pHeight];
    pSheetArray.push(pSheetInfo);
    平移=假;
    this.addEventListener(事件.输入帧,循环WFanim);
    }
    //-------------------------------------------------------
    //-------------------------------------------------------
    //加载动画的下一帧并将其转换
    //-------------------------------------------------------
    //----------------------------