ActionScript 3.0で始めるオブジェクト指向スクリプティング

第54回 【特別編】配列の処理をVectorオブジェクトで最適化する

この記事を読むのに必要な時間:およそ 4 分

配列をVectorオブジェクトに置換える

第15回スクリプト2の配列をVectorオブジェクトで置換えようとしたとき,すぐにつまずくのがインデックスの数値だ。矢印キーのコードには,第13回表2(再掲)のとおり,37から40までの整数が割り振られている。ところが,01「Vectorクラスのおさらい」で確かめたとおり,⁠インデックスが連番になる」必要があった。

第13回表2 Keyboardクラスの矢印キーの定数(再掲)

定数キー
Keyboard.DOWN下矢印キー40
Keyboard.LEFT左矢印キー37
Keyboard.RIGHT右矢印キー39
Keyboard.UP上矢印キー38

この問題を解くのは,さほど難しくない。というのは,キーボードのキーの数はかぎられるからだ。すべてのキーコードのインデックスに,無効であることがわかる整数をエレメントとして入れておけばよい。Vector()コンストラクタの第1引数には,長さVector.lengthプロパティ)を定める整数が渡せる※1⁠。すると,基本的にベース型のデフォルト値が,その数だけVectorオブジェクトのエレメントに加えられる。

前掲第15回スクリプト2の配列は,エレメントに入れ子の配列を加えていた。したがって,置換えるVectorオブジェクトのベース型はArrayにする。また,長さは300もあれば十分だろう※2⁠。実は,書替えはたった1行で済む。

// var keys_array:Array = new Array();
var keys_array:Vector.<Array> = new Vector.<Array>(300);   // Vectorオブジェクトに置換え

もっとも,変数名に「_array」の文字がつくのは気になる。そこで,変数名も含めて前掲第15回スクリプト2を書替えたのが,つぎのスクリプト1だ。これで,処理の速さは条件判定のswitchステートメントを使った場合(第14回スクリプト2)にかなり近づく。

スクリプト1 操作するプロパティをVectorオブジェクトのキーコードのインデックスに定める

// MovieClip: キー操作で動かすインスタンス
var nMove:int = 1;
var nShiftMove:int = 10;
var keys:Vector.<Array> = new Vector.<Array>(300);
keys[Keyboard.LEFT] = ["x", -1];
keys[Keyboard.RIGHT] = ["x", 1];
keys[Keyboard.UP] = ["y", -1];
keys[Keyboard.DOWN] = ["y", 1];
stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown);
function xKeyDown(eventObject:KeyboardEvent):void {
  var nKeyCode:int = eventObject.keyCode;
  var bShiftKey:Boolean = eventObject.shiftKey;
  xMove(nKeyCode, bShiftKey);
}
function xMove(nKeyCode:int, bShiftKey:Boolean):void {
  var key:Array = keys[nKeyCode];
  if (key) {
    this[key[0]] += key[1] * xGetPixels(bShiftKey);
  }
}
function xGetPixels(bShiftKey:Boolean):int {
  var nPixels:int = bShiftKey ? nShiftMove : nMove;
  return nPixels;
}
※1)
さらに,Vector()コンストラクタの第2引数は,長さを固定するかどうかのブール(論理)値を定める。デフォルト値は固定しないfalseだ。
  • new Vector.<ベース型>(長さ, 長さの固定)
※2)
標準キーボードのキーコードの一覧は,ヘルプ[Adobe Flash ActionScript 2.0の学習] > [キーボードのキーとキーコードの値]に掲げられている。

Vectorオブジェクトの長さは予め定めた方が速い

Vectorオブジェクトをつくるとき,必要なエレメント数の上限が予めわかっているときは,コンストラクタの第1引数で長さを定めた方がよい。エレメントを加えるときの扱いが速くなるからだ。英語版ヘルプ([Optimizing Performance for the Flash Platform] > [ActionScript 3.0 performance] > [Vector class versus Array class])にはつぎのように説明されている(筆者訳※3⁠。

Vectorの大きさが前もって定められていないと,空きが足りなくなったときに増やされます。Vectorの大きさが増えるたびに,新たなメモリ領域が割当てられます。そのときのVectorの中身は,その新たなメモリ領域にコピーされます。追加の割当てとデータのコピーは,パフォーマンスを損なうことになります。

Vectorオブジェクトをつくると,含まれるエレメントの数ぴったりではなく,予め少し余裕をみてメモリが充てられる。さらにエレメントを加えて,空きが足りなくなると,割当てを増やす。だが,それは追加したエレメント分ではなく,オブジェクト全体(プラス余裕分)の大きさで,その新たな領域にすべてのエレメントがコピーされるというのだ。

マンションの建替えを想像すればよい。戸数が足りなくなったら,その部屋数を既存の建物につけ足すのではない。新たな土地を確保して,より大きなマンションを建て,全員が引越すのだ図2⁠。土地の確保と引越には手間ひまがかかる。初めから十分な戸数の大規模マンションを建てておけば,引越などしなくて済む。

図2 新たにメモリを確保してエレメントが全員引越す

図2 新たにメモリを確保してエレメントが全員引越す

上述の理由から,新たなメモリの確保とデータのコピーという負荷を避けるには,Vector()コンストラクタに予め必要なエレメント数を定めた方がよい。

特別編の次回は,大量の処理につきものの繰返し処理を採上げる。とくに,配列をforループでいかに速く扱うかが,おもなお題になるだろう。

※3)

日本語のヘルプ([モバイル] > [Flash Platformのパフォーマンスの最適化] > [ActionScript 3.0のパフォーマンス] > [VectorクラスとArrayクラス])にはつぎのように記述されている。しかし,意味がわかりにくいため,本文では英語版をもとにした。

Vectorのサイズが時間よりも先に指定されない場合,Vectorの容量が不足すると,サイズが増えます。Vectorのサイズが増えるたびに,メモリの新しいブロックが割り当てられます。Vectorの最新の内容がメモリの新しいブロックにコピーされます。データを余分に割り当てて複製することにより,パフォーマンスに影響があります。

今回解説した次のサンプルファイルがダウンロードできます。

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書