2011-08-20

AS3优化性能笔记三

尽可能使用内联代码

尽可能使用内联代码以减少代码中函数的调用次数。

Math.abs()方法计算绝对值:

const MAX_NUM:int = 500000;
var arrayValues:Vector.<Number>=new Vector.<Number>(MAX_NUM,true);
var i:int;
 
for (i = 0; i< MAX_NUM; i++)
{
arrayValues[i] = Math.random()-Math.random();
}
 
var started:Number = getTimer();
var currentValue:Number;
 
for (i = 0; i< MAX_NUM; i++)
{
currentValue = arrayValues[i];
arrayValues[i] = Math.abs ( currentValue );
}
 
trace( getTimer() - started );
// output : 70

内联方式,是函数调用运行速度的四倍以上。

const MAX_NUM:int = 500000;
var arrayValues:Vector.<Number>=new Vector.<Number>(MAX_NUM,true);
var i:int;
 
for (i = 0; i< MAX_NUM; i++)
{
arrayValues[i] = Math.random()-Math.random();
}
 
var started:Number = getTimer();
var currentValue:Number;
 
for (i = 0; i< MAX_NUM; i++)
{
currentValue = arrayValues[i];
arrayValues[i] = currentValue > 0 ? currentValue : -currentValue;
}
 
trace( getTimer() - started );
// output : 15

避免计算循环中的语句

不计算循环中的语句也可以实现优化。以下代码遍历数组,但为进行优化。因为在每次遍历时都需要计算数组长度。

for (var i:int = 0; i< myArray.length; i++)
{
}

最好存储该值并重复使用:

var lng:int = myArray.length;
 
for (var i:int = 0; i< lng; i++)
{
}

对while循环使用相反的顺序

以相反顺序进行while循环的速度比正向顺序循环快

var i:int = myArray.length;
 
while (--i > -1)
{
}

尽可能避免使用alpha属性

当显示对象使用alpha值混合处理时,运行时必须将每个堆叠显示对象的颜色值与背景色混合起来,以确定最终颜色。因此会占用更多的处理器资源。

尽可能使用低帧速率

较高的帧速率会耗用更多的CPU资源和电池能量。

如果视频是应用程序中唯一的动态内容,使用低帧速率。因为运行时以本级帧速率播放加载的视频内容,而与应用程序的帧速率无关。

动态更改应用程素的帧速率,例如应用程序不执行任何动画时可降低帧速率。如果应用程序真该后台运行(已失去焦点),可进一步降低帧速率。

2011-08-19

AS3优化性能笔记二

处理像素

使用setVector()方法绘制像素。

var wdth:int = 200;
var hght:int = 200;
var total:int = wdth*hght;
// Pixel colors Vector
var pixels:Vector. = new Vector.(total, true);
 
for ( var i:int = 0; i&lt; total; i++ )
{
// Store the color of each pixel
pixels[i] = Math.random()*0xFFFFFF;
}
 
// Create a non-transparent BitmapData object
var myImage:BitmapData = new BitmapData ( wdth, hght, false );
var imageContainer:Bitmap = new Bitmap ( myImage );
// Paint the pixels
myImage.setVector ( myImage.rect, pixels );
addChild ( imageContainer );

如果用的是较慢的方法,如setPixel()或者setPixel32(),请使用lock()和unlock()方法加快运行速度。

var buffer:BitmapData = new BitmapData(200,200,true,0xFFFFFFFF);
var bitmapContainer:Bitmap = new Bitmap(buffer);
var positionX:int;
var positionY:int;
// Lock update
buffer.lock();
var starting:Number=getTimer();
 
for (var i:int = 0; i&lt;2000000; i++)
{
// Random positions
positionX = Math.random()*200;
positionY = Math.random()*200;
// 40% transparent pixels
buffer.setPixel32( positionX, positionY, 0x66990000 );
}
 
// Unlock update
buffer.unlock();
addChild( bitmapContainer );
trace( getTimer () - starting );
// output : 670

BitmapData类的lock()方法可以锁定图像,并防止引用该图像的对象在BitmapData对象更改时进行更新。

注:如果处理的是位图(而不是显示列表)中的像素(双缓动),有时该技术不会提高性能。如果位图对象没有引用位图缓冲区,则使用lock()和unlock()不会提高性能。

遍历像素的方法(例如getPixel()、getPixel32()、setPixel()、setPixel32()可能速度很慢,特别是移动设备上。如果可能,则使用在一次调用中检索所有像素的方法。要读取像素,使用getVector()方法,它比getPixels()方法速度快。尽可能使用依赖于Vector对象的API,因为它们的运行速度可能会更快。

TextField优化

使用appendText()方法而不要使用 += 运算符。并尽可能的更新循环外的文本字段。

+=运算符:

var myTextField:TextField = new TextField();
addChild ( myTextField );
myTextField.autoSize = TextFieldAutoSize.LEFT;
 
var started:Number = getTimer();
 
for (var i:int = 0; i&lt; 1500; i++ )
{
myTextField.text += "ActionScript 3";
}
 
trace( getTimer() - started );
// output : 1120

appendText()方法:

var myTextField:TextField = new TextField();
addChild ( myTextField );
myTextField.autoSize = TextFieldAutoSize.LEFT;
 
var started:Number = getTimer();
 
for (var i:int = 0; i&lt; 1500; i++ )
{
myTextField.appendText ( "ActionScript 3" );
}
 
trace( getTimer() - started );
// output : 847

在每个循环中更新文本字段会使用很多内部处理。通过仅连接一个字符串并将其分配给循环外的文本字段,可大大减少运行代码所需的时间。

var myTextField:TextField = new TextField();
addChild ( myTextField );
myTextField.autoSize = TextFieldAutoSize.LEFT;
 
var started:Number = getTimer();
var content:String = myTextField.text;
 
for (var i:int = 0; i&lt; 1500; i++ )
{
content += "ActionScript 3";
}
 
myTextField.text = content;
 
trace( getTimer() - started );
// output : 2

处理HTML文本时,前一种方法速度更慢,易造成Timeout异常,如果基础硬件速度太慢,则可能会引发异常。

var myTextField:TextField = new TextField();
addChild ( myTextField );
myTextField.autoSize = TextFieldAutoSize.LEFT;
var started:Number = getTimer();
 
for (var i:int = 0; i&lt; 1500; i++ )
{
myTextField.htmlText += "ActionScript <strong>2</strong>";
}
 
trace( getTimer() - started );

通过此值分配给循环外的字符串,此代码将仅需要29毫秒即可完成:

var myTextField:TextField = new TextField();
addChild ( myTextField );
myTextField.autoSize = TextFieldAutoSize.LEFT;
 
var started:Number = getTimer();
var content:String = myTextField.htmlText;
 
for (var i:int = 0; i&lt; 1500; i++ )
{
content += "<strong>ActionScript</strong> 3";
}
 
myTextField.htmlText = content;
trace ( getTimer() - started );
// output : 29

尽可能避免使用中括号[]运算符

使用中括号运算符可能会降低性能,以下代码演示了使用中括号运算符的效率很低:

var lng:int = 5000;
var arraySprite:Vector. = new Vector.(lng, true);
var i:int;
 
for ( i = 0; i&lt; lng; i++ )
{
arraySprite[i] = new Sprite();
}
 
var started:Number = getTimer();
 
for ( i = 0; i&lt; lng; i++ )
{
arraySprite[i].x = Math.random()*stage.stageWidth;
arraySprite[i].y = Math.random()*stage.stageHeight;
arraySprite[i].alpha = Math.random();
arraySprite[i].rotation = Math.random()*360;
}
 
trace( getTimer() - started );
// output : 16

以下优化的版本减少了对中括号运算符的使用:

var lng:int = 5000;
var arraySprite:Vector. = new Vector.(lng, true);
var i:int;
 
for ( i = 0; i&lt; lng; i++ )
{
arraySprite[i] = new Sprite();
}
 
var started:Number = getTimer();
 
for ( i = 0; i&lt; lng; i++ )
{
currentSprite = arraySprite[i];
currentSprite.x = Math.random()*stage.stageWidth;
currentSprite.y = Math.random()*stage.stageHeight;
currentSprite.alpha = Math.random();
currentSprite.rotation = Math.random()*360;
}
 
trace( getTimer() - started );
// output : 9
2011-08-18

AS3优化性能笔记一

Vector类和Array类

尽可能使用Vector类而不是Array类,尤其是固定长度的Vector类。

Array类

var coordinates:Array = new Array();
 
var started:Number = getTimer();
 
for (var i:int = 0; i<t; 300000; i++)
 
{
 
coordinates[i] = Math.random()*1024;
 
}
 
trace(getTimer() - started);
 
// output: 107

Vector类

var coordinates:Vector.<Number> = new Vector.<Number>();
var started:Number = getTimer();
for (var i:int = 0; i< 300000; i++)
{
coordinates[i] = Math.random()*1024;
}
trace(getTimer() - started);
// output: 72

固定长度的Vector类

var coordinates:Vector.<Number> = new Vector.<Number>(300000, true);
var started:Number = getTimer();
for (var i:int = 0; i< 300000; i++)
{
coordinates[i] = Math.random()*1024;
}
trace(getTimer() - started);
// output: 48

事件捕获和冒泡

使用事件捕获和冒泡可以最大程度地减少事件处理函数。最好在一个对象(而不是多个对象)注册时间处理函数以提高性能,例如在具有多个child的parent上注册事件处理函数而不是为每一个child注册事件处理函数。

例如删除屏幕上被击中的苹果游戏中,以下是为每一个苹果调度MouseEvent.CLICK事件。此代码对各个Apple实例调用addEventListener()方法。此外,还会在用户单击每个苹果时使用removeEventListener()方法删除对应的侦听器。

const MAX_NUM:int = 10;
var sceneWidth:int = stage.stageWidth;
var sceneHeight:int = stage.stageHeight;
var currentApple:InteractiveObject;
var currentAppleClicked:InteractiveObject;
 
for ( var i:int = 0; i< MAX_NUM; i++ )
{
currentApple = new Apple();
currentApple.x = Math.random()*sceneWidth;
currentApple.y = Math.random()*sceneHeight;
addChild ( currentApple );
currentApple.addEventListener ( MouseEvent.CLICK, onAppleClick);
}
 
function onAppleClick ( e:MouseEvent ):void
{
currentAppleClicked = e.currentTarget as InteractiveObject;
currentAppleClicked.removeEventListener(MouseEvent.CLICK, onAppleClick );
removeChild ( currentAppleClicked );
}

使用捕获阶段侦听来自父对象的事件。

const MAX_NUM:int = 10;
var sceneWidth:int = stage.stageWidth;
var sceneHeight:int = stage.stageHeight;
var currentApple:InteractiveObject;
var currentAppleClicked:InteractiveObject;
var container:Sprite = new Sprite();
addChild ( container );
 
// 第三个参数useCapture设置为true,该侦听器只在捕获阶段进行侦听
container.addEventListener ( MouseEvent.CLICK, onAppleClick, true );
 
for ( var i:int = 0; i< MAX_NUM; i++ )
{
currentApple = new Apple();
currentApple.x = Math.random()*sceneWidth;
currentApple.y = Math.random()*sceneHeight;
container.addChild ( currentApple );
}
 
function onAppleClick ( e:MouseEvent ):void
{
currentAppleClicked = e.target as InteractiveObject;
container.removeChild ( currentAppleClicked );
}

可通过停止事件传播(此操作将阻止继续传播事件)来进一步优化处理函数。

function onAppleClick ( e:MouseEvent ):void
{
e.stopPropagation();
currentAppleClicked = e.target as InteractiveObject;
container.removeChild ( currentAppleClicked );
}

冒泡阶段也可用于捕捉事件,方法是将false作为第三个参数传递到addEventListener()方法。因为默认值为false,因此可以忽略。

2011-08-2

添加遮罩使png图片透明部分的鼠标事件失效

根据png图片非透明部分制作一个png图片的遮罩。

private function createMask(bitmapData:BitmapData):Sprite
{
    var mask:Sprite = new Sprite();
    mask.graphics.clear();      
    mask.graphics.beginFill(0xff0000);
    for (var y:uint=0; y<bitmapData.height; y++) 
    {
        for (var x:uint=0; x<bitmapData.width; x++) 
        {                       
            if ((bitmapData.getPixel32(x,y) & 0x000000ff) != 0)
            {
                mask.graphics.drawRect(x,y,1,1);
            }
        }
    }
    mask.graphics.endFill();
    return mask;
}
2011-07-25

ActionScript代码小技巧[zz]

地球人都知道作为一名Flash开发,ActionScript是我们工作的基本语言,如何利用ActionScript写出高效的代码呢? 今天我整理了一篇简单的只针对代码细节的文章和大家一起分享下自己在这方面的积累。

抛除算法和渲染对应用程序的影响还有什么地方会影响程序的效率呢?——那就是代码的细节,这部分最容易被人忽略却又是最容易学习的内容,有的时候可以让你的程序运行得更加快。

1、关于变量的声明:

//声明对象
var obj:Object = new Object{};
//其实这样速度更快,而且写更少的代码
var obj:Object = {};
//声明数组
var arr:Array = new Array();
//这样更快,而且写更少的代码
var arr:Array = [];

2、关于数组的使用

数组除了最常用的Array.push() 和 Array.pop() 函数外,还有两个也是大家常用到的 Array.shift() 和 Array.unshift(),但是后两者的效率却比前者的效率低了几个数量级!如果不是必要,请不要用 Array.shift() 和 Array.unshift()。

还有一个函数 Array.splice() ,一般被大家用来删除数组中的元素,面对数据庞大的数组,此函数会消耗很多的时间,如果对数组的数据顺序不太敏感的话,建议使用下面的优化函数:

function removeElementOfArray(index:int, array:Array):void
{
    var finalIndex:int = array.length - 1;
 
    if (index != finalIndex)
    {
        array[index] = array[finalIndex];
    }
 
    array.pop();
}

获取数组的长度后最好保存下来,下次用不要再去调用 Array.length,因为Array.length的调用也会带来性能损耗的。

3、使用Object还是Dictionary?

很多人都是利用Object或者Dictionary来做哈希表,一般情况下,Dictionary是比Object的访问速度快约15%左右,但是Dictionary在访问不存在的数据的时候,速度要比Object慢10%左右,所以在使用的时候要权衡究竟访问到空数据的比例有多大,进而选择应该使用的对象。

4、关于逻辑判断

很多人喜欢这样写:

foo && bar++;

但是其效率只有下面等价代码的一半

if (foo)
{
    bar++;
}

很多人还喜欢:

if (myVar == null)
{
    //code here...
}

其实下面的代码要更加少并且更加高效

if (!myVar)
{
    //code here...
}

有些人喜欢这样判断String

if (myString != null && myString.length > 0)
{
    //code here...
}

而这样写会更加高效

if (myString)
{
    //code here...
}

5、关于取整和数据转换

把小数转换成整数,这个是程序开发中经常遇到的。下面的语句从慢到快

Math.round(float);
 
Math.ceil(float); // or Math.floor(float);
 
int(float);

把字符串转换成整数或者小数我们经常用:

parseInt(str, 10);
 
parseFloat(str);

如果都是10进制直接用下面更快:

int(str);
 
Number(str);

 

6、关于循环

for循环

for (var i:int=0; i<10000000; ++i)
{
    //code here...
}

要比 while 循环:

while (i < 10000000)
{
    ++i;
}

更快。

转自:TENCENT FLASH TEAM

页面:«1234567...15»