AS3与许多OOP语言一样,包含许多优化技术,对于缺乏经验的用户来说可能是闻所未闻的。这些可以从微宏编码差异到文件结构。帮助经验不足的人:有什么值得了解的提示,这将丰富AS3程序员。
核心思想:是向可能了解基础知识的新程序员介绍优化方法。但不是“经验丰富”程序员的各种技术(特别是在循环中)。
由于大多数as3程序员,将使用flash或flex,因此自然也欢迎涉及它们的编程技巧。
另外请将每个答案限制在一个提示,所以最好的答案自然会浮到顶部=)
然而:AS3,作为一种“编译语言”本身就做了很多优化,所以对于新人来说,这很难按照提示进行。从中学习,而不是它的奴隶。第一步始终是“完成应用程序”。
答案 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:如果可能,只创建单个Array
或Dictionary
实例,只将它们用作容器,以便在方法中生成某些结果。
// 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)并通过BitmapData
和applicationDomain.getDefinition()
获取new
项时,它可能特别有用。缓存你得到的东西可能非常有用。
答案 6 :(得分:2)
自学bitwise operations。在主渲染循环,位图或音频处理中使用它,并学习如何在不需要时使用它来保持程序员友好的代码(这是困难的部分)。
答案 7 :(得分:2)
当然,自Flash Player 10.2以来,新的StageVideo类比使用传统的Video对象渲染更高效。
答案 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,享受。
TurboSignals和as3-signal是可靠的开箱即用实施。我将as3信号视为生产就绪,并在我的日常工作中使用它。
答案 10 :(得分:1)
尽可能多地拆分你的应用程序!
将所有功能分解为类,子类等。避免使用代码混乱MXML包含脚本/初始化脚本,将其保持在最低限度。当你的应用计划可能发生变化时,它将在不太长的时间内帮助,特别是在更大的RIA项目上。它还可以通过交换类和运行搜索替换来简化更改。
让您的代码更容易理解,将来或其他人更容易理解。
答案 11 :(得分:1)
如果您使用Flex Ffamework进行编码,请务必记住Flex Component LifeCycle并在构建自己的组件时使用它。以下是MX Lifecycle和the 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生命周期方法添加其他挂钩。
一些额外的钩子方法:
您将扩展这些方法以执行您自己的功能。从updateDisplayList调用layoutContents和drawBackground。从set currentState方法调用commitCurrentState。
一些辅助方法包括:
您不会扩展这些方法,只需根据需要调用它们。