ログイン中のQiita Team
ログイン中のチームがありません

Qiita Team にログイン
コミュニティ
OrganizationイベントアドベントカレンダーQiitadon (β)
サービス
Qiita JobsQiita ZineQiita Blog
JavaScript
ゲーム制作
6
どのような問題がありますか?
Organization

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

はじめに

その2ではテキスト表示を行いました。
今回はキー入力を行っていきたいと思います。

キー入力について

まずは簡単なサンプルを作成しました。
カーソルキー、スペースキー、エンターキーが入力可能になっています。


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

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 = "未入力";
}

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

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

キー入力修正版サンプル

上記の問題を対応したサンプルが以下になります。


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

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

修正版のソースコード

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アプリケーションでも使用することがあるので覚えておいて損はないと思います。

今回の内容でこういうのが作れるようになります

ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
ari-group
Biz&Tech&Creative 三位一体型でサービス企画、UIデザイン、アプリ開発からクラウド基盤や音声基盤の構築、BIやRPAなどのソリューション導入、各種保守運用までをワンストップで提供するITコンサルティングとクラウドインテグレーションをやっている会社です。渋谷、大阪、名古屋の国内3拠点体制で、FAQチャットボットなど自社サービスも展開しています。仲間を絶賛募集中です。

コメント

リンクをコピー
このコメントを報告

冗長かな、と感じる部分が多いように思いました。
例えば

function hexToRGB( hex )
{
  var rgb24 = hex;

  if( isNaN(hex) ){ // 数値型ではない
    if( hex.substring(0, 1) == "#" ){ // 先頭が#だったら、取り除く
      hex = hex.substring( 1, hex.length );
    }

    rgb24 = Number( "0x"+hex.toString(16) );  // 16進数へ変換
  }

  var r = rgb24 >> 16;
  var g = (rgb24 ^ (r << 16)) >> 8;
  var b = (rgb24 ^ (r << 16)) ^ (g << 8);
  return { r:r, g:g, b:b };
}

なども

function hexToRGB(hex) {
  const num = parseInt(hex.replace(/[^\da-f]/ig, ''), 16);
  return {r: num >> 16 & 0xff, g: num >> 8 & 0xff, b: num & 0xff};
}

こんな感じで十分かな、と思います。

0
(編集済み)
リンクをコピー
このコメントを報告

記事中2つ目のサンプルですが、canvasの使用は省略していますが、キー入力処理部分をこんな感じに書いてみました。

sample.html
<!DOCTYPE html>
<html lang='ja'>
<head>
<meta charset='utf-8'>
</head>
<body>
入力されているキー:<span class='key'>未入力</span><br>
スペースキーでカウントアップ:<span class='count'>0</span>
<script>
'use strict';

const keyList = {
  ArrowUp    : '',
  ArrowDown  : '',
  ArrowLeft  : '',
  ArrowRight : '',
  Enter      : 'エンターキー',
  Space      : 'スペースキー',
};

const status = {};
const elemKey = document.querySelector('span.key');
const elemCount = document.querySelector('span.count');

let countUpFlg = false;

document.addEventListener('keydown', e => {
  if(Object.keys(keyList).includes(e.code)) {
    status[e.code] = keyList[e.code];
    elemKey.textContent = Object.values(status).join(',');
    if(e.code === 'Space' && !countUpFlg) {
      elemCount.textContent++;
      countUpFlg = true;
    }
  }
});

document.addEventListener('keyup', e => {
  if(Object.keys(keyList).includes(e.code)) {
    delete status[e.code];
    const v = Object.values(status);
    elemKey.textContent = v.length ? v.join(',') : '未入力';
    if(e.code === 'Space' && countUpFlg) {
      countUpFlg = false;
    }
  }
});
</script>
</body>
</html>
0
リンクをコピー
このコメントを報告

アップされているコードを拝見したのですが、HTMLがHTML4時代の書き方が多いこと、JavaScriptの変数宣言がすべてvarである、比較に同値/非同値演算子ではなく等値/不等値演算子を使っている、非推奨プロパティであるKeyboardEvent.whichを使用しているなど、現代のコーディングとしては気になる点が多いように思います。

0
どのような問題がありますか?
あなたもコメントしてみませんか :)
ユーザー登録
すでにアカウントを持っている方はログイン
記事投稿イベント開催中
マイクロソフト認定資格を取得する際の学習方法や経験談、おすすめ学習リソースなどを紹介しよう!
~
6
どのような問題がありますか?
ユーザー登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
ユーザー登録ログイン
ストックするカテゴリー