Now on Sale!! 『ActionScript 3.0プロフェッショナルガイド』をテキストにした短期集中講座 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
■Mailing List: ActionScript 3.0 Adobe MAX Japan 2009 ActionScript 3.0におけるパフォーマンス向上のヒント
■サンプルファイル(Flash CS4形式/約40KB) 本稿は、ActionScript 3.0のスクリプティングで、パフォーマンスを高めるテクニックを解説する。ActionScript 3.0は、最適化されたAVM2(ActionScript Virtual Machine 2)で動作する[*1]。そのパフォーマンスを引出すポイントおよび、さまざまな小ネタをアラカルトで紹介する。内容の多くは、ActionScript 2.0でも活用できるだろう。 【追記】本講演の内容に基本的な説明や補足を加えて、Adobeデベロッパーセンターに「ActionScript 3.0におけるパフォーマンス向上のヒント」として寄稿した。
01 データ型を指定する 図001■型指定がバイトコードを最適化する! バイトコードが最適化されるというのは、Flash Player上におけるActionScriptの処理効率が高まることを意味する。 変数や関数に対するデータ型の指定の仕方はつぎのとおりだ。 【変数の型指定】 【関数の型指定】
ActionScript 3.0で型指定による最適化の恩恵を受けるには、「強い参照」(strong reference)が必要だ。それは、型指定とドットシンタックスにより得ることができる。
たとえば、整数を格納するaというプロパティをObjectインスタンスに設定したとき、このプロパティには型指定ができない。
カスタムクラスを定義すれば、プロパティのデータ型が指定でき、処理も最適化されるので、プロパティへのアクセスは速くなる(スクリプト001)[*3]。 スクリプト001■int型のブロパティをもったクラスの定義
クラスMyClassにint型で宣言したプロパティaに文字列(String型)の値を代入しようとすれば、Objectクラスの場合とは異なり、[コンパイルエラー]が生じる(図002)。 図002■クラス定義で型指定したプロパティに異なるデータ型の値を入れようとするとコンパイルエラー
02 型指定した変数を活用する ●配列エレメントを処理する
継続条件に指定したArray.lengthプロパティの値が、ループするたびに毎回参照される。この値は、予め型指定した変数(nLength)に納めておく方がよい(スクリプト002)[*4]。 スクリプト002■配列のループ処理ではArray.lengthプロパティの値は予め型指定した変数に納めておく
なお、forステートメントのカウンタ変数(i)は通常整数を用いるので、浮動小数値(Number型)でなく整数(intまたはuint型)で指定する方が処理は速くなる。 ●TextFieldインスタンスに文字列を加える 図003■TextField.textプロパティに演算子+=でテキストを追加すると警告が表示される では、forループでTextFieldインスタンスに、文字列を連続して加えてみよう。たとえば、0から9までの数字をTextFieldインスタンスに続けて追加するなら、forステートメントをつぎのように記述すればよいだろうか。
TextFieldインスタンスに文字列を設定する操作は、そもそも負荷が高い。forステートメントで繰返すコードブロックからは、できるだけ重い処理を外すべきだ。 繰返す文字列の連結にはStringで型指定した変数を用い、forループが終わってからその変数の文字列をTextFieldインスタンスに加えればよい(スクリプト003)[*5]。 スクリプト003■String型の変数にループ処理で文字列を加えた後TextField.appendText()メソッド使用
03 条件判定を考える たとえば、「うるう年かどうかを判定する関数」を定義して、引数に渡した整数の年がうるう年であればtrue、そうでなければfalseを返すことにしよう。うるう年は、つぎのように定められている。
すると、うるう年を判定する関数isLeapYear()は、以下のスクリプト004のように定義することが考えられる(図005)。なお、剰余演算子%は、右側の項(オペランド[*6])で割った余りを求める。 スクリプト004■複数の条件を組合わせて判定する
図005■複数の条件をifステートメントに指定
しかし、条件をいくつも組合わせると複雑になりがちで、誤りを生みやすく、最適化のための分析もしにくい。if/else if/elseステートメントで条件を組合わせて指定するとそれらが順に判定され、最初にtrueと評価されたコードブロックを実行したらただちに処理を抜ける。 いわばテレビ番組の勝抜けクイズと同じで、1問でも正解すればその人はその場で解答者席から抜け、あとの問題には答える必要がない(図006)。すると、条件の順序が大切になる。 図006■条件判定の処理は勝抜けクイズと同じ 収穫したみかんを大きさによって仕分けるみかん選別機は、コンベヤーの先に大きさの異なる穴が空いている(図007)。そのとき、手前からS、つぎにM、そして最後にLの穴という順にすれば、正しく仕分けられる。 図007■みかん選別機の穴は手前から順にSML 条件は例外から考えると、整理しやすいことが少なくない。うるう年についても、例外の例外である400で割切れる場合から順に考えるとわかりやすい(スクリプト005)。 スクリプト005■例外から順に判定する
400で割切れれば迷うことなくうるう年だ。つぎの条件の100で割切れるというのは、例外で普通の年になる。これで例外はすべて勝抜けたので、あとは4で割切れるかどうかにより、うるう年と普通の年とを仕分ければよい。 もっとも、この仕分けは、あまり効率がよくない。最初に勝抜けるのは、400年に1度のうるう年だ。ざっと3/4を占めるであろうごく普通の年は最後まで残ってしまう。 処理効率を高めるには、できるだけ初めの方の問題で、より多くの勝抜けを出すべきだ(スクリプト006)。 スクリプト006■初めに多くの勝抜けを出す
条件を否定形にしているので、少しわかりにくいかもしれない。けれど、仕分けを前掲スクリプト005とはちょうど逆の順序にしているだけだ。スクリプト005やスクリプト004と比べて、処理の効率は高まっている。 スクリプト004のように複数条件を論理演算子&&や||で組合わせる場合にも、最適化は考えられる。評価が論理演算子の左辺(左オペランド)だけで判定できる場合、右辺(右オペランド)は評価されない。 if ((nYear%4 == 0 && nYear%100 != 0) || nYear%400 == 0) { よって、スクリプト004におけるif条件の最初の論理式「nYear%4 == 0 && nYear%100 != 0」は、関数の引数nYearが4の倍数でなければ、論理積演算子&&の右オペランドである「nYear%100 != 0」は評価することなくfalseを返す。そして、つぎの論理演算子が論理和||なので、その右オペランド「nYear%400 == 0」がつぎに評価される。 また、逆に引数nYearが4の倍数であれば、つぎに論理積演算子&&の右オペランドが評価される。つまり、スクリプト004の条件の組合わせでは、少なくともふたつ以上の論理式を評価しなければ、条件判定ができない。それに対してスクリプト006は、ひとつの論理式の評価だけで、3/4近くを占める普通の年を勝抜けさせてしまう。
04 visibleとalphaとremoveChild()
●DisplayObject.visibleプロパティ 注意しなければならないのは、インスタンスが表示リスト内には存在し続け、そのサイズの情報も残ったままだということだ。たとえば、他のインスタンスとの当たり判定の領域には含まれるし、表示リスト内のインスタンスすべてを処理しようとすると非表示のインスタンスも対象となる。 なお、DisplayObject.visibleプロパティをfalseに設定したインスタンスは、マウスイベントを受取らない。 ●DisplayObject.alphaプロパティ インスタンスが表示リスト内に存在し続け、サイズ情報に反映されることはDisplayObject.visibleプロパティと変わらない。違うのは、DisplayObject.alphaプロパティを0にしても、マウスイベントを受取ることだ。つまり、透明ボタンができる。 もっとも、透明ボタンをつくるには、Sprite.hitAreaプロパティにヒット領域とするインスタンスを指定し、そのDisplayObject.visibleプロパティをfalseにしてしまう方法がある(図008)。このやり方であれば、描画負荷はかからない。 図008■Sprite.hitAreaプロパティに非表示のインスタンスを指定する ●DisplayObjectContainer.removeChild()メソッド けれど、もとどおりに表示しようとすると、インスタンスを表示リストから削除する前の情報が必要になる。表示・非表示を頻繁に切替える必要がなく、当分インスタンスが不要になるという場合に用いるのが適切だ。 なお、3つのいずれのやり方でも、MovieClipインスタンスのフレームアニメーションは止まらない。無駄な処理をしないためには、原則として再生ヘッドは止めておくべきたろう。
05 ArrayとVectorクラス ●Arrayクラス 第2に、配列エレメントは密(dense)すなわちインデックス0から連番で納められている方が、アクセスは速い[*9]。たとえば、つぎのようなArrayインスタンスを作成すると、インデックス0から2まではエレメントが密で、インデックス1000のエレメントは密ではない。
すると、インデックス0から2までのエレメントの方が、インデックス1000のエレメントより速くアクセスできる。
●Vectorクラス しかし、Vectorクラスはつぎのふたつの点で、Arrayクラスとは扱いが異なる。
Vectorクラスのコンストラクタは、つぎのようなシンタックスでインスタンスを生成する。 Vector.<データ型>(長さ:uint = 0, 長さの固定:Boolean=false) Vectorクラスを使うとエレメントにデータ型が指定されるため、アクセスが配列と比べて高速になる。Vectorインスタンスの生成とエレメントの値の追加、変更、取出しは、つぎのように行う。
エレメントのデータ型がひとつで、連番のインデックスに値を納めるときには、ArrayよりVectorクラスのインスタンスを使う方がよい。また、ActionScript 3.0に新たに備わるメソッドには、引数として複数の値をVectorインスタンスで渡す場合が増えるだろう[*10]。
06 数値の演算 こうした違いは、FlashコンテンツがFlash Playerとブラウザを介して処理を行っていることに起因すると考えられる。したがって、細かな差にかかずらうより、処理手順やそのロジックを重視した方がよい。 ●Mathクラスの数値演算
通常は、切捨てはMath.floor()メソッドを使う。しかし、数値を整数に変換するグローバル関数int()の方が、Math.floor()メソッドよりも処理は速い[*11]。 ●掛け算と割り算 n / 5 ただし、2の累乗による割り算はFlash Playerで最適化されているらしく、掛け算との差がほとんどなくなる。 もっともたとえば、つぎのような座標のイージング(イーズアウト)の処理では、減速率のパラメータは割り算にすると反比例の係数になり、演算値が双曲線を描いて変わる。掛け算であれば比例の直線的な変化なので、値の微調整がしやすい(図009)。
図009■比例と反比例のグラフ ●ビット演算 ビット単位の左シフト演算子<<は、左オペランドの整数(nNumber)を右オペランドの整数(n)の桁数左に繰上げる。2n(2のn乗)を掛け算したのと同じ結果になる。 nNumber << n ビット単位の右シフト演算子>>は、左オペランドの整数(nNumber)を右オペランドの整数(n)の桁数右に繰下げる。2n(2のn乗)で割り算したのと同じ結果になる。 nNumber >> n ビット単位の論理和演算子|は、ふたつのオペランドの対応する各ビット(2進数の各桁)の値の少なくとも一方が1であれば1を、そうでなければ0を返す(表003)。 表003■ビット単位の論理和演算子|の演算結果
たとえば、Array.sortOn()メソッドの第2引数にソートオプションとして指定する複数のArray定数は、|演算子でまとめる。配列my_arrayをフィールド名field_strで、数値の降順に並べ替えたいときは、つぎのようなステートメントになる。
Array定数は次表004のとおり、2進数で表したとき値1を取る桁が重ならないようにフラグとして定められている。したがって、複数の定数値をまとめる場合、加算+で演算しても同じ結果が得られる。けれど、ビット単位の演算子を使う方が一貫している[*12]。 表004■Array定数とその値
カラー値は、RGB各成分値を0からFまでの16進数ふた桁の256階調で指定し、計6桁で表す。16進法はひと桁が24(=16)だから、ビット演算では4桁になる。したがって、16進法のひと桁繰上げ/繰下げは、ビット単位で4桁シフトすればよい。16進数がふた桁(162 = 24×2 = 28)の256階調なら、ビット単位の8桁シフトになる(図010)。 図010■256進法(階調)のひと桁はビット単位の8桁になる すると、RGBの各256階調の値がint型の変数nR、nG、nBにそれぞれ入っているとすれば、RGGカラー値はつぎのようなビット演算で求めることができる。
●暗黙の型変換
[おまけ] セッションで紹介したFlash CS4 Professionalの[ヘルプ]については、F-site「Flash CS4のヘルプ」を参照してほしい。 作成者: 野中文雄 Copyright © 2001-2009 Fumio Nonaka. All rights reserved. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||