ブラウザゲームを作ってみよう(その3:キー入力)

#はじめに
[その2](https://qiita.com/noji505/items/b432236de1917ede0dc5)ではテキスト表示を行いました。
今回はキー入力を行っていきたいと思います。

#キー入力について
まずは簡単なサンプルを作成しました。
カーソルキー、スペースキー、エンターキーが入力可能になっています。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="bGrRYOw" data-user="noji505" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/bGrRYOw">
  Qiita13_sample01(キー入力)</a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

キー入力部分のソースコード抜粋

```javascript:main.js
function init(){
    window.document.onkeydown = onKeyPress;
    window.document.onkeyup = onKeyUp;
}

function onKeyPress( e )
{
	var keyCode = e.which;

	switch( keyCode ){
	case 38:	// 上キー
		keyInputStr = "↑キー";
		break;
	case 40:	// 下キー
		keyInputStr = "↓キー";
		break;
	case 37:	// 左キー
		keyInputStr = "←キー";
		break;
	case 39:	// 右キー
		keyInputStr = "→キー";
		break;
	case 32:	// スペースキー
		keyInputStr = "スペースキー";
		spaceCount++;
		break;
	case 13:	// エンターキー
		keyInputStr = "エンターキー";
		break;
	}
}
function onKeyUp( e )
{
	var keyCode = null;
	keyCode = e.which;
	keyInputStr = "未入力";
}
```

何らかのキーが入力されると、「<b>onKeyPress</b>」メソッドが実行され、キーが離されると「<b>onKeyUp</b>」メソッドが実行されます。

一見問題なく動いてそうですが、いくつか問題があります。
■左上や右下などの同時入力が出来ない
→斜め入力が出来ない
■スペースキーを押すと数字がカウントアップするのですが、押しっぱなしにするとどんどんカウントアップしてしまう
→押した瞬間だけカウントアップし、離して再度押すとカウントアップするようにしたい

#キー入力修正版サンプル
上記の問題を対応したサンプルが以下になります。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="OJjgZjm" data-user="noji505" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/OJjgZjm">
  Qiita13_sample02(キー入力)</a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

カーソルキーの左と上を同時に押すと、両方認識しているのが分かると思います。
あとスペースキーを一回押すごとにカウントアップするようになっています。

これらを使い分けると
・キャラクター・・押している間、移動し続ける
・メニュー画面・・一回押す度に開く、閉じるを繰り返す
といったことが実現出来ます。

修正版のソースコード

```javascript:main.js
function run(){
	keyInputStr = "";
	var isKeyInput = 0;

	if( (keyPress & KEY_UP) != 0 ){
		isKeyInput = 1;
		keyInputStr += "↑";
	}
	if( (keyPress & KEY_DOWN) != 0 ){
		isKeyInput = 1;
		keyInputStr += "↓";
	}
	if( (keyPress & KEY_LEFT) != 0 ){
		isKeyInput = 1;
		keyInputStr += "←";
	}
	if( (keyPress & KEY_RIGHT) != 0 ){
		isKeyInput = 1;
		keyInputStr += "→";
	}
	if( (keyPress & KEY_SPACE) != 0 ){
		isKeyInput = 1;
		keyInputStr += "スペース";
	}
	if( (keyPress & KEY_RETURN) != 0 ){
		isKeyInput = 1;
		keyInputStr += "エンター";
	}
	if( isKeyInput == 0 ){
		keyInputStr = "未入力";
	}
	
	// スペースキーカウントアップ
	if( keyTrg == KEY_SPACE ){
		spaceCount++;
	}

	drawText( "入力されているキー："+keyInputStr+"", 0, 0, '#000000', 16, TEXT_NONE );
	drawText( "スペースキーでカウントアップ："+spaceCount+"", 0, 20, '#000000', 16, TEXT_NONE );

	keyTrg = 0;
}
function onKeyPress( e )
{
	var keyCode = e.which;

	switch( keyCode ){
	case 38:	// 上キー
		if( (keyPress & KEY_UP) != 0 )		break;
		keyPress |= KEY_UP;
		keyTrg |= KEY_UP;
		break;

	case 40:	// 下キー
		if( (keyPress & KEY_DOWN) != 0 )	break;
		keyPress |= KEY_DOWN;
		keyTrg |= KEY_DOWN;
		break;

	case 37:	// 左キー
		if( (keyPress & KEY_LEFT) != 0 )	break;
		keyPress |= KEY_LEFT;
		keyTrg |= KEY_LEFT;
		break;

	case 39:	// 右キー
		if( (keyPress & KEY_RIGHT) != 0 )	break;
		keyPress |= KEY_RIGHT;
		keyTrg |= KEY_RIGHT;
		break;

	case 32:	// スペースキー
		if( (keyPress & KEY_SPACE) != 0 )	break;
		keyPress |= KEY_SPACE;
		keyTrg |= KEY_SPACE;
		break;

	case 13:	// エンターキー
		if( (keyPress & KEY_RETURN) != 0 )	break;
		keyPress |= KEY_RETURN;
		keyTrg |= KEY_RETURN;
		break;
	}
}
function onKeyUp( e )
{
	var keyCode = e.which;
	switch( keyCode ){
	case 38:	keyPress &= ~KEY_UP;		break;	// 上
	case 40:	keyPress &= ~KEY_DOWN;		break;	// 下
	case 37:	keyPress &= ~KEY_LEFT;		break;	// 左
	case 39:	keyPress &= ~KEY_RIGHT;		break;	// 右
	case 32:	keyPress &= ~KEY_SPACE;		break;	// スペースキー
	case 13:	keyPress &= ~KEY_RETURN;	break;	// エンターキー
	}
}
```

修正前はキー入力のメソッド内で入力されたキーの文字を設定(↑キーなど)していたのですが、修正後は押されたキーに応じてあらかじめ定義した定数のビットを立てるようにしています。
論理演算で処理することで、1つの変数で「左と上が押されている」というのが判定出来、同時押しが出来るようになります。

スペースキーのカウントアップについては、トリガ変数で判定しています。
以下のような処理を行っています。
1.スペースキーが入力される
2.トリガ変数にスペースキーの入力値がセットされる(押されたことになる)
3.スペースキーを押している間はトリガ変数に値をセットしない(押しっぱなし防止)
4.ループの最後でトリガ変数を初期化する(押したままでも強制的にスペースキーが離されたことになる)
5.スペースキーを離すと、再度1の入力を受け付ける

#マウス入力について
キー入力のサンプルと言いつつ、マウスの処理も入っています。
キー入力の方が直感的に操作が出来るので作りやすいのですが、マウスでも遊べるようにしているとスマートフォンでもほとんど同じコードで遊べるようになるメリットがあります。


#最後に
キー入力で動かせるようになるとゲームっぽくなりますね。
あとマウスの処理はWebアプリケーションでも使用することがあるので覚えておいて損はないと思います。

#今回の内容でこういうのが作れるようになります
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="GRvEdVM" data-user="noji505" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/GRvEdVM">
  Qiita13_sample03(オマケ)</a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>