2012年2月25日土曜日

セミナー「ActionScript 3.0 パフォーマンスチューニング 」覚書

「ActionScript 3.0 パフォーマンスチューニング - 速い、軽い、 うまいスクリプティングを目指す」
講師:野中文雄氏
http://www.jagra.or.jp/schoolblog/2012/01/actionscript-30-1.html

非常に良いセミナーであった。上手い人に教わるとこんなにわかりやすいものかと感動。
忘れないうちに覚書き。


◆Mathクラスについて
「Math.floor()よりint()を用いる 」

またbitmapDataに粒子等を描く場合や、ビットマップ自体を配置するとき小数点以下ピクセルだと画像がにじので、整数化に使ってた。

「Math.max() , Math.min() , Math.abs()は3項演算子で置き換える」
maxNum=Math.max(a , b) → maxNum=(a>b) ? a: b;
minNum=Math.min(a , b) → minNum=(a<b) ? a : b ;
absNum=Math.abs(a )   → absNum=(a<0)? -a : a ; 
で代用する。
『ただしMathの名誉のために言えば』(野中氏の言葉そのまま)
Math.max()やMath.min()などは複数の数が引数にできるので、たくさんの数のうち最も大きいのを調べていときは、Math.max()を用いたほうが速い。
maxNum=Math.max(a , b , c , d , …) ; 

◆距離計算
「PointクラスメソッドのPoint.distanceを用いるより三平方の定理を用いる」
Point.distance(begin , end)→
var dx=endX-biginX ; 
var dy=endY-biginY ;
var distance=Math.sqrt(dx*dx + dy+dy);
一方、3次元の場合に用いるvector3D.distance()も同様
var dx=endX-biginX ; 
var dy=endY-biginY ;
var dz=endZ-biginZ ;
var distance=Math.sqrt(dx*dx + dy*dy+dz*dz);
最後は立方根ではなく平方根を用いることに注意(なぜ?ってのはいまだ理解できてない…)。

◆イベントリスナー
「複数のENTER_FRAMEはひとつにまとめる」
enterframeイベントで動作を記載したmcを複数生成している場合は
ルートのタイムラインなどでまとめて記載する
mc内
addEventListener(Event.EnterFrame , myEnterFrame );
function  myEnterFrame (event:Event):void{
   y+=0.5;
}
mc
root.addListeners(myEnterFrame);
function myEnterFrame(event:Event):void{
  y+=0.5;
}

rootタイムライン
//各mcのメソッド(元enterFrame)格納用のVectorを作成する
var listeners:Vector.<Function>=new Vector.<Function>();
//mcから以下のメソッドを呼び出してそれぞれの更新メソッドを格納する
function addListeners(listener:Function):void{
   listeners.push(listener);
}

//唯一のenterFrameリスナーを設定する
addEventListener(Event.EnterFrame , myEnterFrame);

//EnterFrameを以下で一括動作する
function myEnterFrame(event:Event):void{
  for(var i:int=0  ; i<listeners.length ; i++){
      var myFunction:Function=listeners[ i ] ;
      myFunction(event) ; 
//ここで引数にeventを設定することにより、mc内のメソッドを書き換えなくてよくなる
      //私見:mc内をfunction myEnterFrame(event:Event=null)としておいてもよいかと。
  }
}

◆マウスイベント
「ActionScript3 から無くなったreleaseOutsideはバブリングで判定することにより対応」
入れ子になったmcで
function Test() {
stage.addEventListener(MouseEvent.MOUSE_OUT , stageOut);
addEventListener(MouseEvent.MOUSE_OUT , myOut);
addEventListener(MouseEvent.CLICK , onClick);
}
function onClick(event:MouseEvent):void {
//stage.addEventListener(MouseEvent.MOUSE_OUT , stageOut);
//親ははずさないので親のリスナーだけ生きる
removeChild.addEventListener(MouseEvent.MOUSE_OUT , myOut);
}
といった感じ?実際に後でやってみる。

◆オブジェクトの使い回し
「matrixはnewで都度作らず初期化して再利用」
var matrix:Matrix=new Matrix()で都度生成し、画像などを回転するよりも、
matrix.identity()で初期化してあらたなパラメータを与えて使った方が速い。
「配列も初期化して再利用」
var array=new Array() ;
…処理後

array=new Array()ではなく
array.length=0; で初期化することができる

◆ポリフォーリズム
「見た目は一緒だけど動作が違う」
3つの画像にて説明
Clip1はx回転、Clip2はy回転、Clip3は拡大縮小の繰り返し
switch(mc) {
case clip1:
clip1.rotationX += angle;
break;

case clip2:
clip2.rotationY += angle;
break;
case clip3:
clip3.scaleX = Math.cos(angle++)*1;
clip3.scaleY = Math.cos(angle++)*1;
break;
}

ではなく子の中にそれぞれ以下の記述をし、
//clip1
private function update():void {
rotationX += angle;
}
//clip2
private function update():void {
rotationY += angle;
}
//clip3
private function update():void {
scaleX = Math.cos(angle++)*1;
scaleY = Math.cos(angle++)*1;
}
親では
function xMove():void{

}
function xMove():void{
for(var i:int=0 ; i<mcs ; i++){
 var mc:MovieClip=mcs[ i ];
 mc.xMove();
}
}
で済ませることができる。
このxMoveという同一のメソッド名を用いることがミソ。
同一名称で各々の動作が違う=ポリフォーリズム(多態性)だそうだ。

◆インターフェース
上記例ではそれぞれのmcがxMoveと名前のメソッドを持っていることが前提になる。
もし大規模開発で他社がmcを作ったり自分が作っても間違えてxmoveとしたりしたらエラーとなってしまう。そこでインターフェースを用いる。

//インターフェースは以下の様に記載する
package {
public interface IClip {
//必須のメソッドの引数とその型、
 //返しがある場合はその型を記載する
function xMove(angle:Number):void
function xStop():void
}
}
//インターフェースは以下のように利用する
public class Test extends Sprite implements IClip{
function Test() {

「インターフェースは型としても使える」
以下の例の場合
function xMove():void{
for(var i:int=0 ; i<mcs ; i++){
  var sp:Sprite=sprites[ i ];
  sp.xMove();   →spriteはxMoveメソッドを持っていないのでエラーになる
}
}
そこで
function xMove():void{
for(var i:int=0 ; i<mcs ; i++){
  var sp:IClip=sprites[ i ]; //なんとinterfaceは型指定としても使える!
  sp.xMove();   
}
}
今までクラスを配列化してたり、やる必要もない(しかも不安定?な)継承をしていたのは何だったのか!

◆メモリの開放
「基本はFlashのガベージコレクションにまかせる」
なるべく削除
removeChild
removeEventListener
MovieClip.stop()
=null
を用いて参照を解き、ガベージコレクションを待つ。
が強制的に使えるものとして
System.gc();
System.disposeXML();
System.totalMemory();
var bmd:BitmapData = new BitmapData();
bmd.dispose();
などがある。
Player11以降はガベージコレクションのしきい値(頻繁にやったり、ここではやらんといてとお願いしたり)できるらしい。
これらは次期Flashを入手してからトライしよう。

書籍も近日購入予定。

2 件のコメント:

  1. 三次元の距離も三平方の定理を使っているだけですよ。

    返信削除
    返信
    1. なるほど!ありがとうございます。
      まず平面として考えて
      平面上の距離=Math.sqrt(dx*dx + dy*dy)
      として、
      そこからさらに三角形としてz軸を加味して
      Math.sqrt( 平面上の距離*平面上の距離 + dz*dz)
      =Math.sqrt( Math.sqrt(dx*dx + dy*dy)*Math.sqrt(dx*dx + dy*dy) +dz*dz);
      =Math.sqrt(dx*dx+dy*dy +dz*dz);
      ということかな?

      削除