tag:crieit.net,2005:https://crieit.net/tags/%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%82%B2%E3%83%BC%E3%83%A0/feed 「ブラウザゲーム」の記事 - Crieit Crieitでタグ「ブラウザゲーム」に投稿された最近の記事 2022-08-18T12:13:07+09:00 https://crieit.net/tags/%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%82%B2%E3%83%BC%E3%83%A0/feed tag:crieit.net,2005:PublicArticle/17552 2021-08-01T21:54:06+09:00 2022-08-18T12:13:07+09:00 https://crieit.net/posts/022ab7e5fad6719e3b95c32ad8e6fb23 ブラウザゲームの操作入力を一括管理するインプットマネージャーを作る <p>ブラウザゲームを作るときにゲームを操作できるものがたくさんあります。キーボード、マウス、ゲームパッド、そしてスマホのタッチ入力。これらからの入力を一括して管理できればめちゃくちゃ楽で便利ですよね。</p> <p>というわけでこれらの操作入力を一括管理をしてくれる便利なinputManagerクラスを作りたいと思います。</p> <p>あ、一括管理と言いましたけどスマホやマウスのただのタッチ入力は関係ありません。これは個別で必要に応じて作ればいいです。まとめて管理するのはキーボード、ゲームパッド、そしてスマホのバーチャルキーパッドの入力です。</p> <p>けっこう長いプログラムになるので面倒ですが一回作れば今後のゲーム開発がクッソ楽になるので頑張ってつくりましょう(‘ω’)ノ</p> <p>ちなみに開発環境はpixi.js + Typescritptですが今回はpixi.jsは関係ないです。javascriptでもゲームパッド以外はできると思います(ゲームパッドはnpmで入れてるのでjsなら要自作。他はenchant.jsでも同じもの作ってました)。他の言語については全く分かりませんがどうやってるかってのは参考になるかなと思います(‘ω’)</p> <h2 id="ゲーム操作に必要な定数を作る"><a href="#%E3%82%B2%E3%83%BC%E3%83%A0%E6%93%8D%E4%BD%9C%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E5%AE%9A%E6%95%B0%E3%82%92%E4%BD%9C%E3%82%8B">ゲーム操作に必要な定数を作る</a></h2> <p>ではまず先に入力の判断に使う定数を作ります。</p> <h3 id="方向入力の定数"><a href="#%E6%96%B9%E5%90%91%E5%85%A5%E5%8A%9B%E3%81%AE%E5%AE%9A%E6%95%B0">方向入力の定数</a></h3> <p>方向入力の定数を作ります。方向入力は8方向で作ります。</p> <p>で、まず8方向のうちの4方向、上下左右を4桁の2進数で考えるようにします。0000が何も押されていない状態です。で<br /> - 0001 上<br /> - 0010 右<br /> - 0100 下<br /> - 1000 左</p> <p>と考えてください。こうすると上と右が押されると3になります。左上が押されると9になります。こんな感じで8方向の定数を作ると</p> <pre><code>public keyDirections = { UP: 1, UP_RIGHT: 3, RIGHT: 2, DOWN_RIGHT: 6, DOWN: 4, DOWN_LEFT: 12, LEFT: 8, UP_LEFT: 9, } </code></pre> <p>となります。</p> <p>キーボードではいくつも同時にキーが押せるため変な数字になることがありますが入力判定処理時にこの定数以外の場合は無視すればOKです。</p> <h3 id="ボタンの状態管理用定数"><a href="#%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AE%E7%8A%B6%E6%85%8B%E7%AE%A1%E7%90%86%E7%94%A8%E5%AE%9A%E6%95%B0">ボタンの状態管理用定数</a></h3> <p>キーボードやゲームパッドのボタンは単純に押した離しただけではなくて、正確にゲームでコントロールしようと思うと「今押した」「押しっぱなし」「今離した」「押してない」という4つの状態が必要になります。</p> <p>なのでその定数を作っておきます。</p> <pre><code>public keyStatus = { HOLD: 2, DOWN: 1, UNDOWN: 0, RELEASE: -1, } </code></pre> <h3 id="ボタンの状態管理用変数"><a href="#%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AE%E7%8A%B6%E6%85%8B%E7%AE%A1%E7%90%86%E7%94%A8%E5%A4%89%E6%95%B0">ボタンの状態管理用変数</a></h3> <p>次はボタンの状態を入れておく変数を作ります。</p> <p>で、この状態を管理する変数ですが1つのボタンについて2つ作ります。これはボタンが「今押した」のか「押されっぱなし」なのかという状態を知るために前の状態を残しておくためです。一つ前の状態が押されているかどうか分かれば今押された(離した)のかどうかが分かります。</p> <pre><code>public input = { //入力されたキーのチェック用 keys: { Up: false, Right: false, Down: false, Left: false, A: false, B: false, Start: false }, //一つ前のキーの状態管理用 keysPrev: { Up: false, Right: false, Down: false, Left: false, A: false, B: false, Start: false } } </code></pre> <p>私は方向入力以外はAボタン、Bボタン、スタートボタンしか作ってないですがもっと欲しい人は追加してください。</p> <h2 id="キーボード入力イベントを作る"><a href="#%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E5%85%A5%E5%8A%9B%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B">キーボード入力イベントを作る</a></h2> <p>キーボードの入力イベントを作ります。</p> <p>なんかkeyCodeが非推奨みたいですがそんなの気にしない(^^;)気になる方は修正してください。押されたキーをtrueに、離したらfalseにしてます。</p> <pre><code>document.addEventListener('keydown', (e) => { switch(e.keyCode){ case 87://w this.input.keys.Up = true; break; //以下同様に他のボタンも作る } }); document.addEventListener('keyup', (e) => { switch(e.keyCode){ case 87://w this.input.keys.Up = false; break; //以下同様に他のボタンも作る } }); </code></pre> <h2 id="キーの入力をチェックする関数"><a href="#%E3%82%AD%E3%83%BC%E3%81%AE%E5%85%A5%E5%8A%9B%E3%82%92%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0">キーの入力をチェックする関数</a></h2> <h3 id="入力方向を調べる関数"><a href="#%E5%85%A5%E5%8A%9B%E6%96%B9%E5%90%91%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B%E9%96%A2%E6%95%B0">入力方向を調べる関数</a></h3> <p>押されている方向キーの数字を合算して返します。単純に足してるだけです。</p> <pre><code> public checkDirection() { let direction = 0; if(this.input.keys.Up){ direction += this.keyDirections.UP; } if(this.input.keys.Right){ direction += this.keyDirections.RIGHT; } if(this.input.keys.Down){ direction += this.keyDirections.DOWN; } if(this.input.keys.Left){ direction += this.keyDirections.LEFT; } return direction; } </code></pre> <h3 id="入力状態の取得"><a href="#%E5%85%A5%E5%8A%9B%E7%8A%B6%E6%85%8B%E3%81%AE%E5%8F%96%E5%BE%97">入力状態の取得</a></h3> <p>現在のキーの状態を取得します。引数は状態管理用変数に使っているボタンの名前(UpとかAとかStart)を入れて使います。これで返ってくる値が現在のボタンの状態です。</p> <p>またこれを使うのは毎フレーム1回だけです。ここでkeyPrev(前回の状態)を書き換えているので2回以上使うとおかしくなります。必要な場合は戻り値を保存して使ってください。</p> <pre><code>public checkButton(key: string) { if(this.input.keys[key]){ if(this.input.keysPrev[key] == false){ this.input.keysPrev[key] = true; return this.keyStatus.DOWN;//押されたとき } return this.keyStatus.HOLD;//押しっぱなし }else{ if(this.input.keysPrev[key] == true){ this.input.keysPrev[key] = false; return this.keyStatus.RELEASE;//ボタンを離した時 } return this.keyStatus.UNDOWN;//押されていない } } </code></pre> <h3 id="上の2つの処理がミソ"><a href="#%E4%B8%8A%E3%81%AE2%E3%81%A4%E3%81%AE%E5%87%A6%E7%90%86%E3%81%8C%E3%83%9F%E3%82%BD">上の2つの処理がミソ</a></h3> <p>このinputManagerの一番のポイントはゲームの入力をチェックする際にキーボードだろうがゲームパッドだろうがバーチャルパッドだろうが上の2つの処理から入力をチェックできることです。これができるようにするためにボタンの状態管理用変数を作っているわけです。</p> <p>inputManagerの役目はゲームのプログラムを書くときに入力デバイスのことを考える必要がないようにすることです。</p> <h3 id="ゲームパッドの入力について"><a href="#%E3%82%B2%E3%83%BC%E3%83%A0%E3%83%91%E3%83%83%E3%83%89%E3%81%AE%E5%85%A5%E5%8A%9B%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">ゲームパッドの入力について</a></h3> <p>ゲームパッドの入力については先にこちらの記事を読んでください(‘ω’)ノ<br /> <a target="_blank" rel="nofollow noopener" href="https://techlog.wgc-cosmo.com/use-gamepad/">ブラウザゲームでもコントローラーで操作できるようにする!</a></p> <p>で、ゲームパッドの入力判定してるところで</p> <pre><code>if(this.gamepad.button('dpad down')){ this.input.keys.Down = true; }else{ this.input.keys.Down = false; } </code></pre> <p>て感じで状態管理用フラグを変えてやればOKです。楽勝だね(*‘∀‘)</p> <h3 id="バーチャルゲームパッドの入力について"><a href="#%E3%83%90%E3%83%BC%E3%83%81%E3%83%A3%E3%83%AB%E3%82%B2%E3%83%BC%E3%83%A0%E3%83%91%E3%83%83%E3%83%89%E3%81%AE%E5%85%A5%E5%8A%9B%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">バーチャルゲームパッドの入力について</a></h3> <p>バーチャルゲームパッドについてはこちらの記事を先に読んでください(‘ω’)ノ<br /> <a target="_blank" rel="nofollow noopener" href="https://inwans.com/how-to-make-vpad/">バーチャルパッドの作り方</a></p> <p>で、もうわかると思いますがこれも同様に入力判定してるところで状態管理用フラグを変えてやればOKです。</p> <pre><code>class Btn { constructor(key: string){ this.addEventListener("touchstart", () => { InputManager.input.keys[key] = true; }); this.addEventListener("touchend", () => { InputManager.input.keys[key] = false; }); } } </code></pre> <p>クラスの内容は省略してますがこんな感じです。</p> <h2 id="おしまい"><a href="#%E3%81%8A%E3%81%97%E3%81%BE%E3%81%84">おしまい</a></h2> <p>以上な感じで私はInputManagerというクラスを作って入力を管理しております。これで入力デバイスを意識することなくゲームを作っていくことができます。<br /> ちなみにこのInputManagerを使ってるゲームがこちらです(‘ω’)ノ<br /> <a target="_blank" rel="nofollow noopener" href="https://wgc-cosmo.com/game/toilet/">トイレへの道</a></p> いんわん