【プチコン講座】グリッド移動の衝突判定について考えてみよう
こんにちは。継続の錬金術士なおキーヌです。
ブログ毎日更新は135日目になります。
前回「【プチコン講座】プレイヤーをRPGぽく操作してみよう:グリッド移動編」でRPGぽくグリッド移動するところまでやりました。
コードを毎回書いていては疲れてしまうので、今回は箸休めとして次回にやるグリッド移動の衝突判定について少しかんがえてみましょう。
ドット移動の時はプチコンが用意してくれているスプライト用の衝突判定を使えば楽なのですが、
グリッド移動の時はスプライト同士がぶつかるという判定は無駄な処理になるので使用しません。
なのでグリッドの当たり判定は自分で実装する必要があります。
といっても、複雑な計算式を使う必要性はありません。
自分もしくは衝突判定を取りたいキャラクターのX座標とY座標さえ分かれば後は簡単な計算をするだけで
マップのどこにいるのか分かります。
それではプチコンでRPG作り第7回目を始めましょう。
- グリッド移動の衝突判定の方法とは
- マップの正体はただの数値配列
- プレイヤーはマップ配列の添え字何番目にいるか求めてみよう
- 左右に移動出来るかどうかは1を足すか引くかすれば調べられる
- 上下に移動できるかどうかは横幅分足すか引くかすれば調べられる
グリッド移動の衝突判定の方法とは
結論から言っておくと、マップ配列をもとに現在居る位置から±1か±横幅をすれば進む方向に何があるのかわかります。
いきなりこんなこと言われても何が何だかわからない……な状態ですね。
しかしグリッド移動の判定は1度慣れてしまえばスプライト同士で行う衝突判定よりも簡単です。
そのためにはマップデータの構造を頭に叩き込んでおかないとよくわからなくなってきます。
といってもそんなに複雑なものではないので安心してください。
Excelとかエクセル互換等の表計算ソフトがあればわかりやすいかもしれませんね。
パソコンがない人は方眼紙にマップを書いてみるのも楽しいかもしれません。
グリッド移動の衝突判定をするには
先ほども言ったように、移動を開始する前に進む先にある数値を見て条件を分岐させます。
例えば右キーを押したとき以下のような処理の流れになります。
- 1.右キーを押す
- 2.右の数値を調べる
- 3.数値が0だった場合
- 4.0は壁なので進めないのでキャラクターを動かさない
- 5.0ではなく1だった場合
- 6.道なので進めるため移動中フラグをONにする
- 7.移動先を通れない数値に変更しておく(移動中に他のキャラがそこにいけないようにするため)
後は移動が完了したら移動中フラグをOFFにしてキー入力を待つ。の繰り返しですね。
補足:「移動先を通れない数値に変更しておく」の注意点
補足しておくと、移動先の数値を変更してしまうとマップデータを書き換えることになります。
実際のマップ表示に使っているデータを変えるのではなく、マップと同じ形の衝突判定専用のレイヤーを利用します。
プチコンのバックグラウンドは4つのレイヤーがありましたね。
地面をレイヤー0にして木などの障害物をレイヤー1にして2と3は何も置いていません。
なので2と3は使用していないのでどちらかを衝突判定のレイヤーにつかって、
もう片方はイベント情報用のレイヤーとしておいておくといいでしょう。
もしBGレイヤーを全部使うようなゲームを作る場合は、自分でマップサイズと同じ配列をつくるといいです。
マップサイズはマップデータから取り出しているので横x縦の要素を持つ配列を作ればいいですね。
マップの正体はただの数値配列
マップエディタでマップを作ってDATファイルに保存したと思います。
DATファイルは普通では開けないのですが、プログラムを通すと簡単に開けます。
では、DATファイルには何が入っているのか見てみましょう。
正体をネタバレするとカンマ区切りの数字の羅列なのですが、
全部書くとすさまじく長くなるので、簡略化した書き方をします。
仮に「横10」、「縦10」のマップを作ったとします。
するとDATファイルの中身は以下のようになります。
1010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
結果、1次元配列なので中身は↑のような形になります。
これだけだと0がならんでわけがわからないですね。
改行を入れて見やすくしてみましょう。
1010,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0
どうでしょうか?これでもまだわかりづらいかもしれません。
それでは以下のようにすればどうでしょうか?
1010,
0,0,0,0,0,0,0,0,0,0,
0,1,0,1,1,1,1,1,9,0,
0,1,0,1,1,0,0,0,0,0,
0,1,0,1,1,0,0,9,0,0,
0,1,0,1,1,0,0,1,0,0,
0,1,0,1,1,1,1,1,1,0,
0,1,0,1,1,1,0,1,1,0,
0,1,0,0,0,0,0,1,1,0,
0,1,1,1,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,0,0
これで少しは見やすくなったのではないでしょうか?
0が壁
1が道
9が宝箱
とすればもうRPGのマップぽくみえてきたでしょう?
……冗談ではなく、実はこれがゲームのマップになるのです。
マップデータをどう扱うのか
このマップデータをどう扱うかが、プログラミングの腕の見せ所です。
まず一番最初に「1010」とあるところを注目してください。
プチコンRPG作成講座を1から見てくださっている方はもうわかりますね。
そう、横幅と縦幅の数値です。
マップデータを読み込んだ時に配列0個目の要素をSHIFT命令を使って配列の先頭の値を取り出しましたね。
実際には1010ではなく、16bitにしたちょっと複雑な数値なのですが今はわかりやすいようにしています。
なので実際にはAND演算やビットシフト等を行ったと思います。
そして横幅と縦幅の情報を取得出来たら、0個目の配列は取り出したので配列から削除されます。
残ったのは以下のようなマップのデータのみです。
0,0,0,0,0,0,0,0,0,0,
0,1,0,1,1,1,1,1,9,0,
0,1,0,1,1,0,0,0,0,0,
0,1,0,1,1,0,0,9,0,0,
0,1,0,1,1,0,0,1,0,0,
0,1,0,1,1,1,1,1,1,0,
0,1,0,1,1,1,0,1,1,0,
0,1,0,0,0,0,0,1,1,0,
0,1,1,1,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,0,0
DATファイルの中身はこの10×10が4倍あると思っていてください。
今はこのように見やすい形にしていますが、実際には最初に書いたように横にずらーっと並んでいる感じです。
これをどうやってマップ表示するのかというと、最初の方で作ったマップ表示関数が答えです。
忘れた方の為にもう一度言っておくと
10×10のマップの場合はX座標のカウントが0~9までマップを左から右に描写したら、
Y座標のカウントを1増加させると改行されてまた一番左から描写していくのを繰り返します。
プレイヤーはマップ配列の添え字何番目にいるか求めてみよう
衝突判定の方法もマップデータの中身もわかっていただけたと思うので、
衝突判定をするためにまずは自分の座標をもとに配列のどこに自分がいるのか調べましょう。
先に答えを書いておくと、プレイヤースプライト変数の0番目のX座標と1番目のY座標を掛けた数値が座標になります。
0に何を掛けても0になってしまうので、Y座標が0の時だけはX座標数値そのままでOKですね。
ここだけ気を付けてください。
条件分岐でY座標が0の時は~とそれ以外の時は~で分ければOKです。
この計算式を1つの関数にしておけばプレイヤーだけはなく敵や宝箱などのイベントの座標も調べられますね。
こういった使いまわせる処理は関数にしておきましょう。
左右に移動出来るかどうかは1を足すか引くかすれば調べられる
グリッド衝突判定については文字だけだと全て説明してしまったようなものですが、
最後におさらいをしておきましょう。
まずはX軸だけを見てみましょう。
X軸は横なので左か右のキーが押されたときですね。
マップ配列を思い出してください。
実際には1次元の配列ですが、イメージは2次元にしてOKです。
しかしX軸だけで見ると1次元でみようが2次元で見ようが右か左の添え字にアクセスするだけですね。
プレイヤーがマップ配列の添え字5にいたとき
左キーを押した場合は-1の配列添え字4の中身を調べる。
右キーを押した場合は+1の配列添え字6の中身を調べる。
これだけです。
簡単ですね。
上下に移動できるかどうかは横幅分足すか引くかすれば調べられる
配列の左右を調べるのはとても簡単でした。
しかし上下となるとどうでしょうか?
1次元の配列で考えるとちょっとわかりづらいかもしれません。
2次元に置き換えてみると、上下の場合はX座標は同じ位置でY座標が変わるだけですね。
X軸、つまり横幅はどれだけ上下しようがサイズは変わりません。
なので30×30のマップだった場合プレイヤーがマップ配列の添え字15にいたとき
上に行くときは-横幅分1の配列添え字5の中身を調べる。
下に行くときは+横幅分1の配列添え字25の中身を調べる。
難しいようで簡単でしたね。
横幅も縦幅もマップを読み込んだ時に変数に格納しているので調べる必要は全くないのです。
──グリッド衝突判定ができてしまえば7割ぐらいRPGは完成したようなもんです。
というのも、あとは衝突判定をしたらどうしょりするか、数値を増やすのか減らすのか。
グラフィックを動かすのか消すのかだけになってきます。
が、次に重要な箇所はシーンの管理ですね。
これもまた会話シーンやバトルシーンを作るときに解説します。
それでは。