ゲームを作るとき取得できると便利かもしれないキー入力状況情報パターン

まえがき

キーボードを使うゲームは、当然キー入力の状況を受け取らないといけません。
どのキーが押されているか、押されていないか等。


Aキーが押されているか、押されていないかだけでなく、
もうちょっといろんなパターンでのキー入力状況を簡単に取得できるようにしておくと、
いちいちaddEventLisならなくて良いので便利です。

パターン1 - 押されているか、押されていないか

一番スタンダードなキー入力の情報です。
Aキーを押しているならtrue、押されていないならfalseを取得できます。

package 
{
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	
	/**
	 * キー状態
	 */
	public class KeyState extends Sprite
	{
		private var _aKey:Boolean;     // Aキー
		
		/** Aキー */
		public function get aKey():Boolean { return _aKey; }
		
		/**
		 * コンストラクタ
		 */
		public function KeyState() 
		{
			_aKey = false;
			
			addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
		}
		
		/**
		 * キーダウンイベント処理
		 * 
		 * @param event イベント
		 */
		private function onKeyDown(event:KeyboardEvent):void
		{
			switch (event.keyCode)
			{
				case 90:
					_aKey = true;
					break;
				default:
					break;
			}
		}
		
		/**
		 * キーアップイベント処理
		 * 
		 * @param event イベント
		 */
		private function onKeyUp(event:KeyboardEvent):void
		{
			switch (event.keyCode)
			{
				case 90:
					_aKey    = false;
					break;
				default:
					break;
			}
		}
	}
}

パターン2 - KEY_DOWNイベントっぽく

メニューをキーボードで操作して、項目を選択するような場合、
パターン1だと目的の項目へ選択カーソルをやるのに苦労します。
例えば↓キーを押した場合、わずかに長押ししただけでカーソルは下へガーっと行きすぎてしまったり。
通常こういう場合はKEY_DOWNイベントをaddEventLisなるものですが、
いちいちイベントイベントするのが面倒なので、
変数を参照するだけでこのキー入力状況を取得できるようにしようと思います。

package 
{
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	
	/**
	 * キー状態
	 */
	public class KeyState extends Sprite
	{
		private var _sysAKey:Boolean;  // システム用Aキー
		
		/** システム用Aキー */
		public function get sysAKey():Boolean { return _sysAKey; }
		
		/**
		 * コンストラクタ
		 */
		public function KeyState() 
		{
			_sysAKey = false;
			
			addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
		}
		
		/**
		 * システム用キー初期化
		 *  全体処理の最後で実行する
		 */
		public function initSystemKey():void
		{
			_sysAKey = false;
		}
		
		/**
		 * キーダウンイベント処理
		 * 
		 * @param event イベント
		 */
		private function onKeyDown(event:KeyboardEvent):void
		{
			switch (event.keyCode)
			{
				case 90:
					_sysAKey = true;
					break;
				default:
					break;
			}
		}
		
		/**
		 * キーアップイベント処理
		 * 
		 * @param event イベント
		 */
		private function onKeyUp(event:KeyboardEvent):void
		{
			switch (event.keyCode)
			{
				case 90:
					_sysAKey = false;
					break;
				default:
					break;
			}
		}
	}
}

initSystemKeyメソッドを処理の最後に呼び出すようにすれば、
ほぼKEY_DOWNイベントっぽいキー入力状況を取得できます。

private var _keyState:KeyState; // キー状態

/**
 * エンターフレームイベント処理
 * 
 * @param event イベント
 */
private function onEnterFrame(event:Event):void
{
	exec(); // メインの処理
	
	_keyState.initSystemKey(); // 処理の最後に実行
}

パターン1との違いは以下のような感じ。

パターン1  パターン2  キー状況
true       true       ←Aキー押す(以下押しっぱなし)
true       false
true       false
true       false
true       false
true       true
true       true
false      false      ←Aキー離す
false      false
false      false
false      false
false      false
false      false

厳密にキー入力状況を取得したい場合は当然KEY_DOWNイベントを使うしかないですが、
そうでない場合は楽じゃないかと。

パターン3 - キー押しっぱなし状況

Aキーを2フレーム以上押しっぱなしにしている場合true、そうでない場合falseを取得します。


どこで使うかというと、例えばアクションゲームの場合。
ジャンプを↑キーでする場合、押しっぱなしの判定をしなければ↑キーを押しっぱなしにすることで、
地上に降りるたびに自動的にジャンプしてしまいます。
その場その場で「↑キーを離さなかったならジャンプしない」という処理を入れるのは、結構しんどいです。(相当しんどい)
ジャンプだけでなく、攻撃動作しかり、使いどころはたくさんあります。


以下のソースのKeyStateクラスはパターン1のものです。
以下のクラスはキー入力の状況ではなく、ゲーム内の各物体が持っている操作用のキー情報です。
Aキーを押したとき、KeyStateクラスを介してこのクラス内の攻撃キー変数にtrue,falseを設定することで、
その物体の攻撃キーを押した場合のふるまい等をさせます。

package 
{
	/**
	 * オブジェクトのキー状態
	 */
	public class ObjectKeyState 
	{
		private var _attackKey:Boolean;         // 攻撃キー
		private var _attackKeyKeepFlg:Boolean;  // 攻撃キー押しっぱなしならtrue
		
		/** 攻撃キー */
		public function get attackKey():Boolean { return _attackKey; }
		/** 攻撃キー押しっぱなしフラグ */
		public function get attackKeyKeepFlg():Boolean { return _attackKeyKeepFlg; }
		
		/**
		 * コンストラクタ
		 */
		public function ObjectKeyState() 
		{
			_attackKey        = false;
			_attackKeyKeepFlg = false;
		}
		
		/**
		 * キー状態設定
		 * 
		 * @param keyState キー状況
		 */
		public function setKeyState(keyState:KeyState):void
		{
			// 押しっぱなし状態判定
			if (_attackKey && keyState.attackKey)
			{
				_attackKeyKeepFlg = true;
			}
			else
			{
				_attackKeyKeepFlg = false;
			}
			
			// キー状態設定
			_attackKey = keyState.attackKey;
		}
	}
}

例えば攻撃キーを押した場合攻撃するという処理をする場合

private var _state:ObjectKeyState;

private function exec():void
{
	if (_state.attackKey && !_state.attackKeyKeepFlg)
	{
		// 攻撃処理
	}
}

とすることで、攻撃キー押しっぱなしの場合攻撃処理が実行されないようにできます。

あとがき

これでいちいちイベントイベントさせなくても、
とりあえず全部ENTER_FRAMEの処理内で解決できそうですね!