- 2010年3月17日 01:07
- ActionScript 3.0
3/16、Adobeの太っ腹無料イベント、FlashCampがありました。
AdobeチームによるCS5の新機能紹介とiPhone向けの最適化や、RalphHauwert氏,MarioKlingemann氏,erikNatzke氏,深津貴之氏,新藤愛大氏といった超豪華メンバーでお腹いっぱいになってしまいました。
さて、iPhoneの最適化セッションでは、MikeChambers氏が口を酸っぱくしてpackager for iPhoneでなるたけパフォーマンスをよくするためのテクニックが紹介されていました。
そこではiPhone特有のtipsから、普段から使えるものまで紹介されていたわけですが、その一つ、オブジェクトの再利用(リユース・オブジェクト)と、プリレンダリングを試してみましょう。
繰り返し処理で大量生産
たとえば、一文字のテキストを1000個等間隔に並べて、配列から文字をランダムで参照させる。なんてことをしようとします。
for(var i:int;i<n;i++){
var tf:TextField = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.text = strs[Math.floor(Math.random()*strs.length)];
tf.x = 10*(i%50);
tf.y = 20*Math.floor(i/50)
addChild(tf)
}
forが回るたびにnewで生成し、表示リストに1000個追加しています。環境によりますが、僕の環境ではresultTime = 231と表示されます。ということはたとえば極端な話もし、仮にデスクトップより10倍遅いデバイスでこの処理をすると2000ミリ秒かかるということになり、2秒間完全に固まってしまうかもしれません。※本来の最適化では、何回か連続でメソッドを実行し、その最小・最大・平均を取るのですが、今回は割愛。
TextFieldをリユース(再利用)する
上記のボトルネックは明らかで、forの内部で毎回TextFieldを生成し、追加しています。オブジェクトが大量に生成されることで重くなりますし、そもそもTextField自体が重いのも問題です。 これを、予め用意したTextFieldのみを使い、パーティクル表現などでよく用いられるBitmapDataを使ったアプローチが以下です。
var length:int = strs.length;
var tf:TextField = new TextField();
tf.autoSize = "left";
var bd:BitmapData = new BitmapData(500,400,false);
var mtx:Matrix = new Matrix();
var i:int;
while(i<n){
tf.text = strs[Math.floor(Math.random()*length)];
mtx.tx = 10*(i%50);
mtx.ty = 20*Math.floor(i/50);
bd.draw(tf,mtx);
i++;
}
addChild(new Bitmap(bd))
スコアがちょっとあがりましたね。僕の環境ではresultTime = 160と表示されています。ただ、まだ改善点がありそうです。現在はTextFieldに毎回テキストを配列から参照してきています。8文字しか入っていない配列では、1000回のうちに何回も同じ文字が出現するはずです。毎回テキストフィールドに加えて転写するのではなく、事前に用意しておいたらどうでしょうか?
プリレンダリング
出現するものが決まっているなら、前もって用意しておけばいいじゃん。というのがプリレンダリングです。テキストフィールドに対して文字を入れたものを、文字ごとにずらしてbitmapdataに転写しておき、それから後はbitmapdataに対してdrawではなくcopyPixelsで転写することでさらに高速化をねらいます。また、copyPixelsに必要なPointやRectangleなどもその都度生成せずに確保しておき、適宜プロパティを変更します。
var strs:Array = ["a","b","c","d","e","f","g","h"];
var length:int = strs.length;
var tf:TextField = new TextField();
tf.autoSize = "left";
var bd:BitmapData = new BitmapData(80,20,false);
var mtx:Matrix = new Matrix();
var i:int;
while(i <length){
tf.text = strs[i];
mtx.tx = 10*i;
bd.draw(tf,mtx);
i++;
}
bd.lock();
var bd2:BitmapData = new BitmapData(500,400,false);
var pt:Point = new Point(0,0);
var rect:Rectangle = new Rectangle(0,0,10,20)
i=0;
while(i<n){
pt.x=10*(i%50);
pt.y=20*Math.floor(i/50);
rect.x = Math.floor(Math.random()*length)*10;
bd2.copyPixels(bd,rect,pt)
i++;
}
addChild(new Bitmap(bd2));
僕の環境では、resultTime = 6と表示されています。コード数は長くなりますが、凄い効き目ですね。最初の231から比べれば、雲泥の差といえます。実はまだ改善の余地があるのですが、今回はこの辺で。



