游戏中提升效率!

  1.优化显示:透明效果,滤镜,缩放以及旋转可以产生分成绚丽的效果,但是这些效果同时也吃掉了很多的CPU,所以在游戏中尽可能用位图代替这些效果。
    流畅的逻辑运算:另外一个瓶颈是游戏中的逻辑判断。尽量减少不必要的判断,取消程序中的那些临界近似值的判断。出来显示问题,优化逻辑判断是提高游戏性能最为显著的一个。
   2. 使用Vector类存储一组相同类型的数据:Flashplayer10引入了Vector类。除了要求存储数据必须是同一种类型外,它的功能和Array类完全一致。但是如果当需要存储不同类型的数据时,Array的运行效率还要比Vector胜出一筹的。
    用uint代替Math.floor:要对一个小数进行四舍五入,你第一时间可能会想到Math.floor方法,比如Math.floor(9.3213);而将这个数字强制转换为uint类型,可以得到相同个结果:uint(9.3213);更重要的是FlashPlayer处理uint的速度要比Math.floor快的多。
   3. 乘法运算要比除法快两倍:x=(stage.stageWidth/2);与x=(stage.stageWidth*0.5);的结果是一样的,但是乘法的运算效率要比除法快两倍。
    尽量使用查找表:查找表实际是就是一个普通的Array,不过它的数组元素在游戏初始时已经计算好并存储进去了。很显然FlashPlayer在运行过程中去读取一个值要比计算出这个值要快的多。
   4. 避免频繁的创建和删除对象动作:对于要从舞台中删除的对象,如果稍后还会再用到这个对象的话,使用visibility=false将其“删除”,而不是使用removeChild把它从显示列表中删除。因为FlashPlayer中重建对象要比隐藏对象复杂的多。
    使用对象池:在游戏初始化时,把所有需要的对象存放到一个数组中。当需要删除和重建对象是,只需要声明一个对象引用数组中的这个对象即可。这比重新new一个对象出来要快多了。

  5.  位运算有时候会更快:位运算的计算方法和CPU的处理数据本质上是一致的,跟CPU讲它的“母语”,它“理解”起来,做起来自然就更快了!

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    AS3中的DisplayObject有一个render事件,他会在重绘DisplayList之前触发,这给我们提供了在重绘之前最后一次操作的机会。

    每次需要DisplayObject触发render事时,都要调用一次 stage.invalidate();

    下面用一个小例子来说明一下具体用法把。


    假 设我们现在要写一个list组件,该组件有addItem()方法用于添加list项目,和remvoeItem() 方法用于删除list项目,当然还可能有addItemAt(),removeItemAt()等方法,这些方法调用后,都需要对list内的显示对象进 行重新排列。


    我们先实现一个List类,用于显示列表项目
    List类中,有addItem() 和 removeItem() 这两个方法提供给外部调用,用于添加和删除list项目,这两个方法中除了将列表项目添加/删除,还要调用一个方法来重新对list中的项目进行排列,layoutContents()。

    关键就是,这个layoutContents()的调用,他的调用次数越少,那效率当然就越高啦,如果是常规的做法,就是类似这样:
        public function addItem(item:DisplayObject):void {  
            addChild(item);  
            layoutContents();  

        } 

将item加入后,重新排列列表

下面是List类的源代码:

  1. package {  
  2.       
  3. import flash.display.DisplayObject;  
  4. import flash.display.Sprite;  
  5. import flash.events.Event;  
  6. public class List extends Sprite {  
  7.     public function addItem(item:DisplayObject):void {  
  8.         addChild(item);  
  9.         layoutContents();  
  10.     }  
  11.       
  12.     public function removeItem(item:DisplayObject):void {  
  13.         if(contains(item)) {  
  14.             removeChild(item);  
  15.             layoutContents();  
  16.         }  
  17.     }  
  18.       
  19.     //对内部项目进行排列,可以是任意的排列算法  
  20.     protected function layoutcontents():void {  
  21.         trace("do layout");  
  22.           
  23.         var y:Number = 0;  
  24.                   
  25.         var num:int = numChildren;  
  26.         for(var i:int=0; i<num; i++) {  
  27.               
  28.             var child:DisplayObject = getChildAt(i);  
  29.             child.x = 0;  
  30.             child.y = y;  
  31.               
  32.             y += child.height+2;  
  33.         }  
  34.     }  

这个程序粗看似乎没什么问题,但却存在一个效率问题
如果只调用一次addItem,没问题,如果调用10次呢? 前9次的layoutcontents()都不是必须的,只有第十次才是真正需要的这样程序的效率就降低了。
我们可以试一下

先需要一个简单的ListItem

  1. package {  
  2. import flash.display.Shape;  
  3. public class ListItem extends Shape {  
  4.     public function ListItem() {  
  5.         super();  
  6.           
  7.         graphics.beginFill(0xFF6600);  
  8.         graphics.drawRect(0, 0, 30, 16);  
  9.         graphics.endFill();  
  10.     }  
  11. }  

然后测试

  1. package {  
  2. import flash.display.Sprite;  
  3. public class ListTest extends Sprite {  
  4.       
  5.     public function ListTest() {  
  6.           
  7.         var list:List = new List();  
  8.         addChild(list);  
  9.           
  10.         list.addItem(new ListItem());  
  11.         list.addItem(new ListItem());  
  12.         list.addItem(new ListItem());  
  13.           
  14.     }  
  15. }  

我们可以看到,输出了3次 do layout 说明layoutcontents执行了3次,前两次都是多余的。

现在,解决办法就是利用render事件啦。

因为在当前帧内,显示列表更新前会触发render事件,所以在render事件触发后来排列列表项目,就可以保证排列方法在做了任意次的添加或删除操作后只需调用一次,从而提高效率。

这么做只需要对List类稍做一些改动,首先肯定是要监听render事件,我们可以仅监听stage对象的render事件即可,因为这样以后可以做一个独立的RepaintManger来管理所有组件的重绘(可以参考AsWing的RepaintManager类)。
在render事件触发后,做我们需要的调整,由于要render事件触发,就必须先调用stage.invalidate() ,所以每次添加或删除list项目后,都要执行一次该方法,即:


  1. public function addItem(item:DisplayObject):voide {  
  2.     ......  
  3.     stage.invalidate()  
  4. }  

由于是监听的stage的render事件,所以在添加删除操作后,要做一个标记,表示list有改动,需要在render事件后重新排列,如果该标记为 false,那么即使render触发了也不做排列,因为stage的render事件也有可能是由于该stage内的其他child需要重绘而造成 stage的render触发。
下面是改过后的List代码


  1. package {  
  2.       
  3. import flash.display.DisplayObject;  
  4. import flash.display.Sprite;  
  5. import flash.events.Event;  
  6. public class List extends Sprite {  
  7.       
  8.     private var changed:Boolean;  
  9.       
  10.     public function List() {  
  11.         super();  
  12.         addEventListener(Event.ADDED_TO_STAGE, __addToStage);  
  13.     }  
  14.       
  15.     public function addItem(item:DisplayObject):void {  
  16.         addChild(item);  
  17.         requireLayout();  
  18.     }  
  19.       
  20.     public function removeItem(item:DisplayObject):void {  
  21.         if(contains(item)) {  
  22.             removeChild(item);  
  23.             requireLayout();  
  24.         }  
  25.     }  
  26.       
  27.     private function requireLayout():void {  
  28.         changed = true;  
  29.         if(stage != null) stage.invalidate();  
  30.     }  
  31.       
  32.     //对内部项目进行排列,可以是任意的排列算法  
  33.     protected function layoutContents():void {  
  34.         trace("do layout");  
  35.           
  36.         var y:Number = 0;  
  37.                   
  38.         var num:int = numChildren;  
  39.         for(var i:int=0; i<num; i++) {  
  40.               
  41.             var child:DisplayObject = getChildAt(i);  
  42.             child.x = 0;  
  43.             child.y = y;  
  44.               
  45.             y += child.height+2;  
  46.         }  
  47.     }  
  48.       
  49.     private function __addToStage(e:Event):void {  
  50.         stage.addEventListener(Event.RENDER, __render);  
  51.         if(changed) stage.invalidate();  
  52.     }  
  53.       
  54.     private function __render(e:Event):void {  
  55.         if(changed) {  
  56.             layoutContents();  
  57.             changed = false;  
  58.         }  
  59.     }  
  60. }  
  61. }  

当我们再次运行ListTest的时候,do layout 只输出了一次。


就是这些内容,当然,你可能会说,需要做到这些根本不需要这么复杂,只要公开layoutContents方法,在所有操作调用之后让调用者自行调用一次layoutContents()。
在 这个例子中当然可以,但是当情况很复杂的时候,使用者每进行一次操作都要自行调用更新的方法,这样做并不是好的解决方案。试想,如果 flashplayer不会为我们处理显示DisplayObject的工作,而是每次addChild/removeChild之后,我们都需要自行调 用flashplayer底层的方法来让我们需要的东西显示出来,这样做显然很不好。

=======================================================================================================================


Array & Object constructing
构造数组和对象的时候,new Array() and new Object()要比 [] and {}慢3倍的时间

Index Number type for Arrays
数组的数字索引类型
ist[int(0)] 比list[0]要快

Create Array vs. Updating Array
再循环语句中避免多次创建数组,最好创建一次用多次更新内容替换

Nulling Array vs. Splicing Array
对于庞大的数组而言,splice操作是比较耗成本的,要尽量避免

Nulling Object vs. Delete Object
delete一个对象的属性要比把该属性设置为null 更昂贵,所以对于对象的属性最好设置为null

Inline code vs. function references
如果在时间帧上的函数很长而且执行时间长,最好,把该函数分成多个小的函数执行。
这样可以缩短执行时间提高效率

Arguments vs. variable referencing
尽量最小化函数的参数个数

Array push vs. Array index
用设置index的方式来代替使用数组函数push
比如
list[list.length] = data; 要比直接用push快600%;

Array emptying - length 0 vs. A new Array ***
如果你需要设置一个空数组,有一个方便的办法去选择,就是通过设置它的length属性为0
或者你会认为这么做是不错的选择,原因是它能节省内存,但是事实上这样做的执行速度不如直接new array的效率高
当然,如果你需要在一次循环中清除多于510个数组为空时,用length设置为0的时候会更好

Var declarations on multiple lines vs. Var declarations on a single line
将变量声明在一行中,要比声明多行更好,效率更高
i.e.
var a:int=0, b:int=0, c:int=0;
vs.
var a:int=0;
var b:int=0;
var c:int=0;

Using Xor to swap variables
如果你想去交换变量,但是又不想创建新的变量的时候,可以用xor
如:
a = a^b;
b = a^b;
a = a^b;

Multiplication vs. Division
乘法的运算速率总是比除法快,比如5000/1000 要比 5000*0.001快130%;

Type casting comparison 强制转换类型对比
建议使用对应的类型的变量进行比较
同类型的比较效率高的多

Long vs Short variable names
尽量用短的变量名

Nesting Loops(嵌套循环)
多次嵌套循环效率差,所以最好保证循环在2层以内


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值