マリオ風のアクションゲームの作り方① ブロックの上をジャンプして進む
2384 回閲覧されました
みなさんこんにちは、WEB制作のエンジニアのjonioです。
今回から数回に渡ってスーパーマリオみたいに左右に動かしたりジャンプしたり穴に落ちるJavaScript製のミニゲームの作り方の解説をします。
現在ゲームを作成中ですので作成が終わり次第記事の更新をします。
それでは解説します。
目次
今回作成する内容
今回実装する内容は下記になります。
- キーボードの右を押すとキャラが右に進む
- キーボードの左を押すとキャラが左に進む
- キーボードの上を押すとキャラがジャンプしてジャンプは一定の高さまでしかジャンプできない
- ブロックとブロックの間の隙間に行くと落ちる
デモ
デモ動画は↓です。
HTML
canvasでゲームを作るのですがcanvasを表示する場所(11行目)だけ記述しています。
id属性を指定していますがJavaScriptで取得します。
canvasの設定
canvasで表示する場所(HTMLの11行目)を取得します。
コードを↓にします。
canvasで表示する領域の指定をします。
コードを↓にします。
7行目の「.getContext(“2d”)」でxy平面でcanvasの内容を表示します。
8行目でcanvasで表示する内容の横幅を指定して9行目でcanvasで表示する内容の縦幅を指定しています。
キャラとフィールドの表示
キャラはこのサイトから取りました。
フィールドは私が作ったのですがデモ動画のスクショをフィールド画像に使うなどしてください。
まずはキャラを表示します。
コードを↓にします。
14行目は「window.addEventListener(“load”,関数);」で「load」はHTML・画像・<script></script>の読み込みが終わったら関数の読み込みをします。
この記事に説明があります。
16行目〜22行目がupdate関数の中身ですが17行目の「new Image();」で画像を生成しています。
そして18行目の「imageright.src」に表示したい画像(キャラ)のパス「”../images/boy1.png”」を代入することでキャラの画像を表示しています。
19行目のキャラの画像をcanvasに表示していますがコードの書き方は「〜.drawImage(画像名, 画面左上からキャラまでのx方向の位置, 画面左上からキャラまでのy方向の位置, キャラの横の長さ, キャラの縦の長さ)」です。
画面左上からキャラまでのx方向の位置をxと置き 画面左上からキャラまでのy方向の位置, キャラの横の長さをyと置いているのは後で位置を自由に変える事ができるようにするためです。
画像名は17行目の「imageright」です。
画面左上からキャラまでのx方向の位置・画面左上からキャラまでのy方向の位置がイメージしにくいと思いますが図にすると↓です。
21行目の「.requestAnimationFrame()」ですが一定間隔で画面を再描画するためにの記述です。
setInterval()でも一定間隔の時間で表示できますが「.requestAnimationFrame()」はブラウザに最適なタイミングで表示してくれます。
これで↓と表示されます。
今度はフィールドを表示します。
デモは3つ表示されていますがまずは1つ表示します。
コードを↓にします。
これで↓と表示されます。
次はフィールドを3つ作ります。
コードを↓にします。
フィールドを3つ使うために14行目〜18行目の様に1つ1つのフィールドを配列の要素として33行目〜35行目のfor文で使っています。
for文にofを使うのはこの記事に説明があります。
これで↓と表示されます。
次はキャラを左右に動かします。
キャラを左右に動かす
コードを↓にします。
24行目・30行目の「window.addEventListener」ですがブラウザの画面に対して認識させたいからwindowを使っています。
9行目に配列を置いていますがキーボードを押した時と離した時に使います。
キーボードを押してキャラを動かす流れは以下になります。
例えばキーボードの「→」を押した(24行目のkeydown)時に26行目から空の配列inputKeyの要素の最後に「→」に当たる(e.keyに対応する)キーコードの「ArrowRight」が入ります。(この時inputKey = [ ]はinputKey = [‘ArrowRight’]になります)
そして27行目より配列inputKeyのe.key+1番目(配列は0番目から始めるから+1になる)にtrueが入ります。
そして27行目の「inputKey[e.key]」に60行目の「inputKey[“ArrowRight”]」が対応して27行目のinputKey[e.key]はtrueなので60行目の「updatedX = x + 2」より右に動きます。
updatedXは41行目でxを使って置いていますが右に動くという事はxが動くので置いています。(updatedYは今の段階では使いませんが後で使うので置いています)
普通のゲームならキーボードの右を押している時だけ右に動かしたいですが今のままでは右のキーボードを1回押せば右に動き続けます。
それを防ぐために30行目〜33行目があります。
24行目のkeydownに対して30行目の「keyup」はキーボードを話した時です。
32行目のinputKey[e.key]をfalseにする事によってキーボードを話した時にキャラが動くのを止めます。
キャラを左に動かすのは62行目です。
これでキャラを一応動かすことはできますが問題があります。
キャラのブレをなくす
キャラを動かせばわかりますがブレた動きをします、↓を見てください。
キャラがブレた動きをしますがこれは例えばキャラを一回右に動かした時に動かす前のキャラが残ったままになっていて動かす前のキャラと動かした後のキャラの2つが表示されているからブレたような動きになります。
これを解消するためにコードを↓にします。
37行目を追加していますが「.clearRect()」でキャラを動かした時に前の情報を消すことができます。
「.clearRect()」のコードの書き方は「.clearRect(画面左上からキャラまでのx方向の位置, 画面左上からキャラまでのy方向の位置, 適用される横幅, 適用される縦幅)」です。
次はキャラをジャンプさせます。
キャラのジャンプ
キャラを左右に動かすのはx座標を増やすか減らすかなので単純ですがジャンプは少し難しいです。
いきなりジャンプのやり方を説明するのではなくまずは速度について説明します。
速度って何?
車を運転する時・バイクを運転する時に時速40kmを出すとか見かけますがどういう意味でしょう。
簡単な言い方をすると時速40km(40km/h)は1時間に40km進むことができるという意味です。
秒速100mなら1秒で100m進むことができるという意味です。
だから速度は一定時間にどれだけ進むことができるという意味になります。(本当は向きも考えないといけないのですが必要ないので触れません)
これを踏まえた上でキャラのジャンプのやり方について説明します。
ジャンプの考え方
ジャンプは上に動きますが上方向の位置を増やせばいいという訳にはいきません。
理由はあなたがジャンプする時をイメージして欲しいのですがジャンプした時にずーっと上に上がり続けず絶対に地面に落ちますよね。
これは重力加速度(上に上がるのを邪魔するもの、凄く重たい物のイメージです)という物が働くからです。
上方向の位置を変える時に速度を使いますが速度は位置がどれだけ変わるかでした。
ジャンプすると上に上がりますが速度に重力加速度が加わるので速度は次第に減ってどこかで0になります(0になった時が一番上に上がった時です)。
そして重力加速度で下に落ちていきます。
gですが一定の値だと上に上がる時落ちる時の動きが極端になるので緩やかに動く様にします。
一定の高さまでしかジャンプできなくするのをいきなりやる分かりにくいと思うので今の段階ではキーボードの↑を押し続ければずっと上に上がりつづけるのを説明します。
コードを↓にします。
ジャンプした時のフラグを17行目で設定していますがフラグがtrueの時にできることを後で色々と追加するためです。
重力加速度に当たるのが66行目でジャンプの動きを緩やかにするのが71行目です。
これで↓になりますがジャンプが終わって地面に着地せず下に落ちます。
ジャンプが終わって地面に着地するための記述をします。
ジャンプが終わって地面に着地する
コードを↓にします。
67行目を追加していますがこれはジャンプして高さが上がって戻ってキャラの高さが300を超えたらキャラの高さが300になるという意味です。
キャラの高さを300にしているのはフィールドの高さが300だからその上に乗る様にするためです。
次はキャラのジャンプを一定の高さまでしかできないようにします。
一定の高さまでジャンプ
コードを↓にします。
71行目〜73行目を追加していますがジャンプして高さが200を超えた瞬間に高さを200にしてジャンプできないように見せています。
今のままではジャンプしている時にキーボードの↑を押したままにすると↓の様に空中移動ができます。
ジャンプ中にジャンプできなくするのは他の回で説明します。
次は今回の最後ですがブロックとブロックの間に行ったらキャラが落ちる処理です。
ブロックとブロックの間に行ったら下に落ちる
考え方から説明します。
フィールドの上側の高さは300です。
ジャンプした時にフィールドの下に落ちないための記述は67行目の「if (updatedY > 300) updatedY = 300;」でしたがここを変えます。
いきなりジャンプした時を考えると説明しにくいのでまずは下に落ちない説明からします。
下に落ちないのはフィールドの上に乗っている時です。
コードを↓にします。
フィールドの上は高さ300より小さくてブロックとブロックの間の穴の部分は高さ300より大きいです。