[AS3] 矢印キーでインスタンスを移動させる [Edit]

MovieClipインスタンスを矢印キーで上下左右に動かす例のご紹介です(図001)。ただし、少しひねりを加えて、キーを押し続けたときに入力が繰返される速さではなく、フレームレートで進むようにします。

図001■MovieClipインスタンスを矢印キーで上下左右に動かす
AS3_OptimizingPerformance_01_02_008.png

お題はFLASH-japanの「fpsに同期したmcの移動」で上がったものです。もっとも、この回答ではつくりを単純にするために、乱暴なスクリプトになっています。そこを少し整えて、簡単な説明を加えます。


01 ふたつの課題と繰返されるキー入力の扱い

まず、キー入力の基本的な扱いについては、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;
}

02 switch-caseステートメントでキー入力を切り分ける

初めの課題の押されたキーによる振分けは、条件判定によるのが定石でしょう。ここでは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引数に渡したリスナーがイベントに登録されていなくてもとくに問題は生じません。


03 配列によりキーコードを切り分ける

キーコードは正の整数で一意に定められています。重複しない整数はインデックスとして使うことができ、配列ととても相性がよいです。配列の基本的な扱い方とキーコードへの適用について、前出「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「条件分岐をポリモーフィズムに置換える」をご参照ください。

コメント

この記事にコメントを書く

記事に対するテクニカルな質問はご遠慮ください(利用規約)。

その他の記事