操作に応じてプレイヤーキャラクターを動かすプログラミング【絵が動くゲームを作ってみよう】
2020/05/17

緊急事態宣言が一部で解除されましたが、東京近郊はまだまだですね。 その中で動画を見る機会も増えて、 最近はアマゾンPrimeビデオで「ようこそ実力至上主義の教室へ」を見てプチハマり、Kindleで原作を読み漁り中です。 似た方向として「魔法科高校の劣等生」は以前から大好きなのですが、頭脳戦をしつつ最終的に主人公が無双するのが好きなんだと思います。 「賭ケグルイ」も同様かな。 あっ、この説明が違ったらスミマセン!個人の感想です!
さてさて今回は、 絵が動くゲームで最も重要とも言える処理、プレイヤーキャラクターを動かすプログラミングの解説を行います。
絵が動くゲームの完成形はこの記事で公開していますので、参考にしてください。

プログラミングブログ記事一覧
[PR]
ボールは勝手に動くようにしておきました
まず最初にゲームスタートボタンを押してみてください。 何も手を加えていないときの、本記事で用意されているプログラムの挙動を確認してみましょう。
プレイヤーキャラクターは超スーパーヒーローな英雄の絵を用意しました。 大事なことだから二回ずつ。(冗談ですヨ!)
プレイヤーキャラクターは真ん中から動きませんが、「ゲームスタート」を押して、ボールが動き出せば成功です。
プレイヤーを動かす関数
では早速、以下を実装してみましょう。 プレイヤーを動かす関数 movePlayer() です。
function movePlayer() { let hfD = loUI.getVecStep(); g.cfPlayerPos.fX += hfD.fX; g.cfPlayerPos.fY += hfD.fY; }
【実装】ボタンを押下して、「ゲームスタート」を押してみてください。 ボールが初期位置に戻って移動を再開すればまずはOKです。
操作は方法は色々と
そして、プレイヤーキャラクターを動かすような操作をしてみてください。
本記事で有効な操作は、ゲーム画面に見立てたグレーの部分でのスワイプ、マイスのドラッグ、 キーボードの[←][↑][↓][→]または[W][A][S][D]、およびゲームパッドの左ステックです。
これでプレイヤーが動けば成功です!
loUI.getVecStep() は操作方向を返す
loUI.getVecStep() は、操作の方向を返す、当ブログで独自実装した関数です。
let hfD = loUI.getVecStep();
この式により、 ( hfD.fX , hfD.fY ) が、操作している方向になります。
+=は変数に足す
「+=」(プラスイコール)は、「変数+=値;」の形式で、変数に値を足す、加算するというものです。 変数はプログラミング用語で、値を入れておくための場所です。
g.cfPlayerPos はプレイヤーキャラクターの座標
変数 ( g.cfPlayerPos.fX , g.cfPlayerPos.fY ) はプレイヤーキャラクターの座標が入っています。
以下の式で X座標を、操作方向ぶんだけ加えています。 これは、横に動く操作です。
g.cfPlayerPos.fX += hfD.fX;
hfD.fX は、左方向ならマイナス、右方向ならプラスの値が入っています。 つまりこの式で、左右両方に動くすぐれものです。
そして以下でY座標も動かしています。
g.cfPlayerPos.fY += hfD.fY;
スクリーン座標は、左上が ( 0 , 0 ) です。 右下は環境にもよりますが ( 319 , 179 ) です。
つまり、数学の一般的な座標系と異なり、上の方が Y の値が小さいので注意が必要です。 hfD.fY は、上に動く操作の場合にマイナス、下に動く操作はプラスで入っています。
[PR]
はみ出ないように
このプログラムには、まだ問題がありますが、発見できましたでしょうか。 実は、プレイヤーキャラクターが勢い余って、ゲームスクリーン外にはみ出てしまいます。
これを防ぐために、関数に以下を加えましょう。 【実装】ボタンを押して「ゲームスタート」してみてください。
g.cfPlayerPos.fX = loMath.normalizeMinMax( g.cfPlayerPos.fX , 40.0 , 296.0 ); g.cfPlayerPos.fY = loMath.normalizeMinMax( g.cfPlayerPos.fY , 28.0 , 152.0 );
どうでしょうか。端で止まるようになれば成功です!
loMath.normalizeMinMax()は最小と最大の間にする関数
loMath.normalizeMinMax()は最小と最大の間にする、当ブログで独自実装した関数です。 中身は以下になっています。
return Math.min( Math.max( fValue , fMin ) , fMax );
Math.min() は引数の小さい方、Math.max() は大きい方を返します。 つまり元の行は、独自実装の関数を使わずに、以下のように書けます。
g.cfPlayerPos.fX = Math.min( Math.max( g.cfPlayerPos.fX , 40.0 ) , 296.0 ); g.cfPlayerPos.fY = Math.min( Math.max( g.cfPlayerPos.fY , 28.0 ) , 152.0 );
スッキリしていますし、これでも問題ないのですが、min と max の関係がややこしいので、 独自実装の関数を追加しました。
このあたりは、ややこしいと感じれば別関数にする、くらいで良いと思います。
左上は(0,0)…じゃない?
スクリーンは左上の座標が (0,0) です。 しかしプログラムで指定している最小値は ( 40.0 , 28.0 ) です。
これは、 g.cfPlayerPos が示す座標を、プレイヤーキャラクターの見た目上の中心位置、としているからです。 その方が、当たり判定のプログラミングがしやすいです。
速度調整
これで、本記事の目的は達成しているのですが、微調整します。 現状は移動速度が早いと感じるので、少し遅くします。
実装としては、プレイヤーキャラクター座標に加算する2行を以下に変更します。 【実装】から「ゲームスタート」で、ぜひお試しください。
g.cfPlayerPos.fX += hfD.fX * 0.25; g.cfPlayerPos.fY += hfD.fY * 0.25;
作り込む!
この速度調整のような、ゲームバランスに影響するところは、可能な限り調整します。
ゲーム開発では、遅延してしまうと、調整の時間が削られてしまうことが少なくありません。 この調整が、ゲームの面白さに直結するところですので、 きちんとスケジュール通り進行させて、十分な調整等の作り込みを行い、リリースしたいものです。
[PR]
まとめ
本記事では、操作の情報を受けて、プレイヤーキャラクターを動かすプログラミングを解説しました。
ボールとプレイヤーキャラクターがぶつかっても何も起きませんが、 これだけでも結構
参考として、完成した関数全体を以下に記します。
function movePlayer() { let hfD = loUI.getVecStep(); g.cfPlayerPos.fX += hfD.fX * 0.5; g.cfPlayerPos.fY += hfD.fY * 0.5; g.cfPlayerPos.fX = loMath.normalizeMinMax( g.cfPlayerPos.fX , 40.0 , 296.0 ); g.cfPlayerPos.fY = loMath.normalizeMinMax( g.cfPlayerPos.fY , 28.0 , 152.0 ); }
また、本記事で使用している操作情報を取得するプログラムは、この記事で解説していますので、併せてご覧ください。
補足
- 今回使用しているプログラミング言語はWeb業界で一般的に使われる「JavaScript」です。
- ゲームパッドの入力は上下と左右が逆になっている可能性がありますが、そのカスタマイズは今回は未対応です。
- 本記事に記載のプログラムソースコードは、悪意のない範囲で自由に使用・改変していただいて問題ありません。ただし、ご自身の判断と責任でお願いします。
- (本記事公開後)本記事公開後に公開された記事へのリンクを追加しております。
- (本記事公開後)初期に提示していたプログラム記述ギミックを2025年5月にセキュリティー上の都合で閉じました。
- (本記事公開後)本記事の「実装」方式を変更しました。最終形において個別に処理をフラグ制御する形にしています。
- (本記事公開後)「まとめ」セクションの内容を調整しました。
- (本記事公開後)実装方式変更後さらに変数名の先頭xyfをcfとhfに変更しました。
カテゴリー:絵が動くゲームを作ってみよう,プレイヤー操作で動かす
[PR]