MovieClipインスタンスを矢印キーで上下左右に動かす例のご紹介です(図001)。ただし、少しひねりを加えて、キーを押し続けたときに入力が繰返される速さではなく、フレームレートで進むようにします。
図001■MovieClipインスタンスを矢印キーで上下左右に動かす
お題はFLASH-japanの「fpsに同期したmcの移動」で上がったものです。もっとも、この回答ではつくりを単純にするために、乱暴なスクリプトになっています。そこを少し整えて、簡単な説明を加えます。
まず、キー入力の基本的な扱いについては、gihyo.jp連載「ActionScript 3.0で始めるオブジェクト指向スクリプティング」第13回「キーボードによる操作」をお読みください。InteractiveObject.keyDownイベント(定数KeyboardEvent.KEY_DOWN)のリスナー関数が受取るKeyboardEventオブジェクトのKeyboardEvent.keyCodeプロパティで押されたキーのコードがわかります。そこでキーの振分けをどうするかが第1の課題です。
第2の課題は、矢印キーを押し続けたときの扱いです。InteractiveObject.keyDownイベントは、押している間繰返し生じます。しかし、初めに押したときフレームレートのアニメーションを開始し、キーを放したら止めるようにします。そのためには、繰返されるイベントは除けなければなりません(前掲FLASH-japanの回答ではこの処理を省いています)。
ふたつ目の課題から先にかたづけましょう。以下のスクリプトのように、初めのInteractiveObject.keyDownイベントで押したキーのコードを変数(nPressedKey)にとります。続くイベントではそのコードが変わらないかぎり、中身の処理は端折ります。InteractiveObject.keyUpイベント(定数KeyboardEvent.KEY_UP)が起きたら、変数は初期化します。
var nPressedKey:uint = 0; stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, xKeyUp); function xKeyDown(eventObject:KeyboardEvent):void { var nKeyCode:uint = eventObject.keyCode; if (nKeyCode != nPressedKey) { nPressedKey = nKeyCode; // 中身の処理 trace(nKeyCode); // 確認用 } } function xKeyUp(eventObject:KeyboardEvent):void { nPressedKey = 0; }
初めの課題の押されたキーによる振分けは、条件判定によるのが定石でしょう。ここではswitch-caseステートメントを使うと、スクリプトが見やすくなります。もちろん、ifステートメントでも差支えありません。switch-caseステートメントにより矢印キーの操作を切り分けるスクリプトについては、前出「ActionScript 3.0で始めるオブジェクト指向スクリプティング」第14回「キー操作とif以外の条件判定」で詳しく解説しています。このやり方にしたがって整えたのが、つぎのスクリプト001です。矢印キーで動かすMovieClipシンボルのフレームアクションとして加えます。
スクリプト001■矢印キーの操作をswitch-caseステートメントで切り分ける// MovieClip: 矢印キーで動かすMovieClipシンボル var nMove:Number = 0; var nPressedKey:uint = 0; stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, xKeyUp); function xKeyDown(eventObject:KeyboardEvent):void { var nKeyCode:uint = eventObject.keyCode; if (nKeyCode != nPressedKey) { xRemoveAllEventListeners(); switch (nKeyCode) { case Keyboard.LEFT : nPressedKey = nKeyCode; nMove = -1; addEventListener(Event.ENTER_FRAME, xMoveX); break; case Keyboard.RIGHT : nPressedKey = nKeyCode; nMove = 1; addEventListener(Event.ENTER_FRAME, xMoveX); break; case Keyboard.UP : nPressedKey = nKeyCode; nMove = -1; addEventListener(Event.ENTER_FRAME, xMoveY); break; case Keyboard.DOWN : nPressedKey = nKeyCode; nMove = 1; addEventListener(Event.ENTER_FRAME, xMoveY); break; } } } function xKeyUp(eventObject:KeyboardEvent):void { nPressedKey = 0; xRemoveAllEventListeners(); } function xMoveX(eventObject:Event):void { x += nMove; } function xMoveY(eventObject:Event):void { y += nMove; } function xRemoveAllEventListeners():void { removeEventListener(Event.ENTER_FRAME, xMoveX); removeEventListener(Event.ENTER_FRAME, xMoveY); }
[ムービープレビュー]を確かめると、上下左右の矢印キーをおしたとき、その方向にインスタンスがフレームレートで移動します。なお、EventDispatcher.removeEventListener()メソッドを呼出したとき(関数xRemoveAllEventListeners())、第2引数に渡したリスナーがイベントに登録されていなくてもとくに問題は生じません。
キーコードは正の整数で一意に定められています。重複しない整数はインデックスとして使うことができ、配列ととても相性がよいです。配列の基本的な扱い方とキーコードへの適用について、前出「ActionScript 3.0で始めるオブジェクト指向スクリプティング」第15回「配列を使ったキーコードとプロパティの扱い」で詳しく解説しました。このやり方で整えたのがつぎのスクリプト002です。
スクリプト002■矢印キーのコードを配列により切り分ける// MovieClip: 矢印キーで動かすMovieClipシンボル var nMove:Number = 0; var nPressedKey:uint = 0; var moveFunction:Function; var movements:Array = []; movements[Keyboard.LEFT] = [-1, xMoveX]; movements[Keyboard.RIGHT] = [1, xMoveX]; movements[Keyboard.UP] = [-1, xMoveY]; movements[Keyboard.DOWN] = [1, xMoveY]; stage.addEventListener(KeyboardEvent.KEY_DOWN, xKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP, xKeyUp); function xKeyDown(eventObject:KeyboardEvent):void { var nKeyCode:uint = eventObject.keyCode; if (nKeyCode != nPressedKey) { xRemoveAllEventListeners(); var movement:Array = movements[eventObject.keyCode]; if (movement) { nPressedKey = nKeyCode; nMove = movement[0]; moveFunction = movement[1]; addEventListener(Event.ENTER_FRAME, moveFunction); } } } function xKeyUp(eventObject:KeyboardEvent):void { nPressedKey = 0; xRemoveAllEventListeners(); } function xMoveX(eventObject:Event):void { x += nMove; } function xMoveY(eventObject:Event):void { y += nMove; } function xRemoveAllEventListeners():void { removeEventListener(Event.ENTER_FRAME, xMoveX); removeEventListener(Event.ENTER_FRAME, xMoveY); }
前出「配列を使ったキーコードとプロパティの扱い」で示したスクリプトと大きく異なるのは、配列にプロパティの文字列ではなく、関数(xMoveX()またはxMoveY())の参照を納めたことです。プロパティを直接いじるより、関数で扱う方が安全で応用範囲も広がります[*1]。さらに、配列をVectorオブジェクトに置換えると、扱いがより速くなります。詳しくは「キーボードのキー操作をVectorオブジェクトで扱う」をお読みください。
[*1] さらに汎用性を高めた考え方としては、FumioNonaka.com「条件分岐をポリモーフィズムに置換える」をご参照ください。