Input設計とは?ループと状態に統合する入力管理の基本構造

input javascriptのアイキャッチ画像

これまでの流れ:

そして今回。

「ユーザーの操作を、どうやってゲーム側に伝えるのか?」

ここを設計します。

❌ よくある初心者パターン

window.addEventListener("keydown", (e) => {
  if (e.key === "ArrowRight") {
    player.x += 5;
  }
});

一見問題なさそうですが、これには大きな問題があります。

問題1:イベント発火回数に依存する

キーボードのリピート速度は環境依存。

問題2:Fixed Time Stepと相性が悪い

update() の中で時間制御しているのに、
イベント側で直接状態を変更してしまう。

問題3:設計がバラける

入力処理があちこちに散らばる。

✅ 正しい考え方

入力は「イベント」ではなく、

“入力状態(Input State)” を作る

1.入力は「記録する」だけ

①入力管理クラスを作る

class Input {
  constructor() {
    this.keys = {};
    
    window.addEventListener("keydown", (e) => {
      this.keys[e.key] = true;
    });

    window.addEventListener("keyup", (e) => {
      this.keys[e.key] = false;
    });
  }

  isDown(key) {
    return !!this.keys[key];
  }
}

②update内で参照する

class Player {
  constructor(input) {
    this.x = 100;
    this.speed = 200;
    this.input = input;
  }

  update(dt) {
    if (this.input.isDown("ArrowRight")) {
      this.x += this.speed * dt;
    }

    if (this.input.isDown("ArrowLeft")) {
      this.x -= this.speed * dt;
    }
  }
}

🔥 何が良いのか?

  • 入力とロジックが分離される
  • Fixed Time Stepと完全に整合する
  • フレームレートに依存しない
  • Scene切替にも強い

2.「イベント駆動」ではなく「ポーリング」

❌ イベント駆動

押された瞬間に処理する

✅ ポーリング

毎フレーム「今どうなっているか?」を確認する

ゲームループ設計ではポーリングが基本です。

マウスも同じ考え方

class Input {
  constructor(canvas) {
    this.mouse = { x: 0, y: 0, down: false };

    canvas.addEventListener("mousemove", (e) => {
      this.mouse.x = e.offsetX;
      this.mouse.y = e.offsetY;
    });

    canvas.addEventListener("mousedown", () => {
      this.mouse.down = true;
    });

    canvas.addEventListener("mouseup", () => {
      this.mouse.down = false;
    });
  }
}

3.設計レベルが1段上がる瞬間

Inputは「橋」です。

User → Input → Game State → Render

これがシリーズ後半の核になります。

4.実験:「イベント直接制御 vs 入力状態管理」比較デモ

実験内容

  • 左:イベントで直接 x += 5
  • 右:Inputクラス + dt制御

👀 観察ポイント

  • キーを押しっぱなしにする
  • PC負荷を上げる
  • フレームレートを落とす

👉 右側は常に一定速度で動く
👉 左側は環境依存で不安定

5.まとめ

Input設計とは

「イベントを状態に変換すること」

これが出来ると:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA