【pixi.js】キー入力処理を作って四角を動かしてみよう

javascript

pixi.js キー入力

こんにちは。継続の錬金術士なおキーヌです。

ブログ毎日更新は96日目になります。

今回はゲームをプレイしてもらうために必須なキー入力処理を覚えましょう。

ゲーム作り入門者向けのpixi.js講座は全4回になります。

この記事の内容
pixi.jsによるキー入力処理の実装
キー入力で四角を移動させたり止めたりする

まずは前回のコードを載せておきます。
ここから始めるという方は、htmlファイルを作成してコードをコピペしてください。

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>pixi.js v4 テスト</title>
    <style>
      * { margin:0; padding:0; }
    </style>
  </head>
  <body>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>
      <script>
        // pixi.jsのアプリケーションを作成
        const app = new PIXI.Application();

        // bodyにpixi.jsのview(ステージ)を追加する
        document.body.appendChild(app.view);

        // グラフィックスクラスのインスタンス「square」を作成
        const square = new PIXI.Graphics();

        // squareの大きさと座標を指定
        square.width = 100;
        square.height = 100;
        square.x = 50;
        square.y = 50;

        // 何もしないと透明なのでsquareを塗りつぶしで可視化する
        square.beginFill(0xff00ff);
        square.drawRect(0,0,100,100);
        square.endFill();

        // squareをステージに追加する
        app.stage.addChild(square);

        // ゲームループ関数を実行
        app.ticker.add(delta => this.gameloop(delta,square));

        // ゲームループ関数の中身(毎フレーム実行される)
        function gameloop(delta, square) {
          // switchによる条件分岐開始
          // Math.random() * 4 をすることで0~3の数値を取得することが出来る
          // このままだと小数点も含まれるので条件に一致しなくなるためMath.floorで小数点を切り捨てている
          switch(Math.floor( Math.random() * 4 )) {
            case 0:
              square.x += 10;
              break;
            case 1:
              square.x -= 10;
              break;
            case 2:
              square.y += 10;
              break;
            case 3:
              square.y -= 10;
              break;
          }
        }
      </script>
    </body>
  </html>
</html>

キー入力処理で四角を自分で動かす

pixi.js キー入力 移動

このままだと四角があらぶって画面外に行ってしまうのでキー操作で制御してみましょう。

今回変更する点は、お察しの通りswitch関数のところの変更です。

キー入力処理を作るときの考え方は、キーの入力された値によって条件を切り分ける。

ということですね。

しかしこのままではキー入力処理が受け付けていない状態なので
まずはキーを入力できるように処理を作っていきます。

キー入力のためにイベントリスナーを作成してループ関数を書き換える

これはpixi.jsの機能ではなくjavascriptとブラウザの機能になります。
イベントリスナーを登録してから、ループ関数の中身を変えてみましょう。

<script>
  // キー入力状態変数の定義
  keyFlag = 0;

  // pixi.jsのアプリケーションを作成
  const app = new PIXI.Application();
~~~省略~~~
  // イベントリスナー登録
  window.addEventListener("keydown", (event) => { this.downHandler(event) },false);
  window.addEventListener("keyup", (event) => { this.upHandler(event) },false);

  // downHandlerを定義
  function downHandler(event) {
    switch(event.key) {
      case 'ArrowRight':
        keyFlag = 1;
        break;
      case 'ArrowLeft':
        keyFlag = 2;
        break;
      case 'ArrowDown':
        keyFlag = 3;
        break;
      case 'ArrowUp':
        keyFlag = 4;
        break;
    }
  }

  // upHandlerを定義
  function upHandler(event) {
    keyFlag = 0;
  }


  // ゲームループ関数の中身(毎フレーム実行される)
  function gameloop(delta, square) {
    // switchによる条件分岐開始
    // Math.random() * 4 をすることで0~3の数値を取得することが出来る
    // このままだと小数点も含まれるので条件に一致しなくなるためMath.floorで小数点を切り捨てている
    switch(keyFlag) {
      case 1:
        square.x += 1;
        break;
      case 2:
        square.x -= 1;
        break;
      case 3:
        square.y += 1;
        break;
      case 4:
        square.y -= 1;
        break;
      default: 
        break;
    }
  }

少しやっていることは複雑に見えるかもしれませんが、至って簡単なことしかしていません。

上から見ていきましょう

キー入力の状態変数の定義

ソースコードの一番上にどのキーを押されたか保持をするための変数を作っています。

キーが入力されるたびに対応した数値が格納されるようになっています。

右が押されたら2を格納、左を押されたら2を格納という感じです。

イベントリスナーの定義

今回のメイン部分ともいえるイベントリスナーの定義です。
ブラウザが持っている機能なのでwindowという変数の中に入っているaddEventListener関数を呼び出しています。
その中の第一引数はキーイベントが何かを文字列で指定します。

キーが押されたらという場合は「keydown」と記述し、
キーが離されたら「keyup」と記述します。

今回は両方使いたいので2つのイベントリスナーを登録しています。

第二引数には、イベントが発生した場合(今回の場合はキーが押されたor離された場合)の実行したい関数を指定します。

ソースコードではアロー関数を使用していますが、現時点ではfunctionで記述しても問題ありません。

アロー関数についてはthisが固定されたりと色々メリットはあるのですが解説すると記事の方向性が
ズレまくってしまうので、今はこういう書き方をするんだなって覚えておくだけで大丈夫です。

問題はなぜここで実行したい関数ではなくアロー関数を用いて他の関数を呼び出しているかというと、
何を押されたかの判断をするためにeventオブジェクトを受け取って中身を見て条件分岐をしたいからです。

その為にアロー関数の引数にeventと設けてそれをdownHandler関数にわたしています。

downHandelrとupHandlerの定義

次はキーが押された時に呼び出されるdownHandlerと、
キーが離された時に呼び出されるupHandlerを定義しています。

先ほどのイベントリスナーから渡されたeventオブジェクトが持つkeyプロパティには、押されたキーの情報が格納されているので、
関数の中でswitchを用いて分岐すればどのキーを押されたかの情報を保持できます。

今回はkeyFlag変数に右は1、左は2、上は3、下は4と入るように設定してみました。

キーが離された時は、0が入るようにしています。

このキーが離された時に0を入れないと押した方向にずっと動いてしまうので、
動きを止めてあげる必要があったからです。

ゲームループの処理書き換え

keyFlag変数の数値に合わせてゲームループ内のswitchの条件も変えてしまいましょう。
条件式以外は特に変更がないので、ここまですべて変更出来たら実行してみましょう。

カーソルキーを押して紫の四角が方向通りに動いてくれれば完璧です。

次回はキー入力処理を流用して四角をジャンプさせてみましょう。

これでキー入力処理は一旦完成です。
次回は四角をジャンプさせる処理を作ってみましょう。

最後に今回の完成版コードを乗せておきます。
コピペで動かせますので、自分で打ち込んでエラーが出た場合は見比べてみてください。

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>pixi.js v4 テスト</title>
    <style>
      * { margin:0; padding:0; }
    </style>
  </head>
  <body>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.1/pixi.min.js"></script>
      <script>
  // フラグの定義
  keyFlag = 0;

// pixi.jsのアプリケーションを作成
        const app = new PIXI.Application();

        // bodyにpixi.jsのview(ステージ)を追加する
        document.body.appendChild(app.view);

        const square = new PIXI.Graphics();

        square.width = 100;
        square.height = 100;
        square.x = 50;
        square.y = 50;

        square.beginFill(0xff00ff);
        square.drawRect(0,0,100,100);
        square.endFill();

        app.stage.addChild(square);
        app.ticker.add(delta => this.gameloop(delta,square));

  // イベントリスナー登録
  window.addEventListener("keydown", (event) => { this.downHandler(event) },false);
  window.addEventListener("keyup", (event) => { this.upHandler(event) },false);

  // downHandlerを定義
  function downHandler(event) {
    switch(event.key) {
      case 'ArrowRight':
      keyFlag = 1;
      break;
      case 'ArrowLeft':
      keyFlag = 2;
      break;
      case 'ArrowDown':
      keyFlag = 3;
      break;
      case 'ArrowUp':
      keyFlag = 4;
      break;
    }
  }


  // upHandlerを定義
  function upHandler(event) {
    keyFlag = 0;
    console.log(keyFlag)
  }


  // ゲームループ関数の中身(毎フレーム実行される)
  function gameloop(delta, square) {
    // switchによる条件分岐開始
    // Math.random() * 4 をすることで0~3の数値を取得することが出来る
    // このままだと小数点も含まれるので条件に一致しなくなるためMath.floorで小数点を切り捨てている
    console.log(keyFlag)
    switch(keyFlag) {
      case 1:
        square.x += 10;
        break;
      case 2:
        square.x -= 10;
        break;
      case 3:
        square.y += 10;
        break;
      case 4:
        square.y -= 10;
        break;
      default:
        break;
    }
  }

      </script>
    </body>
  </html>
</html>

──思ったよりも1つのことをやるだけで結構記事が無くなってしまうため
ダラダラと続けるよりは区切った方が学ぶ方もわかりやすいと思うので、
今回はキー入力の処理と動かすことだけに絞ってみました。

1つの記事で色々なことをやってしまうと少し前にやったことを忘れてしまうのもありますし
私としても文章の密度が減ってしまうので、1つに集中したほうが理解しやすい記事になるんじゃないかなと思っています。

それでは。