高效AS3编码的技巧

时间:2011-07-11 08:40:33

标签: flash flex actionscript-3

AS3与许多OOP语言一样,包含许多优化技术,对于缺乏经验的用户来说可能是闻所未闻的。这些可以从微宏编码差异到文件结构。帮助经验不足的人:有什么值得了解的提示,这将丰富AS3程序员。

核心思想:是向可能了解基础知识的新程序员介绍优化方法。但不是“经验丰富”程序员的各种技术(特别是在循环中)。

由于大多数as3程序员,将使用flash或flex,因此自然也欢迎涉及它们的编程技巧。

另外请将每个答案限制在一个提示,所以最好的答案自然会浮到顶部=)

然而:AS3,作为一种“编译语言”本身就做了很多优化,所以对于新人来说,这很难按照提示进行。从中学习,而不是它的奴隶。第一步始终是“完成应用程序”。

14 个答案:

答案 0 :(得分:4)

如果您认真对待游戏编程:evolve your hierarchy,请不要使用深层次结构,自学实体/组件架构(agregation / composition vs inheritance),深入了解PushButton Engine源代码。

答案 1 :(得分:4)

高级游戏编程的另一个优化:使用位图blitting技术(setPixels,BitmapData,而不是MovieClip / Sprites),如下所述:http://mikegrundvig.blogspot.com/2007/05/copypixel-is-faster-then-sprites.html。深入了解Flixel源代码。

答案 2 :(得分:4)

在创建对象时请提供。 尽可能重复使用miscelaneous对象

更好地说:重用你可以的东西,但重用misc对象很容易入手。

这为garbage collector节省了大量工作,从而影响了应用程序的整体性能。这样,您还可以节省在创建冗余实例时可能会丢失的时间。

这些努力并非总是必要,但是,您的应用活动越激烈,以下技术就越有价值。

以下几个提示说明了矩阵,点,数组,字典,...休息,滤镜,颜色变换等方面的想法。

提示1:矩阵。

// DO: reusing a matrix.

private static const MATRIX:Matrix = new Matrix();
// <...>
var bmp:BitmapData = new BitmapData(width, height, true, 0);
MATRIX.identity();
MATRIX.scale(0.5, 0.5);
bmp.draw(source, MATRIX);

// DON'T
var bmp:BitmapData = new BitmapData(width, height, true, 0);
var matrix:Matrix = new Matrix();
matrix.scale(0.5, 0.5);
bmp.draw(source, matrix);

提示2:点。

// DO: reusing a point.

private static const ZERO_POINT:Point = new Point();
// <...>
var thresholdTest:BitmapData = new BitmapData(bmp.width, bmp.height, true, 0);
thresholdTest.threshold(bmp, bmp.rect, ZERO_POINT, ">", 0x10000000, 0xFFFF0000, 0xFF000000);

// DON'T

var thresholdTest:BitmapData = new BitmapData(bmp.width, bmp.height, true, 0);
thresholdTest.threshold(bmp, bmp.rect, new Point(), ">", 0x10000000, 0xFFFF0000, 0xFF000000);

提示3:避免大量使用为您创建冗余实例的方法,除非绝对必要且方便。或者至少在应用会话期间减少此类方法对单个呼叫的使用。

  • localToGlobal()globalToLocal():尝试确定您是否可以自己计算坐标。否则,将在每次调用时创建Point实例。
  • getRect()getBounds():看看您是否可以以不需要检测复杂位移的方式构建显示列表。否则,将在每次调用时创建Rectangle实例。
  • ...rest:Array:很明显,在每个方法调用中,这会创建一个在方法返回时被处理掉的数组。这绝对有必要吗?可能是你可以使用在方法之外创建的数组并且每次都重复使用它(参见下一个提示)?

提示4:如果可能,只创建单个ArrayDictionary实例,只将它们用作容器,以便在方法中生成某些结果。

// DO: reuse array that holds results

public function generateMeSomeResults(results:Array):void
{
    results.length = 0;
    // <...>
    // fill results array with what you need
    // and reuse this reference next time
}

// DON'T

public function generateMeSomeResults():Array
{
    var results:Array = [];
    // <...>
    return results;
}

提示5:每次要更改 someDisplayObject.filters 时,都不要创建新数组和新过滤器对象。如果您为过滤器设置动画并且每个帧中都有更改,这一点尤其重要。

// DO: reuse filters array and filter objects

private static const EMPTY_FILTERS:Array = [];
private static const GLOW:GlowFilter = new GlowFilter(0xFF0000, 1, 12, 12);
private static const HOVER_FILTERS:Array = [GLOW];

private function onRollOver(event:MouseEvent):void
{
    // it's Ok to change constant here
    // because once filters property is set,
    // you are free to change filter object: it will not affect
    // filters that were set before.
    GLOW.color = 0xFF0000+Math.random()*0xFF00;
    this.filters = HOVER_FILTERS;
}

private function onRollOut(event:MouseEvent):void
{
    this.filters = EMPTY_FILTERS;
}

// DON'T

private function onRollOver(event:MouseEvent):void
{
    this.filters = [new GlowFilter(0xFF0000, 1, 12, 12)];
}

private function onRollOut(event:MouseEvent):void
{
    this.filters = [];
}

还有一点需要注意:DisplayObject.filters一个getter / setter。当您获取 DisplayObject.filters值时,您有效地创建了一个不是您想要的新对象。因此,重用一组过滤器是个好主意:你只有一个实例。

提示6:相同的提示5适用于ColorTransform个对象。对于显示对象的色调的每次更改,您不需要单独的ColorTransform实例。设置DisplayObject.transform.colorTransform = someColorTransform;后,您可以自由更改someColorTransform对象:它不会影响已应用的颜色转换。

filters的情况类似,此属性是getter / setter。当您获取 DisplayObject.transform.colorTransform值时,您有效地创建了一个不是您想要的新对象。请参阅下面的测试。

import flash.geom.ColorTransform;

var test1:ColorTransform = transform.colorTransform;
var test2:ColorTransform = transform.colorTransform;
trace(test1 == test2); // always false. this object gets created each time on access.

答案 3 :(得分:3)

尽可能使用向量而不是数组。它比Array具有约60%的性能提升。

  

向量是具有可变类型和/或数组长度限制的数组。

http://www.mikechambers.com/blog/2008/08/19/using-vectors-in-actionscript-3-and-flash-player-10/

一般情况下,不要费心优化所有内容,只优化需要优化的时间和优势,如果优化占代表性能95%的代码的3%,则达到类似的性能水平在3%的时间内优化100%的代码,或者总体上减少33倍的时间......

答案 4 :(得分:3)

使用[]和新的Object()代替新的Array()和{}。它最多快3倍。并且在循环中发生更昂贵的操作是非常常见的。

一般来说,新关键字的价格非常昂贵。

编辑:更新以反映更改:惊喜,似乎更新版本的flash,已经大大提高了“new Object();”的性能。声明。这似乎适用于CS5及以上版本。因为我在CS4中做的测试显示了另一种方式。 [} {更好于新的Object()]

无论如何,对于那些想要自己看的人来说

import flash.utils.getTimer;

public var _time:Number;
public var _simpleArrayTime:Number;
public var buffer:Array;
public function testArray():void
{
    trace( "----------------Array Test--------------");
    _time = getTimer();
    for ( var a:int = 0; a < 100000; a++ )
        buffer = [];
    _simpleArrayTime = getTimer() - _time;
    trace( "[] * 100000 :"+_simpleArrayTime.toPrecision(21) );

    _time = getTimer();
    for ( var b:int = 0; b < 100000; b++ )
        buffer = new Array();
    _simpleArrayTime = getTimer() - _time;
    trace( "new Array() * 100000 :"+_simpleArrayTime.toPrecision(21) );

    _time = getTimer();
    for ( var c:int = 0; c < 100000; c++ )
        buffer = [];
    _simpleArrayTime = getTimer() - _time;
    trace( "[] * 100000 :"+_simpleArrayTime.toPrecision(21) );
}

public var objBuffer:Object;
public function testObject():void
{
    trace( "----------------Object Test--------------");
    _time = getTimer();
    for ( var a:int = 0; a < 100000; a++ )
        objBuffer = {};
    _simpleArrayTime = getTimer() - _time;
    trace( "{} * 100000 :"+_simpleArrayTime.toPrecision(21) );

    _time = getTimer();
    for ( var b:int = 0; b < 100000; b++ )
        objBuffer = new Object();
    _simpleArrayTime = getTimer() - _time;
    trace( "new Object() * 100000 :"+_simpleArrayTime.toPrecision(21) );

    _time = getTimer();
    for ( var c:int = 0; c < 100000; c++ )
        objBuffer = {};
    _simpleArrayTime = getTimer() - _time;
    trace( "{} * 100000 :"+_simpleArrayTime.toPrecision(21) );
}

public function runTests(event:Event = null):void
{
    testArray();
    testObject();
}

以下是我的结果

----------------Array Test--------------
[] * 100000 :82.0000000000000000000
new Array() * 100000 :152.000000000000000000
[] * 100000 :53.0000000000000000000
----------------Object Test--------------
{} * 100000 :53.0000000000000000000
new Object() * 100000 :36.0000000000000000000
{} * 100000 :53.0000000000000000000

答案 5 :(得分:3)

当您需要在一个屏幕上显示多个图像副本时,请不要创建多个BitmapDatas:使用单个BitmapData实例并将其引用传递给单独的Bitmap个对象。

import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.Bitmap;

// create one image
var bmp:BitmapData = new BitmapData(100, 100, true, 0);
bmp.perlinNoise(36, 36, 3, 100, false, false, BitmapDataChannel.BLUE|BitmapDataChannel.GREEN);

// *** display the same image multiple times ***

var test1:Bitmap = new Bitmap(bmp);
test1.x = 0;
test1.y = 0;
addChild(test1);

var test2:Bitmap = new Bitmap(bmp);
test2.x = 30;
test2.y = 30;
addChild(test2);

var test3:Bitmap = new Bitmap(bmp);
test3.x = 60;
test3.y = 60;
addChild(test3);

当您加载外部资源库(SWF)并通过BitmapDataapplicationDomain.getDefinition()获取new项时,它可能特别有用。缓存你得到的东西可能非常有用。

答案 6 :(得分:2)

自学bitwise operations。在主渲染循环,位图或音频处理中使用它,并学习如何在不需要时使用它来保持程序员友好的代码(这是困难的部分)。

答案 7 :(得分:2)

当然,自Flash Player 10.2以来,新的StageVideo类比使用传统的Video对象渲染更高效。

Adobe MAX 2010 Stage Video Preview (video)

Getting Started With Stage Video (tutorial)

答案 8 :(得分:1)

对象实例化很昂贵。在关键代码(渲染,游戏循环)中使用对象池来创建/销毁对象。您可以在此处找到高效的开箱即用库:http://lab.polygonal.de/2008/06/18/using-object-pools/

答案 9 :(得分:1)

在Flash Platform API中大量使用的常用EventDispatcher有一个成本:实例化几个对象,通常继承事件类型。

signal-and-slots模式是一个可靠的替代品,众所周知(参见Boost :: Signals,Qt),并将带来巨大的性能提升,基准here,享受。

TurboSignalsas3-signal是可靠的开箱即用实施。我将as3信号视为生产就绪,并在我的日常工作中使用它。

答案 10 :(得分:1)

尽可能多地拆分你的应用程序!

  

将所有功能分解为类,子类等。避免使用代码混乱MXML包含脚本/初始化脚本,将其保持在最低限度。当你的应用计划可能发生变化时,它将在不太长的时间内帮助,特别是在更大的RIA项目上。它还可以通过交换类和运行搜索替换来简化更改。

     

让您的代码更容易理解,将来或其他人更容易理解。

答案 11 :(得分:1)

如果您使用Flex Ffamework进行编码,请务必记住Flex Component LifeCycle并在构建自己的组件时使用它。以下是MX Lifecyclethe Spark Lifecycle的信息。

生命周期利用Flash Player的渲染事件,并通过将类似的更改分组到代码中的单个位置来节省时间和性能。

答案 12 :(得分:1)

了解Flash Player如何平衡屏幕上的渲染事件以及这些事件背后的执行代码。该方法有时被称为弹性赛道。以下是一些描述其工作原理的相关链接:

http://ted.onflash.org/2005/07/flash-player-mental-model-elastic.php

http://www.craftymind.com/2008/04/18/updated-elastic-racetrack-for-flash-9-and-avm2/

http://ted.onflash.org/2008/04/flash-player-mental-model-elastic.php

一旦你知道它是如何工作的,你就可以用它来优化你的代码

答案 13 :(得分:1)

在为移动设备优化Flex项目时,请务必使用ActionScript而不是MXML构建自定义外观。由于Flex编译器将MXML转换为AS3,因此它并不总是性能最高的。使用ActionScript构建可以避免

您很可能希望扩展MobileSkin类,其中包括辅助方法的额外方法或向标准UIComponent生命周期方法添加其他挂钩。

一些额外的钩子方法:

  • layoutContents()
  • drawBackground()
  • commitCurrentState()

您将扩展这些方法以执行您自己的功能。从updateDisplayList调用layoutContents和drawBackground。从set currentState方法调用commitCurrentState。

一些辅助方法包括:

  • getElementPreferredHeight()
  • getElementPreferredWidth()
  • setElementSize()
  • setElementPosition()

您不会扩展这些方法,只需根据需要调用它们。