actionscript:Flash Actionscript 优化指南

  第章 AS3些优化计算思路方法

  用乘法来代替除法(当除数可转化为有限数时候)比如var n:Number = value * 0.5;要比var n:Number = value / 2;快但差别并不是很大只有在需要大量计算情况下比如3D引擎中差别才比较明显

  用位运算代替除2或乘2比如10>>1要比10*2快而10<<1要比10*2快从测试来看位运算几乎比乘除快但是般情况下我们不能选择位运算比如我们就不能用13>>1来代替13/2尽管前者比后者运算速度更快但2者运算结果却不所以还是要看具体情况

  用unit代替取整运算Math.floor和Math.ceil比如var test:u = u(1.5);要比var test:Number = Math.floor(1.5);快;而var test:u = u(1.5)+1;要比var test:Number = Math.ceil(1.5);也快如果是Math.floor还可以用位运算(>>0)来代替比如var test:u =1.5>>0比unit更快

  用乘-1来代替Math.abs思路方法比如var nn:Number = -23;var test:Number= nn < 0 ? nn * -1 : nn;要比var nn:Number = -23;var test:Number = Math.abs(nn);快当然还有更多优化计算思路方法般来说低级运算要比高级运算速度;内部思路方法比其他思路方法速度快另外要注意这些思路方法有时候可能并定适用

  第 2章 Actionscript 优化指南

  原著 Marco Lapi,alias Lapo, aw译

  在这篇文章中我们将讨论多种优化 Actionscript 代码思路方法.此外我们也针对些典型游戏代码进行了系列测试来最大限度发掘、提高Flash播放器性能何时进行优化对现有进行优化过程有时十分冗长和困难这和原始代码非优化程度有关所以在投入大量时间进行代码优化的前最重要是要估计出要在什么地方对代码做出修改或替换

  个游戏代码最重要部分就是主循环体通常情况下该循环体要在flash帧上执行并控制游戏中角色属性和重要数据参数而对于主循环体以外部分也可能是次要循环部分同样要注意是给其否分配了过多资源而没有分配给那些更需要资源核心部分

  通过积累在各处节约出来时间(可能每处仅仅是几个毫秒)您会明显发现自己swf运行得更加稳定并且游戏感也大大加强

  简洁和高效代码

  书写出十分简洁、可以再次代码(有时可能是面向对象)是项精细工作但这需要多年编程经验对于OOP(object oriented programming面向对象设计)有些场合根本利用不到它优势这使得它显得十分奢侈在有限资源条件下(可能是flash播放器原因)通过更先进思路方法像刚刚提到OOP就可能反而导致令人不满意结果

  我们并不是说OOP对游戏编程不好只是在某些场合它显得过于奢侈和多余毕竟有时候“传统思路方法”却能得到更好结果大体而言用OOP是比较好它让代码维护更加简单但在后文中你会看到有时为了充分发挥flashplayer性能而不采用OOP技术例如:处理快速滚动或者计算十分复杂数学问题基本优化提及代码优化我们马上会联想到执行速度改进而很少去考虑系统资源分配这是当今即使是将被淘汰计算机都有足够内存来运行我们大部分flash游戏(128M内存足以满足大多数情况需要况且512M内存是当今新电脑基本配置)

  变量

  在各种重要代码优化手段中有这么条:在定义局部变量时候定要用关键字var来定义在Flash播放器中局部变量运行速度更快而且在他们作用域外是不耗占系统资源

  aw附:var变量仅仅在花括号对中才有“生命”个人认为没有系统学过编程人容易出错个地方:

awMC.onLoad = function{
 var aw = 1;
}
awMC.onEnterFrame = function{
//不存在aw这个变量
}


  段非优化代码:

function doSomething
{
mx = 100
my = 100
ar = Array
for (y=0; y < my; y)
{
 for (x=0; x < mx; x)
 {
  i = (y * mx) + x
  arr[i] = i 
 }
}
arr
}


  这段代码中并未声明体内那些变量(那些仅仅在内使用变量)为局部变量这使得这些变量被播放器速度更慢并且在执行完毕时候仍然耗占系统资源

  下面列出是经过改进同样功能代码:

function doSomething
{
var mx = 100
var my = 100
var ar = Array
for (var y=0; y < my; y)
{
 for (var x=0; x < mx; x)
 {
  var i = (y * mx) + x
  arr[i] = i
 }
}
arr
}


  这样来所有变量均被定义为了局部变量他们能够更快地被播放器点在大量(10000次)循环运行时显得尤为重要!当结束时候相应局部变量都会被销毁并且释放出他们占有系统资源

  onEnterFrame 事件

  onEnterFrame事件对于游戏开发者而言是非常有用它使得我们能够快速、反复地按照预设帧频(fps)运行回想在Flash5时代这(onEnterFrame实时监控)是种非常流行技术用这样事件来控制机器游戏对手逻辑又或者我们可以在每个子弹上设置这样事件来监测子弹碰撞

  实际上我们并不推荐给过多MoveClip添加这样事件这样做会导致“无头绪码(spaghetti code)”出现并且容易导致效率明显降低

  大多数情况下用单独个onEnterFrame事件就可以解决问题了:用这个主循环来执行你所需要操作

  另个简单办法是设置个合适帧频:要知道帧频越高CPU资源就越紧张在帧频为25-35(fps)的间时onEnterFrame足以很好地执行较复杂代码哪怕你计算机配置较低因此在没有特殊要求场合我们不推荐使用高于60(fps)帧频

  矢量图和位图

  在处理图形前我们定要做出正确选择Flash能对矢量图和位图进行完美兼容然而矢量图和位图在播放器中表现实质却完全区别在用到矢量图时候我们要尽可能简化它们形状去除多余端点这样做将大大降低播放器用于呈现矢量图所要进行计算量个重要方面在于线条运用尽量减少和避免冗陈线条结构它们会直接影响到flash播放效率

  当某个例子透明度小于100时也会对播放速率造成影响所以如果你发现自己Flash播放速率过慢就去挑出这些透明例子来吧!

  那么如果真需要呈现比较复杂场景时你就最好考虑使用位图实现虽然Flash在对位图渲染效率上并不是最优越(比如和Flash“兄长”Director比起来)但丰富视觉内容呈现只能靠位图(和位图同复杂度矢量图形渲染速率非常低)了这也是很多基于区块游戏中广泛采用像素图作为背景原因顺便要提到Flash虽然对GIF,JPG和PNG都有所支持但是渲染速度上PNG还是占有绝对优势

  以我们建议flash中位图都尽可能采用PNG格式

  影片剪辑(MovieClip)可视性[下面将MovieClip简称为mc]

  您可能会经常碰到这样种情况:有大量不可见/屏幕外mc等待出场(比如游戏中屏幕外地图、人物等等)

  要知道播放器仍然要消耗资源来处理这些不可见/屏幕外mc哪怕他们是单帧非播放状态

  最好解决办法的是给这些mc个空白帧当他们不出现在屏幕上时你能用gotoAndStop语句跳转到这从而减少播放器对资源需求

  请务必记住这种情况下简单设置可见度属性为不可见( _visible = false )是无效播放器将继续按照这些mc所停留或播放复杂度来分配资源

  

  在各种需要记录数据应用和游戏中都被广泛使用

  个典型例子就是基于区块Flash游戏在这样游戏中地图有时被存放成形如arr[y][x] 2维虽然这是种很常见思路方法但是如果用却能提高运行效率个重要思路方法来提高效率是在遍历时候使用for in 循环来代替传统 for 或者while循环语法

  例如:

  段代码如下

for (var i in arr)
{
(arr[i] > 50)
{
 // 进行某些操作
}
}


  它执行速度明显高于这段代码:

for (var i=0; i < 10000; i)
{
(arr[i] > 50)
{
 // 进行某些操作
}
}


  前者效率比后者提高了30%这个数字在你游戏要逐帧执行这段代码时候显得更加宝贵!

  高级优化:

  1) for循环 和 while循环

  用while循环将会得到比for循环更好效率然而中读取数据用for in循环式最好选择!

  所以我们不推荐使用:

for (var i=0; i < 1000; i)
{
//进行某些操作
}而推荐使用
var i=-1
while (i < 1000)
{
//进行某些操作
}


  2) 从中读取数据

  我们通过测试发现for in循环效率大大高于其他循环方式参看:

arr =
MAX = 5000
//赋值
for (i=0; i < MAX; i)
{
arr[i] = i
}
var item = null
// For 循环
for (var i=0; i < MAX; i)
{
item = arr[i]
}
// For 循环
for (var i in arr)
{
item = arr[i]
}
// While 循环
i = -1
while(i < MAX)
{
item = arr[i]
}


  3) 向中写入数据(while , for)可以看到while循环稍占优势

  4) _global(全局)变量同Timeline(时间轴)变量

  我们猜测采用全局变量能提高变量速度然而效果并不像预计那样明显

  5) 单行、多行变量赋值

  我们发现单行变量赋值效率大大高于多行比如:

a = 0
b = 0
c = 0
d = 100
e = 100


  效率就不如:

a = b = c = 0
d = e = 100


  6) 变量名寻址

  这个测试反映了变量名预寻址是非常重要尤其是在循环时候定要先给丁个指向这样大大节约了寻址时间

  比如:

var num = null
t = getTimer
for (var i=0; i < MAX; i)
{
num = Math.floor(MAX) - Math.ceil(MAX)
}
t1.text = "Always lookup: " + (getTimer - t)


  就不如:

t = getTimer
var floor = Math.floor
var ceil = Math.ceil
for (var i=0; i < MAX; i)
{
num = floor(MAX) - ceil(MAX)
}


  7) 短变量名和长变量名

  变量名越短效率越高考虑到长变量名也有它好处(比如便于维护等)因此建议在关键部位(比如大量循环出现时候)使用短变量名最好就1-2个

  8) 循环前、后声明变量

  在测试前我们认为循环前声明变量会更加节约时间不料测试结果并不明显甚至还恰恰相反!

// 内部声明
t = getTimer
for (var i=0; i < MAX; i)
{
var test1 = i
}
t1.text = "Inside:" + (getTimer - t)
// 外部声明
t = getTimer
var test2
for (var i=0; i < MAX; i)
{
test2 = i
}


  9) 使用嵌套结构

  当用到复杂条件表达式时把他们打散成为嵌套独立判断结构是最佳方案下面代码我们进行了测试发现这种效果改进明显!

MAX = 20000
a = 1
b = 2
c = -3
d = 4
var i=MAX
while(--i > -1)
{
(a 1 && b 2 && c 3 && d 4)
{
 var k = d * c * b * a
}
}


  //下面判断更加节省时间

var i=MAX
while(--i > -1)
{
(a 1)
{
  (b 2)
 {
  (c 3)
  {
   (d 4)
  {
   var k = d * c * b * a
  }
  }
 }
}
}


  10) 寻找局部变量(this思路方法同with思路方法比较)

  局部变量定位思路方法很多我们发现用with比用this更加有优势!

obj = {}
obj.a = 1
obj.b = 2
obj.c = 3
obj.d = 4
obj.e = 5
obj.f = 6
obj.g = 7
obj.h = 8
obj.test1 = useThis
obj.test2 = useWith
MAX = 10000
function useThis
{
var i = MAX
while(--i > -1)
{
 this.a = 1
 this.b = 2
 this.c = 3
 this.d = 4
 this.e = 5
 this.f = 6
 this.g = 7
 this.h = 8
}
}
function useWith
{
var i = MAX
while(--i > -1)
{
 with(this)
 {
  a = 1
  b = 2
  c = 3
  d = 4
  e = 5
  f = 6
  g = 7
  h = 8
 }
}
}


  11) 循环监听键盘事件

  同刚才所提到寻址我们实现给个指向会得到更好效率比如:

keyDown = Key.isDown
keyLeft = Key.LEFT


  //我们再用 (keyDown(keyLeft))

  附:我们测试了按键代码和键值常量效率发现并无太大差别

  12) Math.floor思路方法和

  这个问题曾在Flashkit论坛被提出讨论过测试表明思路方法反而效率更高我们测试结果也反映了这

  13)eval表达式和中括号语法

  我们并没有发现明显差别并不像刚才所述那样eval表达式比起中括号思路方法并没有太大优势

var mc = eval("_root.myMc" + i)
var mc = _root["myMc" + i]


  //两者效率差不多16) 涉及MC循环:ASBroadcaster 同欢同循环差别

  结论

  我们从这些测试结果中发现对于区别需求采用区别代码我们可以大大提高脚本执行效率虽然我们在这里罗列了许多优化代码思路方法需要大家自己测试、实验还有很多(考虑到每个人需求区别).如果你想更加深入地讨论这类问题可以来我们论坛

  aw附:

  终于翻译完了自己也学到很多好东西大家又什么问题可以去gotoAndPlay官方也可以来我Blog提出!

  第 3章 黑羽AS心得体会:浅释ActionScript代码优化

  本机要比用户定义运行速度更快本机即Flash中内有(rinsic)比如hitTest你没必要自己写个类似

  3.不要过多使用 Object 类型

  数据类型注释应力求精确这样可以提高性能只有在没有适当备选数据类型时才使用 Object 类型同时也便于代码管理时刻知道对象类型和作用同时也有利于编译器编译时优化

  4.避免使用 eval 或数据访问运算符

  通常较为可取且更有效做法是只设置次局部引用不得已时才用eval比如转换_droptarget为MovieClip时

  5.在开始循环前将 Array.length 赋予变量尤其是大循环

  在开始循环前将 Array.length 赋予变量(比如var iLength:Number)将其作为条件使用而不是使用myArr.length 本身

  原因在循环中iLength是Number变量会被放入寄存器使用效率远比访问Array再得到length高例如应使用

var fontArr:Array = TextField.getFontList;
var .gif' />Len:Number = fontArr.length;
for (var i:Number = 0; i < .gif' />Len; i) {
  trace(fontArr[i]);
}




  来代替:

var fontArr:Array = TextField.getFontList;
for (var i:Number = 0; i < fontArr.length; i) {
  trace(fontArr[i]);
}


  6.注重优化循环及所有重复动作

  Flash Player 花费许多时间来处理循环(如使用 Interval 循环)

  7.在局部变量够用时不要使用全局变量类静态变量也要少用

  全局变量是开发者恶梦实在需要全局变量我建议使用singleton设计模式来进行管理

  8.声明变量时添加 var 关键字

  这是为了编译时让编译器知道你变量类型优化编译

  黑羽补充点:对关键字使用要谨慎

  不赞成使用关键字作为自己method和属性名除非你确认后续开发不会用到相同事件名和属性名

  但你如何知道flash使用了多少隐藏关键字?太多了!比如说 Name, invalidate, refresh, mouseOver等等不常用关键词思路方法是使用SEPY编辑器来写代码那里面加亮了所有公布和没有公布关键词而且很有可能和start,load,等这些常用事件名重复带来代码不必要修改和麻烦

  9.对涉及到绘图资源尽量先多判断再

  所有渐变位置变化创建删除MC组件等都涉及到绘图资源在很多情况下尽量先用逻辑判断变量或者对象属性必要时再这些这样可以节省较多计算资源



Tags:  actionscript错误 actionscript3 actionscript3.0 actionscript

延伸阅读

最新评论

发表评论