优化我的动态背景引擎在ActionScript 3二维Flash游戏我的、背景、引擎、动态

2023-09-08 13:20:31 作者:喜欢受挫

编辑2:判断上的不足的答复,我开始想,如果我的问题是很清楚的。请告诉我,如果我需要更详细地说明。

注意:见底了code更新的

简短的介绍:我正在写一个二维的闪存空间游戏动作。宇宙是无限大的,因为这一特点,背景,必须动态呈现和背景物体(气体云,明星等)已被随机定位。

我创建了一个名为BackgroundEngine和它的工作非常好,但问题是,不过渲染性能。这是如何工作的:

目前启动时,4背景容器(每个阶段的大小)的周围的播放器创建。左上,右上,左下和右下。所有背景正方形被添加到主容器中,背景容易运动。现在,有2轮询功能:

1)垃圾轮询器:查找背景容器并2倍阶段宽度或高度远离游戏者的X或Y坐标,分别。如果是的话,它会删除此背景下方,并允许它进行垃圾回收。

2)渲染轮询:看是否有当前的背景下,在播放器(X的所有方面 - stageWidth,X + stageWidth,Y - stageHeight,Y + stageHeight)。如果不是,那将以此为新的背景方的相应位置。

所有的背景方块用下面的函数创建(即动态创建的那些并在启动时四):

<<<拆除旧的code,见底更新的完整源>>> 的

所有你看到有确保环境看起来非常独特的每平方米的偶合。这实际上的伟大工程,宇宙看起来相当真棒。

以下资产被用作背景的对象:

1)简单星: http://www.feedpostal.com/client /assets/background/1.png (你可能无法看到,一个在白色背景上的浏览器)。

2)的亮星: http://www.feedpostal.com/client /assets/background/2.png

3)白色的气体云: http://www.feedpostal.com/客户端/资产/背景/ 3.png

4)红色气体云: http://www.feedpostal.com/客户端/资产/背景/ 4.png

重要提示:

1)的所有资​​产被缓存,因此它们不必重新下载所有的时间。它们只下载一次

2)图像不旋转或创建之后被缩放,所以我启用的cacheAsBitmap的所有对象,容器和masterContainer。

3)我不得不使用PNG格式,在Photoshop中,因为GIF文件似乎并没有在Flash中呈现非常好,透明度使用时。

那么,问题是,当我周围背景的渲染飞需要太多的表现:在客户端启动滞后(FPS明智的)。正因为如此,我需要优化背景发动机,这样它会呈现快得多。你人可以帮助我在这里?

更新1: 这是我迄今为止的一个响应我后。

BackgroundEngine.as 的

 包com.tommedema.background
{
    进口br.com.stimuli.loading.BulkLoader;

    进口com.tommedema.utils.Settings;
    进口com.tommedema.utils.UtilLib;

    匹配import flash.display.Bitmap;
    进口flash.display.BitmapData;
    进口flash.display.Sprite;
    进口对象类型:flash.events.Event;

    公共final类BackgroundEngine扩展Sprite
    {
    私人静止无功isLoaded:布尔= FALSE;
    私人静止无功bulkLoader:BulkLoader = BulkLoader.getLoader(主);
    私人静止无功masterContainer:雪碧;
    私人静止无功容器:数组= [];
    私人静止无功stageWidth:单元;
    私人静止无功stageHeight:单元;
    私人静止无功资产:阵列;

    //移动背景公司的X坐标
    公共静态函数的Movex(金额:编号):无效
    {
    如果(masterContainer)
    {
    masterContainer.x + =量;
    collectGarbage();
    drawNextContainer();
    }
    }

    //移动背景的y坐标
    公共静态函数moveY(金额:编号):无效
    {
    如果(masterContainer)
    {
    masterContainer.y + =量;
    collectGarbage();
    drawNextContainer();
    }
    }

    //返回是否后台引擎已经装载
    公共静态函数加载():布尔
    {
    返回isLoaded;
    }

    //加载背景引擎
    公众最终的功能加载():无效
    {
    //设置舞台宽度和高度
    stageWidth = stage.stageWidth;
    stageHeight = stage.stageHeight;

    // retreive所有背景的资产
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 1.png,{ID:背景/ 1.png});
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 2.png,{ID:背景/ 2.png});
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 3.png,{ID:背景/ 3.png});
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 4.png,{ID:背景/ 4.png});
    bulkLoader.addEventListener(BulkLoader.COMPLETE,assetsComplete);
    bulkLoader.start();

    //设置isLoaded为真
    isLoaded = TRUE;
    }

    //轮询功能,用于绘制下一个背景广场
    私有静态函数drawNextContainer():无效
    {
    VAR stageCenterX:数= stageWidth / 2;
    VAR stageCenterY:数= stageHeight / 2;
    VAR curContainer:位图= hasBackground(stageCenterX,stageCenterY);
    如果(curContainer)
    {
    			//左上
    如果drawNewSquare(curContainer.x  -  stageWidth,curContainer.y  -  stageHeight)(hasBackground(stageCenterX  -   -  stageWidth,stageCenterY stageHeight)!);
    			//最佳
    如果 -  drawNewSquare(curContainer.x,curContainer.y  -  stageHeight)(hasBackground(stageCenterX,stageCenterY stageHeight)!);
    			//右上
    如果(!hasBackground(stageCenterX + stageWidth,stageCenterY  -  stageHeight))drawNewSquare(curContainer.x + stageWidth,curContainer.y  -  stageHeight);
    //中间偏左
    如果 -  drawNewSquare(curContainer.x  -  stageWidth,curContainer.y)(hasBackground(stageCenterX stageWidth,stageCenterY)!);
    //中右
    如果drawNewSquare(curContainer.x + stageWidth,curContainer.y)(hasBackground(stageCenterX + stageWidth,stageCenterY)!);
    			//左下方
    如果(hasBackground(stageCenterX  -  stageWidth,stageCenterY + stageHeight)!)drawNewSquare(curContainer.x  -  stageWidth,curContainer.y + stageHeight);
    			//底部
    如果(hasBackground(stageCenterX,stageCenterY + stageHeight)!)drawNewSquare(curContainer.x,curContainer.y + stageHeight);
    			//右下角
    如果(!hasBackground(stageCenterX + stageWidth,stageCenterY + stageHeight))drawNewSquare(curContainer.x + stageWidth,curContainer.y + stageHeight);
    }
    }

    //绘制下一个方块,并将其添加到主容器
    私有静态函数drawNewSquare(X:数x,y:编号):无效
    {
    containers.push(genSquareBg());
    VAR CINDEX:UINT = containers.length  -  1;
    容器[CINDEX] .X = X;
    容器[CINDEX] .Y = Y;
    masterContainer.addChild(集装箱[CINDEX]);
    }

    //返回给定的位置是否有背景,如果是返回对应的方
    私有静态函数hasBackground(X:数x,y:号码):位图
    {
    VAR stageX:数字;
    VAR不自然的:数;
    对于(VAR我:UINT = 0; I< containers.length;我++)
    {
    stageX = masterContainer.x +容器[I] .X;
    不自然的= masterContainer.y +容器[I] .Y;
    如果((容器[I])及及(stageX&所述; X)安培;及(stageX + stageWidth&X的催化剂)及及(不自然的&所述; Y)及及(不自然的+ stageHeight> Y))返回容器[I]
    }
    返回null;
    }

    //查询功能,旧的背景广场垃圾收集
    私有静态函数collectGarbage():无效
    {
    VAR stageX:数字;
    VAR不自然的:数;

    对于(VAR我:UINT = 0; I< containers.length;我++)
    {
    如果(容器[I])
    {
    stageX = masterContainer.x +容器[I] .X;
    不自然的= masterContainer.y +容器[I] .Y;
    如果((stageX< -stageWidth * 1.5)||(stageX> stageWidth * 2.5)||(不自然的< -stageHeight * 1.5)||(不自然的> stageHeight * 2.5))
    {
    容器[I] .parent.removeChild(集装箱[I]);
    containers.splice(ⅰ,1);
    }
    }
    }
    }

    //当所有资产已完成下载时调度
    私人最终功能assetsComplete(事件:事件):无效
    {
    资产= [];
    assets.push(bulkLoader.getBitmap(背景/ 1.png)); //星简单
    assets.push(bulkLoader.getBitmap(背景/ 2.png)); //星光灿烂
    assets.push(bulkLoader.getBitmap(背景/ 3.png)); //云白
    assets.push(bulkLoader.getBitmap(背景/ 4.png)); //红云
    		在里面();
    }

    //初始化启动的背景容器
    私人最终功能的init():无效
    {
    masterContainer =新的Sprite(); //创建主容器

    //生成默认背景容器
    containers.push(genSquareBg()); //左上
    容器[0]的.x = 0;
    容器[0] .Y = 0;
    containers.push(genSquareBg()); //最佳
    容器[1]的.x = stageWidth;
    容器[1] .Y = 0;
    containers.push(genSquareBg()); //右上
    容器[2] .X = stageWidth * 2;
    容器[2] .Y = 0;
    containers.push(genSquareBg()); //中间偏左
    容器[3]的.x = 0;
    容器[3] .Y = stageHeight;
    containers.push(genSquareBg()); //中央
    容器[4]的.x = stageWidth;
    容器[4] .Y = stageHeight;
    containers.push(genSquareBg()); //中右
    容器[5] .X = stageWidth * 2;
    容器[5] .Y = stageHeight;
    containers.push(genSquareBg()); //左下方
    容器[6]的.x = 0;
    容器[6] .Y = stageHeight * 2;
    containers.push(genSquareBg()); //底部
    容器[7]的.x = stageWidth;
    容器[7] .Y = stageHeight * 2;
    containers.push(genSquareBg()); //右下角
    容器[8] .X = stageWidth * 2;
    容器[8] .Y = stageHeight * 2;

    //添加新的容器到主容器
    对于(VAR我:UINT = 0; I< = containers.length  -  1;我++)
    {
    masterContainer.addChild(集装箱[I]);
    }

    //显示主容器
    masterContainer.x = 0  -  stageWidth;
    masterContainer.y = 0  -  stageHeight;
    masterContainer.cacheAsBitmap = TRUE;
    的addChild(masterContainer);
    }

    //复制位图显示对象
    私有静态函数dupeBitmap(来源:位图):位图{
    VAR数据:的BitmapData = source.bitmapData;
    VAR位:位图=新位图(数据);
    返回的位图;
    }

    //绘制一个简单的星星
私有静态函数drawStar(X:数x,y:数量,宽度:UINT,身高:UINT):雪碧
{
VAR创作:雪碧=新的Sprite();
creation.graphics.lineStyle(1,0XFFFFFF);
creation.graphics.beginFill(0XFFFFFF);
creation.graphics.drawRect(X,Y​​,宽度,高度);
返回创作;
}

//生成背景方
私有静态函数genSquareBg():位图
{
//设置1%的保证金
VAR宽度:数= stageWidth * 0.99;
VAR HEIGHT:数= stageHeight * 0.99;
变种运行startx:数= 0 + stageWidth / 100;
VAR startY:数​​= 0 + stageHeight / 100;

VAR规模:数;
VAR drawAmount:UINT;
VAR tmpBitmap:位图;
VAR tmpSprite:雪碧;
变种我:UINT;

//创建容器
VAR容器:雪碧=新的Sprite();

//绘制简单的明星
drawAmount = UtilLib.getRandomInt(100,250);
对于(i = 1; I< = drawAmount;我++)
{
tmpSprite = drawStar(0,0,1,1);
tmpSprite.x = UtilLib.getRandomInt(0,stageWidth);
tmpSprite.y = UtilLib.getRandomInt(0,stageHeight);
tmpSprite.alpha = UtilLib.getRandomInt(3,10)/ 10;
比例尺= UtilLib.getRandomInt(2,10)/ 10;
tmpSprite.scaleX = tmpSprite.scaleY =规模;
container.addChild(tmpSprite);
}

//画出明亮的星星
如果(的Math.random()&GT = 0.8)drawAmount = UtilLib.getRandomInt(1,2);
别的drawAmount = 0;
对于(i = 1; I< = drawAmount;我++)
{
tmpBitmap = dupeBitmap(资产[1]);
tmpBitmap.alpha = UtilLib.getRandomInt(3,7)/ 10;
tmpBitmap.rotation = UtilLib.getRandomInt(0,360);
比例尺= UtilLib.getRandomInt(3,10)/ 10;
tmpBitmap.scaleX =规模; tmpBitmap.scaleY =规模;
tmpBitmap.x = UtilLib.getRandomInt(STARTX + tmpBitmap.width,宽 -  tmpBitmap.width);
tmpBitmap.y = UtilLib.getRandomInt(startY + tmpBitmap.height,高度 -  tmpBitmap.height);
container.addChild(tmpBitmap);
}

//画出白云
drawAmount = UtilLib.getRandomInt(1,4);
对于(i = 1; I< = drawAmount;我++)
{
tmpBitmap = dupeBitmap(资产[2]);
tmpBitmap.alpha = UtilLib.getRandomInt(1,10)/ 10;
比例尺= UtilLib.getRandomInt(15,30);
tmpBitmap.scaleX =刻度/ 10;
tmpBitmap.scaleY = UtilLib.getRandomInt(规模/ 2,规模)/ 10;
tmpBitmap.x = UtilLib.getRandomInt(STARTX,宽 -  tmpBitmap.width);
tmpBitmap.y = UtilLib.getRandomInt(startY,高度 -  tmpBitmap.height);
container.addChild(tmpBitmap);
}

//画红云
drawAmount = UtilLib.getRandomInt(0,1);
对于(i = 1; I< = drawAmount;我++)
{
tmpBitmap = dupeBitmap(资产[3]);
tmpBitmap.alpha = UtilLib.getRandomInt(2,6)/ 10;
比例尺= UtilLib.getRandomInt(5,30)/ 10;
tmpBitmap.scaleX =规模; tmpBitmap.scaleY =规模;
tmpBitmap.x = UtilLib.getRandomInt(STARTX,宽 -  tmpBitmap.width);
tmpBitmap.y = UtilLib.getRandomInt(startY,高度 -  tmpBitmap.height);
container.addChild(tmpBitmap);
}

//转换所有层,以一个位图层和回报
VAR的位图数据:的BitmapData =新的BitmapData(stageWidth,stageHeight,真实,0x000000处);
的BitmapData.draw(容器);
容器= NULL;
VAR bitmapContainer:位图=新位图(位图数据);
bitmapContainer.cacheAsBitmap = TRUE;
返回bitmapContainer;
}
    }
}
 

当玩家正在移动,背景MOVEX和moveY方法被调用与玩家的逆方向。这也将导致collectGarbage和drawNextContainer方法被调用。

与此设置的问题在于,有一个最小的容器9始终激活。左上,上,右上,中心左,中,右中,左下,和右下。这需要大量的表现。

编辑:我也想知道,我应该使用的cacheAsBitmap?如果是这样,其上的图像?容器上和主容器或上只有其中一个?当我启用它的所有图像(即使是临时的Sprite对象),它实际上是滞后了。

更新2:

Flash AS教程之七 绘图及颜色的AS编写

这个版本是用方格的两倍大舞台。仅一个或两个正方形应该一次被加载。这是更好,但我还是注意到性能损失,同时移动。它使客户冻结了很短暂的瞬间。任何想法如何优化呢?

BackgroundEngine2.as 的

 包com.tommedema.background
{
    进口br.com.stimuli.loading.BulkLoader;

    进口com.tommedema.utils.Settings;
    进口com.tommedema.utils.UtilLib;

    匹配import flash.display.Bitmap;
    进口flash.display.BitmapData;
    进口flash.display.Sprite;
    进口对象类型:flash.events.Event;

    公共final类BackgroundEngine2扩展Sprite
    {
    	//一般
    私人静止无功isLoaded:布尔= FALSE;
    私人静止无功bulkLoader:BulkLoader = BulkLoader.getLoader(主);
    私人静止无功资产:阵列;

    //对象
    私人静止无功masterContainer:雪碧;
    私人静止无功容器:数组= [];

    	//阶段
    私人静止无功stageWidth:单元;
    私人静止无功stageHeight:单元;
    私人静止无功stageCenterX:数字;
    私人静止无功stageCenterY:数字;

    //移动背景公司的X坐标
    公共静态函数的Movex(金额:编号):无效
    {
    如果(masterContainer!)回报;
    masterContainer.x + =量;
    collectGarbage();
    drawNextContainer();
    }

    //移动背景的y坐标
    公共静态函数moveY(金额:编号):无效
    {
    如果(masterContainer!)回报;
    masterContainer.y + =量;
    collectGarbage();
    drawNextContainer();
    }

    //返回是否后台引擎已经装载
    公共静态函数加载():布尔
    {
    返回isLoaded;
    }

    //加载背景引擎
    公众最终的功能加载():无效
    {
    //设置舞台宽度,高度和中心
    stageWidth = stage.stageWidth;
    stageHeight = stage.stageHeight;
    stageCenterX = stageWidth / 2;
    stageCenterY = stageHeight / 2;

    // retreive背景资产
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 1.png,{ID:背景/ 1.png});
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 2.png,{ID:背景/ 2.png});
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 3.png,{ID:背景/ 3.png});
    bulkLoader.add(Settings.ASSETS_ pre_URL +背景/ 4.png,{ID:背景/ 4.png});
    bulkLoader.addEventListener(BulkLoader.COMPLETE,assetsComplete);
    bulkLoader.start();

    //设置isLoaded为真
    isLoaded = TRUE;
    }

    //轮询功能,用于绘制下一个背景广场
    私有静态函数drawNextContainer():无效
    {
    VAR curContainer:位图= hasBackground(stageCenterX,stageCenterY);
    如果(curContainer)
    {
    如果(hasBackground(stageCenterX  - !stageWidth * 0.75,stageCenterY  -  stageHeight * 0.75))//左上
    drawNewSquare(curContainer.x  -  curContainer.width,curContainer.y  -  curContainer.height);
    如果(hasBackground(stageCenterX,stageCenterY  - !stageHeight * 0.75))//最高
    drawNewSquare(curContainer.x,curContainer.y  -  curContainer.height);
    如果(!hasBackground(stageCenterX + stageWidth * 0.75,stageCenterY  -  stageHeight * 0.75))//右上
    drawNewSquare(curContainer.x + curContainer.width,curContainer.y  -  curContainer.height);
    如果(hasBackground(stageCenterX  - !stageWidth * 0.75,stageCenterY))//中心离开
    drawNewSquare(curContainer.x  -  curContainer.width,curContainer.y);
    如果(!hasBackground(stageCenterX + stageWidth * 0.75,stageCenterY))//中间偏右
    drawNewSquare(curContainer.x + curContainer.width,curContainer.y);
    如果(hasBackground(stageCenterX  - !stageWidth * 0.75,stageCenterY + stageHeight * 0.75))//左下
    drawNewSquare(curContainer.x  -  curContainer.width,curContainer.y + curContainer.height);
    如果(!hasBackground(stageCenterX,stageCenterY + stageHeight * 0.75))//底部中心
    drawNewSquare(curContainer.x,curContainer.y + curContainer.height);
    如果(!hasBackground(stageCenterX + stageWidth * 0.75,stageCenterY + stageHeight * 0.75))//右下
    drawNewSquare(curContainer.x + curContainer.width,curContainer.y + curContainer.height);
    }
    }

    //绘制下一个方块,并将其添加到主容器
    私有静态函数drawNewSquare(X:数x,y:编号):无效
    {
    containers.push(genSquareBg());
    VAR CINDEX:UINT = containers.length  -  1;
    容器[CINDEX] .X = X;
    容器[CINDEX] .Y = Y;
    masterContainer.addChild(集装箱[CINDEX]);
    }

    //返回给定的位置是否有背景,如果是返回对应的方
    私有静态函数hasBackground(X:数x,y:号码):位图
    {
    VAR stageX:数字;
    VAR不自然的:数;
    对于(VAR我:UINT = 0; I< containers.length;我++)
    {
    stageX = masterContainer.x +容器[I] .X;
    不自然的= masterContainer.y +容器[I] .Y;
    如果((容器[I])及及(stageX&所述; X)安培;及(stageX +集装箱[I] .WIDTH&X的催化剂)及及(不自然的&所述; Y)及及(不自然的+集装箱[I] .height> Y))返回容器[I]
    }
    返回null;
    }

    //查询功能,旧的背景广场垃圾收集
    私有静态函数collectGarbage():无效
    {
    VAR stageX:数字;
    VAR不自然的:数;
    对于(VAR我:UINT = 0; I< containers.length;我++)
    {
    如果((容器[I])及&安培;!(isRequiredContainer(集装箱[I])))
    {
    masterContainer.removeChild(集装箱[I]);
    containers.splice(ⅰ,1);
    }
    }
    }

    //返回是否给定的容器所需的显示
    私有静态函数isRequiredContainer(容器:位图):布尔
    {
    如果(hasBackground(stageCenterX,stageCenterY)==容器)​​//中心
    返回true;
    如果(hasBackground(stageCenterX  -  stageWidth * 0.75,stageCenterY  -  stageHeight * 0.75)==容器)​​//左上
    返回true;
    如果(hasBackground(stageCenterX,stageCenterY  -  stageHeight * 0.75)==容器)​​//顶部
    返回true;
    如果(hasBackground(stageCenterX + stageWidth * 0.75,stageCenterY  -  stageHeight * 0.75)==容器)​​//右上
    返回true;
    如果(hasBackground(stageCenterX  -  stageWidth * 0.75,stageCenterY)==容器)​​//中心离开
    返回true;
    如果(hasBackground(stageCenterX + stageWidth * 0.75,stageCenterY)==容器)​​//中间偏右
    返回true;
    如果(hasBackground(stageCenterX  -  stageWidth * 0.75,stageCenterY + stageHeight * 0.75)==容器)​​//左下
    返回true;
    如果(hasBackground(stageCenterX,stageCenterY + stageHeight * 0.75)==容器)​​//底部中央
    返回true;
    如果(hasBackground(stageCenterX + stageWidth * 0.75,stageCenterY + stageHeight * 0.75)==容器)​​//右下
    返回true;
    返回false;
    }

    //当所有资产已完成下载时调度
    私人最终功能assetsComplete(事件:事件):无效
    {
    资产= [];
    assets.push(bulkLoader.getBitmap(背景/ 1.png)); //星简单
    assets.push(bulkLoader.getBitmap(背景/ 2.png)); //星光灿烂
    assets.push(bulkLoader.getBitmap(背景/ 3.png)); //云白
    assets.push(bulkLoader.getBitmap(背景/ 4.png)); //红云
    		在里面();
    }

    //初始化启动的背景容器
    私人最终功能的init():无效
    {
    masterContainer =新的Sprite(); //创建主容器

    //生成默认背景容器
    containers.push(genSquareBg()); //左上
    容器[0]的.x = 0;
    容器[0] .Y = 0;
    masterContainer.addChild(集装箱[0]);

    //显示主容器
    masterContainer.x =  - (stageWidth / 2);
    masterContainer.y =  - (stageHeight / 2);
    masterContainer.cacheAsBitmap = TRUE;
    的addChild(masterContainer);
    }

    //复制位图显示对象
    私有静态函数dupeBitmap(来源:位图):位图{
    VAR数据:的BitmapData = source.bitmapData;
    VAR位:位图=新位图(数据);
    返回的位图;
    }

    //绘制一个简单的星星
    私有静态函数drawStar(X:数x,y:数量,宽度:UINT,身高:UINT):雪碧
    {
    VAR创作:雪碧=新的Sprite();
    creation.graphics.lineStyle(1,0XFFFFFF);
    creation.graphics.beginFill(0XFFFFFF);
    creation.graphics.drawRect(X,Y​​,宽度,高度);
    返回创作;
    }

    //生成背景方
    私有静态函数genSquareBg():位图
    {
    VAR宽度:数= stageWidth * 2;
    VAR HEIGHT:数= stageHeight * 2;
    变种运行startx:数= 0;
    VAR startY:数​​= 0;

    VAR规模:数;
    VAR drawAmount:UINT;
    VAR tmpBitmap:位图;
    VAR tmpSprite:雪碧;
    变种我:UINT;

    //创建容器
    VAR容器:雪碧=新的Sprite();

    //绘制简单的明星
    drawAmount = UtilLib.getRandomInt(100,250);
    对于(i = 1; I< = drawAmount;我++)
    {
    tmpSprite = drawStar(0,0,1,1);
    tmpSprite.x = UtilLib.getRandomInt(STARTX,宽度);
    tmpSprite.y = UtilLib.getRandomInt(startY,高度);
    tmpSprite.alpha = UtilLib.getRandomInt(3,10)/ 10;
    比例尺= UtilLib.getRandomInt(5,15)/ 10;
    tmpSprite.scaleX = tmpSprite.scaleY =规模;
    container.addChild(tmpSprite);
    }

    //画出明亮的星星
    drawAmount = UtilLib.getRandomInt(1,2);
    对于(i = 1; I< = drawAmount;我++)
    {
    tmpBitmap = dupeBitmap(资产[1]);
    tmpBitmap.alpha = UtilLib.getRandomInt(3,7)/ 10;
    tmpBitmap.rotation = UtilLib.getRandomInt(0,360);
    比例尺= UtilLib.getRandomInt(3,10)/ 10;
    tmpBitmap.scaleX =规模; tmpBitmap.scaleY =规模;
    tmpBitmap.x = UtilLib.getRandomInt(STARTX + tmpBitmap.width,宽 -  tmpBitmap.width);
    tmpBitmap.y = UtilLib.getRandomInt(startY + tmpBitmap.height,高度 -  tmpBitmap.height);
    container.addChild(tmpBitmap);
    }

    //画出白云
    drawAmount = UtilLib.getRandomInt(2,4);
    对于(i = 1; I< = drawAmount;我++)
    {
    tmpBitmap = dupeBitmap(资产[2]);
    tmpBitmap.alpha = UtilLib.getRandomInt(1,10)/ 10;
    比例尺= UtilLib.getRandomInt(15,40);
    tmpBitmap.scaleX =刻度/ 10;
    tmpBitmap.scaleY = UtilLib.getRandomInt(规模/ 2,规模* 2)/ 10;
    tmpBitmap.x = UtilLib.getRandomInt(STARTX,宽 -  tmpBitmap.width);
    tmpBitmap.y = UtilLib.getRandomInt(startY,高度 -  tmpBitmap.height);
    container.addChild(tmpBitmap);
    }

    //画红云
    drawAmount = UtilLib.getRandomInt(0,2);
    对于(i = 1; I< = drawAmount;我++)
    {
    tmpBitmap = dupeBitmap(资产[3]);
    tmpBitmap.alpha = UtilLib.getRandomInt(2,6)/ 10;
    比例尺= UtilLib.getRandomInt(5,40)/ 10;
    tmpBitmap.scaleX =规模; tmpBitmap.scaleY =规模;
    tmpBitmap.x = UtilLib.getRandomInt(STARTX,宽 -  tmpBitmap.width);
    tmpBitmap.y = UtilLib.getRandomInt(startY,高度 -  tmpBitmap.height);
    container.addChild(tmpBitmap);
    }

    //转换所有层,以一个位图层和回报
    VAR的位图数据:的BitmapData =新的BitmapData(宽度,高度,真实,0x000000处);
    的BitmapData.draw(容器);
    容器= NULL;
    VAR bitmapContainer:位图=新位图(位图数据);
    //bitmapContainer.cacheAsBitmap = TRUE;
    返回bitmapContainer;
    }
    }
}
 

解决方案

确定,这应该表现出你才可以真正另一个类别的数字与其他aproaches ...

下面的限制是不是星星的数量,限制为密度,即分在同一时间可见数...文本残疾人,我可以得到高达700 @ 30fps的,在酷睿2,具有相当最新版本的调试播放器...

我意识到,Flash播放器是不是很擅长裁剪......这其实用最简单的方式,你花费大量的时间一大堆周围的物体,这是远远可见移动

要真正能够优化的东西,我选择在这里使用MVC ...不是在经典臃肿的方式......这个想法是处理模式,以及是否有任何元素是可见的,创建视图为他们..

现在最好的形式给出是建立一个空间树

您有树叶,包含对象,以及包含叶或节点的节点 如果你的对象添加到一片树叶,它surpases一定的规模,你把它变成有n X ñ叶,redestributing之间的儿童 添加到背景的任何对象将被添加到一个网格,由对象的坐标来确定...创建网格刚刚在时间,一个为树叶开始

这样做的最大的好处是,可以快速隔离可见节点/叶。 在每次迭代中,只有节点/叶这两种转可见,或已经可见(并可能成为无形的),很有意思。你不必在树的其余部分做任何更新。找到所有可见的对象后,创建视图的转可见对象,更新那些只是保持可见,并摧毁意见为不可见物体的位置...

这可以节省非常多的一切......记忆和计算能力... 如果你试图用一个巨大的世界的大小(100000),你会看到,你很快耗尽内存,CPU做任何事情很久以前...实例500000星采用700MB RAM,大约有50颗星星可见,在70 fps的不运行任何巨大的CPU占用率...

发动机概念只是一个证明......和code看起来可怕......我目前感到自豪的是,它支持对象occupate一定区域内,这也是为什么一个对象的唯一功能是几种叶子一部分...我认为,这件事我会删除,但因为它应该给我一个很大的加速......你也看到了,这档了一下,同时加入星,它发生了,当叶子翻转为节点...

我敢肯定,这不是一个空间分割树的最佳方式,它只是这一切,我发现我的那种无用似乎...也许有人谁研究(和理解)CS,可以改进我的方法。 ..:)

除此之外,我用了一个对象池的意见,并 haXe的,因为它执行得更好......一个这可能不是那么聪明,就是要动,而不是把它们放在一个层和移动周围...

所有的单独意见,

有的人还可能导致事成的BitmapData 取值手动,以提高性能,这似乎工作得很好(就是无法找到问题现在)...你应该然而,考虑使用 copyPixels 而不是 ...

希望这有助于...;)

编辑:我决定把我的详细回答成的博客文章 ...有乐趣的阅读...)

Edit 2: judging on the lack of replies I start wondering if my issue is clear enough. Please tell me if I need to elaborate more.

Notice: see bottom for a code update!

Short introduction: I'm writing a 2 dimensional flash space game in actionscript. The universe is infinitely big, because of this feature, the background has to be rendered dynamically and background objects (gas clouds, stars, etc.) have to be positioned randomly.

I created a class called BackgroundEngine and it's working very well, the problem is however the rendering performance. This is how it works:

At startup, 4 background containers (each the size of the stage) are created around the player. Top left, top right, bottom left and bottom right. All background squares are added to a master container, for easy movement of the background. Now, there are 2 polling functions:

1) "garbage poller": looks for background containers that are 2 times the stage width or height away from the player's X or Y coord, respectively. If so, it will remove that background square and allow it for garbage collection.

2) "rendering poller": looks whether there is currently a background at all sides of the player (x - stageWidth, x + stageWidth, y - stageHeight, y + stageHeight). If not, it will draw a new background square at the corresponding location.

All background squares are created with the following function (the ones that are created dynamically and the four on startup):

<<< removed old code, see bottom for updated full source >>>

All the randoms you see there are making sure that the environment looks very unique on every square. This actually works great, the universe looks quite awesome.

The following assets are being used as background objects:

1) Simple stars : http://www.feedpostal.com/client/assets/background/1.png (you probably won't be able to see that one in a browser with a white background).

2) Bright stars : http://www.feedpostal.com/client/assets/background/2.png

3) White gas clouds : http://www.feedpostal.com/client/assets/background/3.png

4) Red gas clouds: http://www.feedpostal.com/client/assets/background/4.png

Important notes:

1) All assets are cached, so they don't have to be re-downloaded all the time. They are only downloaded once.

2) The images are not rotating or being scaled after they are created, so I enabled cacheAsBitmap for all objects, containers and the masterContainer.

3) I had to use PNG formats in Photoshop because GIFs did not seem to be rendered very well in flash when used with transparency.

So, the problem is that when I fly around the rendering of the background takes too much performance: the client starts "lagging" (FPS wise). Because of this, I need to optimize the background engine so that it will render much quicker. Can you folks help me out here?

Update 1: This is what I have so far after the one response I got.

BackgroundEngine.as

package com.tommedema.background
{
    import br.com.stimuli.loading.BulkLoader;

    import com.tommedema.utils.Settings;
    import com.tommedema.utils.UtilLib;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;

    public final class BackgroundEngine extends Sprite
    {
    	private static var isLoaded:Boolean = false;
    	private static var bulkLoader:BulkLoader = BulkLoader.getLoader("main");
    	private static var masterContainer:Sprite;
    	private static var containers:Array = [];
    	private static var stageWidth:uint;
    	private static var stageHeight:uint;
    	private static var assets:Array;

    	//moves the background's X coord
    	public static function moveX(amount:Number):void
    	{
    		if (masterContainer)
    		{
    			masterContainer.x += amount;
    			collectGarbage();
    			drawNextContainer();
    		}
    	}

    	//moves the background's Y coord
    	public static function moveY(amount:Number):void
    	{
    		if (masterContainer)
    		{
    			masterContainer.y += amount;
    			collectGarbage();
    			drawNextContainer();
    		}
    	}

    	//returns whether the background engine has been loaded already
    	public static function loaded():Boolean
    	{
    		return isLoaded;
    	}

    	//loads the background engine
    	public final function load():void
    	{
    		//set stage width and height
    		stageWidth = stage.stageWidth;
    		stageHeight = stage.stageHeight;

    		//retreive all background assets
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/1.png", {id: "background/1.png"});
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/2.png", {id: "background/2.png"});
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/3.png", {id: "background/3.png"});
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/4.png", {id: "background/4.png"});
    		bulkLoader.addEventListener(BulkLoader.COMPLETE, assetsComplete);
    		bulkLoader.start();

    		//set isLoaded to true
    		isLoaded = true;
    	}

    	//poller function for drawing next background squares
    	private static function drawNextContainer():void
    	{
    		var stageCenterX:Number = stageWidth / 2;
    		var stageCenterY:Number = stageHeight / 2;
    		var curContainer:Bitmap = hasBackground(stageCenterX, stageCenterY);
    		if (curContainer)
    		{
    			//top left
    			if (!hasBackground(stageCenterX - stageWidth, stageCenterY - stageHeight)) drawNewSquare(curContainer.x - stageWidth, curContainer.y - stageHeight);
    			//top
    			if (!hasBackground(stageCenterX, stageCenterY - stageHeight)) drawNewSquare(curContainer.x, curContainer.y - stageHeight);
    			//top right
    			if (!hasBackground(stageCenterX + stageWidth, stageCenterY - stageHeight)) drawNewSquare(curContainer.x + stageWidth, curContainer.y - stageHeight);
    			//center left
    			if (!hasBackground(stageCenterX - stageWidth, stageCenterY)) drawNewSquare(curContainer.x - stageWidth, curContainer.y);
    			//center right
    			if (!hasBackground(stageCenterX + stageWidth, stageCenterY)) drawNewSquare(curContainer.x + stageWidth, curContainer.y);
    			//bottom left
    			if (!hasBackground(stageCenterX - stageWidth, stageCenterY + stageHeight)) drawNewSquare(curContainer.x - stageWidth, curContainer.y + stageHeight);
    			//bottom
    			if (!hasBackground(stageCenterX, stageCenterY + stageHeight)) drawNewSquare(curContainer.x, curContainer.y + stageHeight);
    			//bottom right
    			if (!hasBackground(stageCenterX + stageWidth, stageCenterY + stageHeight)) drawNewSquare(curContainer.x + stageWidth, curContainer.y + stageHeight);
    		}
    	}

    	//draws the next square and adds it to the master container
    	private static function drawNewSquare(x:Number, y:Number):void
    	{
    		containers.push(genSquareBg());
    		var cIndex:uint = containers.length - 1;
    		containers[cIndex].x = x;
    		containers[cIndex].y = y;
    		masterContainer.addChild(containers[cIndex]);
    	}

    	//returns whether the given location has a background and if so returns the corresponding square
    	private static function hasBackground(x:Number, y:Number):Bitmap
    	{
    		var stageX:Number;
    		var stageY:Number;
    		for(var i:uint = 0; i < containers.length; i++)
    		{
    			stageX = masterContainer.x + containers[i].x;
    			stageY = masterContainer.y + containers[i].y;
    			if ((containers[i]) && (stageX < x) && (stageX + stageWidth > x) && (stageY < y) && (stageY + stageHeight > y)) return containers[i];
    		}
    		return null;
    	}

    	//polling function for old background squares garbage collection
    	private static function collectGarbage():void
    	{
    		var stageX:Number;
    		var stageY:Number;

    		for(var i:uint = 0; i < containers.length; i++)
    		{
    			if (containers[i])
    			{
    				stageX = masterContainer.x + containers[i].x;
    				stageY = masterContainer.y + containers[i].y;
    				if ((stageX < -stageWidth * 1.5) || (stageX > stageWidth * 2.5) || (stageY < -stageHeight * 1.5) || (stageY > stageHeight * 2.5))
    				{
    					containers[i].parent.removeChild(containers[i]);
    					containers.splice(i, 1);
    				}
    			}
    		}
    	}

    	//dispatched when all assets have finished downloading
    	private final function assetsComplete(event:Event):void
    	{
    		assets = [];
    		assets.push(bulkLoader.getBitmap("background/1.png")); //star simple
    		assets.push(bulkLoader.getBitmap("background/2.png")); //star bright
    		assets.push(bulkLoader.getBitmap("background/3.png")); //cloud white
    		assets.push(bulkLoader.getBitmap("background/4.png")); //cloud red
    		init();
    	}

    	//initializes startup background containers
    	private final function init():void
    	{
    		masterContainer = new Sprite(); //create master container

    		//generate default background containers
    		containers.push(genSquareBg()); //top left
    		containers[0].x = 0;
    		containers[0].y = 0;
    		containers.push(genSquareBg()); //top
    		containers[1].x = stageWidth;
    		containers[1].y = 0;
    		containers.push(genSquareBg()); //top right
    		containers[2].x = stageWidth * 2;
    		containers[2].y = 0;
    		containers.push(genSquareBg()); //center left
    		containers[3].x = 0;
    		containers[3].y = stageHeight;
    		containers.push(genSquareBg()); //center
    		containers[4].x = stageWidth;
    		containers[4].y = stageHeight;
    		containers.push(genSquareBg()); //center right
    		containers[5].x = stageWidth * 2;
    		containers[5].y = stageHeight;
    		containers.push(genSquareBg()); //bottom left
    		containers[6].x = 0;
    		containers[6].y = stageHeight * 2;
    		containers.push(genSquareBg()); //bottom
    		containers[7].x = stageWidth;
    		containers[7].y = stageHeight * 2;
    		containers.push(genSquareBg()); //bottom right
    		containers[8].x = stageWidth * 2;
    		containers[8].y = stageHeight * 2;

    		//add the new containers to the master container
    		for (var i:uint = 0; i <= containers.length - 1; i++)
    		{
    			masterContainer.addChild(containers[i]);	
    		}

    		//display the master container
    		masterContainer.x = 0 - stageWidth;
    		masterContainer.y = 0 - stageHeight;
    		masterContainer.cacheAsBitmap = true;
    		addChild(masterContainer);
    	}

    	//duplicates a bitmap display object
    	private static function dupeBitmap(source:Bitmap):Bitmap {
    		var data:BitmapData = source.bitmapData;
    		var bitmap:Bitmap = new Bitmap(data);
    		return bitmap;
    	}

    	//draws a simple star
	private static function drawStar(x:Number, y:Number, width:uint, height:uint):Sprite
	{
		var creation:Sprite = new Sprite();
		creation.graphics.lineStyle(1, 0xFFFFFF);
		creation.graphics.beginFill(0xFFFFFF);
		creation.graphics.drawRect(x, y, width, height);
		return creation;
	}

	//generates a background square
	private static function genSquareBg():Bitmap
	{
		//set 1% margin
		var width:Number = stageWidth * 0.99;
		var height:Number = stageHeight * 0.99;
		var startX:Number = 0 + stageWidth / 100;
		var startY:Number = 0 + stageHeight / 100;

		var scale:Number;
		var drawAmount:uint;
		var tmpBitmap:Bitmap;
		var tmpSprite:Sprite;
		var i:uint;

		//create container
		var container:Sprite = new Sprite();

		//draw simple stars
		drawAmount = UtilLib.getRandomInt(100, 250);
		for(i = 1; i <= drawAmount; i++)
		{
			tmpSprite = drawStar(0, 0, 1, 1);
			tmpSprite.x = UtilLib.getRandomInt(0, stageWidth);
			tmpSprite.y = UtilLib.getRandomInt(0, stageHeight);
			tmpSprite.alpha = UtilLib.getRandomInt(3, 10) / 10;
			scale = UtilLib.getRandomInt(2, 10) / 10;
			tmpSprite.scaleX = tmpSprite.scaleY = scale;
			container.addChild(tmpSprite);
		}

		//draw bright stars
		if (Math.random() >= 0.8) drawAmount = UtilLib.getRandomInt(1, 2);
		else drawAmount = 0;
		for(i = 1; i <= drawAmount; i++)
		{
			tmpBitmap = dupeBitmap(assets[1]);
			tmpBitmap.alpha = UtilLib.getRandomInt(3, 7) / 10;
			tmpBitmap.rotation = UtilLib.getRandomInt(0, 360);
			scale = UtilLib.getRandomInt(3, 10) / 10;
			tmpBitmap.scaleX = scale; tmpBitmap.scaleY = scale;
			tmpBitmap.x = UtilLib.getRandomInt(startX + tmpBitmap.width, width - tmpBitmap.width);
			tmpBitmap.y = UtilLib.getRandomInt(startY + tmpBitmap.height, height - tmpBitmap.height);
			container.addChild(tmpBitmap);
		}

		//draw white clouds
		drawAmount = UtilLib.getRandomInt(1, 4);
		for(i = 1; i <= drawAmount; i++)
		{
			tmpBitmap = dupeBitmap(assets[2]);
			tmpBitmap.alpha = UtilLib.getRandomInt(1, 10) / 10;
			scale = UtilLib.getRandomInt(15, 30);
			tmpBitmap.scaleX = scale / 10;
			tmpBitmap.scaleY = UtilLib.getRandomInt(scale / 2, scale) / 10;
			tmpBitmap.x = UtilLib.getRandomInt(startX, width - tmpBitmap.width);
			tmpBitmap.y = UtilLib.getRandomInt(startY, height - tmpBitmap.height);
			container.addChild(tmpBitmap);
		}

		//draw red clouds
		drawAmount = UtilLib.getRandomInt(0, 1);
		for(i = 1; i <= drawAmount; i++)
		{
			tmpBitmap = dupeBitmap(assets[3]);
			tmpBitmap.alpha = UtilLib.getRandomInt(2, 6) / 10;
			scale = UtilLib.getRandomInt(5, 30) / 10;
			tmpBitmap.scaleX = scale; tmpBitmap.scaleY = scale;
			tmpBitmap.x = UtilLib.getRandomInt(startX, width - tmpBitmap.width);
			tmpBitmap.y = UtilLib.getRandomInt(startY, height - tmpBitmap.height);
			container.addChild(tmpBitmap);
		}

		//convert all layers to a single bitmap layer and return
		var bitmapData:BitmapData = new BitmapData(stageWidth, stageHeight, true, 0x000000);
		bitmapData.draw(container);
		container = null;
		var bitmapContainer:Bitmap = new Bitmap(bitmapData);
		bitmapContainer.cacheAsBitmap = true;
		return bitmapContainer;
	}
    }
}

When the player is moving, the background moveX and moveY methods are called with the inverse direction of the player. This will also cause the collectGarbage and drawNextContainer methods to be called.

The problem with this setup is that there are a minimum of 9 containers active at all times. Top left, top, top right, center left, center, center right, bottom left, bottom and bottom right. This takes a lot of performance.

Edit: I also wonder, should I use cacheAsBitmap? If so, on which images? On the containers and the master container or on only one of them? When I enable it for all images (even the temporary sprite objects) it's actually lagging more.

Update 2:

This version is using squares that are twice as big as the stage. Only one or two squares should be loaded at a time. It is better, but I still notice a performance hit while moving. It makes the client freeze for a very brief moment. Any idea how to optimize it?

BackgroundEngine2.as

package com.tommedema.background
{
    import br.com.stimuli.loading.BulkLoader;

    import com.tommedema.utils.Settings;
    import com.tommedema.utils.UtilLib;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;

    public final class BackgroundEngine2 extends Sprite
    {
    	//general
    	private static var isLoaded:Boolean = false;		
    	private static var bulkLoader:BulkLoader = BulkLoader.getLoader("main");
    	private static var assets:Array;

    	//objects
    	private static var masterContainer:Sprite;
    	private static var containers:Array = [];

    	//stage
    	private static var stageWidth:uint;
    	private static var stageHeight:uint;
    	private static var stageCenterX:Number;
    	private static var stageCenterY:Number;

    	//moves the background's X coord
    	public static function moveX(amount:Number):void
    	{
    		if (!masterContainer) return;
    		masterContainer.x += amount;
    		collectGarbage();
    		drawNextContainer();
    	}

    	//moves the background's Y coord
    	public static function moveY(amount:Number):void
    	{
    		if (!masterContainer) return;
    		masterContainer.y += amount;
    		collectGarbage();
    		drawNextContainer();
    	}

    	//returns whether the background engine has been loaded already
    	public static function loaded():Boolean
    	{
    		return isLoaded;
    	}

    	//loads the background engine
    	public final function load():void
    	{
    		//set stage width, height and center
    		stageWidth = stage.stageWidth;
    		stageHeight = stage.stageHeight;
    		stageCenterX = stageWidth / 2;
    		stageCenterY = stageHeight / 2;

    		//retreive background assets
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/1.png", {id: "background/1.png"});
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/2.png", {id: "background/2.png"});
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/3.png", {id: "background/3.png"});
    		bulkLoader.add(Settings.ASSETS_PRE_URL + "background/4.png", {id: "background/4.png"});
    		bulkLoader.addEventListener(BulkLoader.COMPLETE, assetsComplete);
    		bulkLoader.start();

    		//set isLoaded to true
    		isLoaded = true;
    	}

    	//poller function for drawing next background squares
    	private static function drawNextContainer():void
    	{
    		var curContainer:Bitmap = hasBackground(stageCenterX, stageCenterY);
    		if (curContainer)
    		{
    			if (!hasBackground(stageCenterX - stageWidth * 0.75, stageCenterY - stageHeight * 0.75)) //top left
    				drawNewSquare(curContainer.x - curContainer.width, curContainer.y - curContainer.height);
    			if (!hasBackground(stageCenterX, stageCenterY - stageHeight * 0.75)) //top
    				drawNewSquare(curContainer.x, curContainer.y - curContainer.height);
    			if (!hasBackground(stageCenterX + stageWidth * 0.75, stageCenterY - stageHeight * 0.75)) //top right
    				drawNewSquare(curContainer.x + curContainer.width, curContainer.y - curContainer.height);
    			if (!hasBackground(stageCenterX - stageWidth * 0.75, stageCenterY)) //center left
    				drawNewSquare(curContainer.x - curContainer.width, curContainer.y);
    			if (!hasBackground(stageCenterX + stageWidth * 0.75, stageCenterY)) //center right
    				drawNewSquare(curContainer.x + curContainer.width, curContainer.y);
    			if (!hasBackground(stageCenterX - stageWidth * 0.75, stageCenterY + stageHeight * 0.75)) //bottom left
    				drawNewSquare(curContainer.x - curContainer.width, curContainer.y + curContainer.height);
    			if (!hasBackground(stageCenterX, stageCenterY + stageHeight * 0.75)) //bottom center
    				drawNewSquare(curContainer.x, curContainer.y + curContainer.height);
    			if (!hasBackground(stageCenterX + stageWidth * 0.75, stageCenterY + stageHeight * 0.75)) //bottom right
    				drawNewSquare(curContainer.x + curContainer.width, curContainer.y + curContainer.height);
    		}
    	}

    	//draws the next square and adds it to the master container
    	private static function drawNewSquare(x:Number, y:Number):void
    	{
    		containers.push(genSquareBg());
    		var cIndex:uint = containers.length - 1;
    		containers[cIndex].x = x;
    		containers[cIndex].y = y;
    		masterContainer.addChild(containers[cIndex]);
    	}

    	//returns whether the given location has a background and if so returns the corresponding square
    	private static function hasBackground(x:Number, y:Number):Bitmap
    	{
    		var stageX:Number;
    		var stageY:Number;
    		for(var i:uint = 0; i < containers.length; i++)
    		{
    			stageX = masterContainer.x + containers[i].x;
    			stageY = masterContainer.y + containers[i].y;
    			if ((containers[i]) && (stageX < x) && (stageX + containers[i].width > x) && (stageY < y) && (stageY + containers[i].height > y)) return containers[i];
    		}
    		return null;
    	}

    	//polling function for old background squares garbage collection
    	private static function collectGarbage():void
    	{
    		var stageX:Number;
    		var stageY:Number;
    		for(var i:uint = 0; i < containers.length; i++)
    		{
    			if ((containers[i]) && (!isRequiredContainer(containers[i])))
    			{
    				masterContainer.removeChild(containers[i]);
    				containers.splice(i, 1);
    			}
    		}
    	}

    	//returns whether the given container is required for display
    	private static function isRequiredContainer(container:Bitmap):Boolean
    	{
    		if (hasBackground(stageCenterX, stageCenterY) == container) //center
    			return true;
    		if (hasBackground(stageCenterX - stageWidth * 0.75, stageCenterY - stageHeight * 0.75) == container) //top left
    			return true;
    		if (hasBackground(stageCenterX, stageCenterY - stageHeight * 0.75) == container) //top
    			return true;
    		if (hasBackground(stageCenterX + stageWidth * 0.75, stageCenterY - stageHeight * 0.75) == container) //top right
    			return true;
    		if (hasBackground(stageCenterX - stageWidth * 0.75, stageCenterY) == container) //center left
    			return true;
    		if (hasBackground(stageCenterX + stageWidth * 0.75, stageCenterY) == container) //center right
    			return true;
    		if (hasBackground(stageCenterX - stageWidth * 0.75, stageCenterY + stageHeight * 0.75) == container) //bottom left
    			return true;
    		if (hasBackground(stageCenterX, stageCenterY + stageHeight * 0.75) == container) //bottom center
    			return true;
    		if (hasBackground(stageCenterX + stageWidth * 0.75, stageCenterY + stageHeight * 0.75) == container) //bottom right
    			return true;
    		return false;
    	}

    	//dispatched when all assets have finished downloading
    	private final function assetsComplete(event:Event):void
    	{
    		assets = [];
    		assets.push(bulkLoader.getBitmap("background/1.png")); //star simple
    		assets.push(bulkLoader.getBitmap("background/2.png")); //star bright
    		assets.push(bulkLoader.getBitmap("background/3.png")); //cloud white
    		assets.push(bulkLoader.getBitmap("background/4.png")); //cloud red
    		init();
    	}

    	//initializes startup background containers
    	private final function init():void
    	{
    		masterContainer = new Sprite(); //create master container

    		//generate default background container
    		containers.push(genSquareBg()); //top left
    		containers[0].x = 0;
    		containers[0].y = 0;
    		masterContainer.addChild(containers[0]);

    		//display the master container
    		masterContainer.x = -(stageWidth / 2);
    		masterContainer.y = -(stageHeight / 2);
    		masterContainer.cacheAsBitmap = true;
    		addChild(masterContainer);
    	}

    	//duplicates a bitmap display object
    	private static function dupeBitmap(source:Bitmap):Bitmap {
    		var data:BitmapData = source.bitmapData;
    		var bitmap:Bitmap = new Bitmap(data);
    		return bitmap;
    	}

    	//draws a simple star
    	private static function drawStar(x:Number, y:Number, width:uint, height:uint):Sprite
    	{
    		var creation:Sprite = new Sprite();
    		creation.graphics.lineStyle(1, 0xFFFFFF);
    		creation.graphics.beginFill(0xFFFFFF);
    		creation.graphics.drawRect(x, y, width, height);
    		return creation;
    	}

    	//generates a background square
    	private static function genSquareBg():Bitmap
    	{
    		var width:Number = stageWidth * 2;
    		var height:Number = stageHeight * 2;
    		var startX:Number = 0;
    		var startY:Number = 0;

    		var scale:Number;
    		var drawAmount:uint;
    		var tmpBitmap:Bitmap;
    		var tmpSprite:Sprite;
    		var i:uint;

    		//create container
    		var container:Sprite = new Sprite();

    		//draw simple stars
    		drawAmount = UtilLib.getRandomInt(100, 250);
    		for(i = 1; i <= drawAmount; i++)
    		{
    			tmpSprite = drawStar(0, 0, 1, 1);
    			tmpSprite.x = UtilLib.getRandomInt(startX, width);
    			tmpSprite.y = UtilLib.getRandomInt(startY, height);
    			tmpSprite.alpha = UtilLib.getRandomInt(3, 10) / 10;
    			scale = UtilLib.getRandomInt(5, 15) / 10;
    			tmpSprite.scaleX = tmpSprite.scaleY = scale;
    			container.addChild(tmpSprite);
    		}

    		//draw bright stars
    		drawAmount = UtilLib.getRandomInt(1, 2);
    		for(i = 1; i <= drawAmount; i++)
    		{
    			tmpBitmap = dupeBitmap(assets[1]);
    			tmpBitmap.alpha = UtilLib.getRandomInt(3, 7) / 10;
    			tmpBitmap.rotation = UtilLib.getRandomInt(0, 360);
    			scale = UtilLib.getRandomInt(3, 10) / 10;
    			tmpBitmap.scaleX = scale; tmpBitmap.scaleY = scale;
    			tmpBitmap.x = UtilLib.getRandomInt(startX + tmpBitmap.width, width - tmpBitmap.width);
    			tmpBitmap.y = UtilLib.getRandomInt(startY + tmpBitmap.height, height - tmpBitmap.height);
    			container.addChild(tmpBitmap);
    		}

    		//draw white clouds
    		drawAmount = UtilLib.getRandomInt(2, 4);
    		for(i = 1; i <= drawAmount; i++)
    		{
    			tmpBitmap = dupeBitmap(assets[2]);
    			tmpBitmap.alpha = UtilLib.getRandomInt(1, 10) / 10;
    			scale = UtilLib.getRandomInt(15, 40);
    			tmpBitmap.scaleX = scale / 10;
    			tmpBitmap.scaleY = UtilLib.getRandomInt(scale / 2, scale * 2) / 10;
    			tmpBitmap.x = UtilLib.getRandomInt(startX, width - tmpBitmap.width);
    			tmpBitmap.y = UtilLib.getRandomInt(startY, height - tmpBitmap.height);
    			container.addChild(tmpBitmap);
    		}

    		//draw red clouds
    		drawAmount = UtilLib.getRandomInt(0, 2);
    		for(i = 1; i <= drawAmount; i++)
    		{
    			tmpBitmap = dupeBitmap(assets[3]);
    			tmpBitmap.alpha = UtilLib.getRandomInt(2, 6) / 10;
    			scale = UtilLib.getRandomInt(5, 40) / 10;
    			tmpBitmap.scaleX = scale; tmpBitmap.scaleY = scale;
    			tmpBitmap.x = UtilLib.getRandomInt(startX, width - tmpBitmap.width);
    			tmpBitmap.y = UtilLib.getRandomInt(startY, height - tmpBitmap.height);
    			container.addChild(tmpBitmap);
    		}

    		//convert all layers to a single bitmap layer and return
    		var bitmapData:BitmapData = new BitmapData(width, height, true, 0x000000);
    		bitmapData.draw(container);
    		container = null;
    		var bitmapContainer:Bitmap = new Bitmap(bitmapData);
    		//bitmapContainer.cacheAsBitmap = true;
    		return bitmapContainer;
    	}
    }
}

解决方案

ok, this should show you can really get another category of numbers with other aproaches ...

the limit here is not the number of stars, the limit is density, i.e. the number of stars visible at the same time ... with text disabled, i can get up to 700 @ 30fps, on a Core2Duo, with quite a recent version of the debug player ...

i realized, flash player is not very good at clipping ... and that actually, using the most simple way, you spend a whole lot of time moving around objects, that are far from being visible ...

to really be able to optimize things, i chose to use MVC here ... not in the classic bloated way ... the idea is to handle the model, and if any elements are visible, create views for them ...

now the best aproach is to build up a spatial tree ...

you have leaves, containing objects, and nodes containing leaves or nodes if you add an object to a leaf and it surpases a certain size, you turn it into a node with nxn leaves, redestributing its children between any object added to the background will be added to a grid, determined by the object's coordinates ... grids are created just-in-time, an start off as leaves

the big advantage of this is, that you can quickly isolate the visible nodes/leaves. in each iteration, only the nodes/leaves which either turn visible, or are already visible (and may become invisible), are interesting. you need not do any updates in the rest of the tree. after finding all the visible objects, you create views for objects that turn visible, update the position of those that simply stay visible, and destroy views for objects that become invisible ...

this saves an awful lot of everything ... memory and computation power ... if you try with a huge world size (100000), you will see, that you run out of RAM quickly, long before CPU does anything ... instantiating 500000 stars uses 700MB ram, with about 50 stars visible, running at 70 fps without any tremendous CPU usage ...

the engine is just a proof of concept ... and code looks awful ... the only feature i am currently proud about is, that it supports object to occupate a certain area, which is why an object can be part of several leafs ... i think, this is something i will remove though, because it should give me a great speed up ... you also see, it stalls a little, while adding stars, which happens, when leafs flip to nodes ...

i am quite sure, this is not the best way for a spatial subdivision tree, it's just that everything i found seemed kind of useless to me ... probably someone who studied (and understood) CS, can refine my approach ... :)

other than that, i used an object pool for the views, and haXe, since it performs better ... a thing that probably is not so clever, is to move all the views individually, instead of putting them on one layer and moving that around ...

some people also render things into BitmapDatas manually, to gain performance, which seems to work quite well (just can't find the question right now) ... you should however consider using copyPixels instead of draw ...

hope this helps ... ;)

edit: i decided to turn my detailed answer into a blog post ... have fun reading ... ;)