スクラッチに挑戦している皆さん、どうも!スクラッチコーチです。
- ① マップチップ(タイル)をグリッド状に並べる
- ② タイルをスクロールさせる
- ③ リストでグリッドを管理する
- ④ ステージを洗練させる
- ⑤ 衝突処理を作る (いまここ)
- ⑥ マリオを動かす!
- ⑦ キー長押しでハイジャンプ
- ⑧ 走るアニメーションをヌルヌル動かす
- ⑨ キュキュッとターンで土ケムリぶわぁ!
- ⑩ もはやマリオメーカー!自由自在にステージを改造する仕組み
- ⑪ 落ちる挙動を作ろう & 品質向上
- ⑫ ステージコードをエンコードする(セーブ)
- ⑬ ステージコードをデコードする(ロード)
- ⑭ コインをゲットしてがっぽり♪
前回はステージの枠を洗練させて、ランダムでブロックを配置するようにしたよね。
カメラもスムーズに動いて端っこで止まるようにしたことで、余計な空白も映り込まないようになってる。すっごい本格的なスクロールゲームができそうな予感がヒシヒシだ!
今回の目標「マリオとタイルの座標から衝突判定を算出する」
今回はマリオを動かして、ブロックとの衝突判定に成功させるところまで行きたい。
え?そんなのカンタンじゃん。「◯に触れたら」ブロックを使えば一発でしょ?
ところが、このタイルで構築された世界はすべてがスプライト「タイル」だから、「◯に触れたら」ブロックではいったいどのタイルに触れたのか分からないのだ!例えば地面なのか壁なのか、どっちもタイルだから分からないという感じ。
そこでマリオの座標からグリッドのインデックスを算出して、その位置にどんなタイルがあるのかをプログラマティックに把握する衝突判定を作っていく。
しかも衝突判定はマリオの左右上下の4箇所で必要だから、そのあたりの算出方法も注目だ!
衝突判定はゲーム開発ではメジャーな用語だよ。当たり判定と呼ぶことも多い。英語だと衝突はCollisionといって、障害物のことをColliderという。コリジョンもコライダーもゲーム開発していると頻出するから、もし出会ったら衝突系のワードだったなと思い出してほしい。
マリオを作るぞ!
やっとマリオのスプライトに取り掛かれる!待ちに待ったマリオだ!カメラの実装ですこし触ったけど、ぜんぜんマリオ感なかったもんね?いよいよココからだぜ。
デフォルト設定を変える
コーディングの前にデフォルトの状態をすこしいじるよ。
表示する
いまはマリオは隠れた状態になってるから、デフォルトで表示状態にしておこうか。
大きさを変える
大きさ100だと少し小さいので、200にしておこう。
回転方法を左右のみにする
あとは回転だね。2Dの横スクロールゲームだから特別な要件がないかぎりは左右のみの回転でOKだ。
実行してみる
これでカメラを動かしてみよう。何も変わってないけどマリオがいる感動を味わうためw
まぁ、このままじゃあブロックをすり抜けちゃっててゲームとしては成り立たない。ということでさっそく衝突判定を作る準備を進めるぞ。
仮想座標の変数を作る
タイルのときと同じように仮想座標の変数を作るよ。
初期化処理を作る
ブロック定義「_初期化する」を作ろう。
変数を初期化する
ここでさっきの変数を2つとも初期化しておこう。値はとりあえず100で!
緑の旗を押したときの処理を一部移す
カメラの初期位置もこっちでセットするようにしておこうか。
変更前
変更後
もとの場所でブロック定義を実行するようにしとくのを忘れずに。
チラつき防止する
念のため初期化時に一回カメラの動きを制御しておこう。どうせこのあとループ内で実行するから一瞬の話だけど、一瞬でもステージ外がユーザーに見えないようにしておくためだよ。
メイン処理を行うループを作る
次にゲームのメイン処理となるループを作っていきたい。
ブロック定義「メイン処理を行う」
ブロック定義化しておくぜ。これは再描画アリで「メイン処理を行う」というブロック定義名にする。
緑の旗が押されたときの処理を一部移す
また緑の旗が押されたときの処理を移動するよ。
変更前
変更後
メッセージ「プレイヤーが動きます」を作る
新しいメッセージを作って、メインループ内で実行していくよ。
メインループ内で送る
左右の移動を制御する
今度はこのメッセージを受け取ったときの処理を作っておこう。
ブロック定義やメッセージが多くて、ムダに複雑化しているように見えるけど、これからプロジェクトでどんどん処理が増えていくから今から処理を小分けにしてるんだ。
準備段階で事前にサンプル作品を完成させているから解説では複雑になる前に小分けしてあるけど、実際の開発では(完成サンプルがないので)複雑になってから小分けするという手順を踏む方が多い気がする。僕は。
変数「スピードX」を作る
まず横方向の移動を制御する変数「スピードX」を作っていくよ。
とりあえずこの変数に値をセットするブロックを置いとくよ。
どんな値をセットするかを解説するね!
左右の動きを検知する
ここでトリッキーな技を使う。左右のキーが押されたことを検知する方法なんだけど、引き算を使うんだ。
引き算に使うブロックはこちら。
これらをこう↓組み合わせる。
右が押されたら
右を押しながらこの演算ブロックをクリックすると下に「1」という結果が見える。
左が押されたら
左だとマイナス1になる。
どちらも押されてないなら
どちらでもないならゼロになる。
ちょうどX軸も右がプラスで左がマイナスだから、右キーでプラス、左キーでマイナスの結果が取れるなんて都合が良すぎる!
どう?めっちゃ便利そうなワザじゃない!?
都合に合わせて値を大きくする
この演算結果はスピードXに割り当てる予定なんだけど、1とマイナス1ではスピード感がない(遅い)ので、6を掛けておこうとおもう。
変数にセットする
この結果を変数「スピードX」に持たせておこう。
上下の動きを制御する
今度はスピードYだ!
上下の動きを検知する
考え方は左右の動きを制御したときと全く同じだから複製するぜ。
そして3箇所を変えよう!
プレイヤーを動かす
いよいよプレイヤーが動くぞ!やっと。
仮想座標をスピードずつ変える
動きを検知したスピードXとスピードYを、仮想X座標と仮想Y座標に加算していく。ブロックは「◯にする」じゃなくて「◯ずつ変える」だから注意。
カメラを制御する
この仮想座標を使ってプレイヤーを動かす直前にカメラの制御も呼び出しておくことでステージ外の空白がちらつくことを防ぐ。
実座標に変更を加える
そしてようやく実座標に変更を加えていく。
使うのは仮想座標とカメラだ。仮想座標からカメラの座標を引いた結果を割り当てる、って書くとややこしいから下のスクショをチェックしてみて。
完成形はこちら↓
歩けぇ!
アニメーションとかないけど、歩いたぁ!!
ただまぁブロックもすり抜ける最強モードw
そしてカメラがマリオに付いてこないから不自然な感じがすごく残ってる。
まだまだ乗り越える山が多そうだね。どんとこい!一緒に登ってやんよ!
カメラを動かす
マリオと一緒にカメラが動くようにするぞ。
ヨコに動かす
横に動かすにはカメラXに仮想座標を割り当てればOK!
タテに動かす
ヨコはシンプルだったけどタテに動かすのはちょっとだけトリッキー。
使うのはこちら↓
仮想Y座標からカメラYを引いた値を4で割った結果ずつカメラYを変えるという演算を作る……文字で読んでも意味分からんねw
完成形はこちら↓
ちょっとややこしいけど、ヨコと違ってタテの動きはあえて鈍くしてる。
マリオみたいにピョンピョン跳ねるゲームの場合はタテのカメラワークをちょっと鈍くしてあげたほうがプレイしててストレスがないからだよ。このあたりは個人で感じ方が違う可能性もあるから数値を変えて自分なりの演算を作ってみてもいいかもね。
現在地のタイルを取得する
さて、いよいよ今回のメインディッシュの衝突判定、の前提となる処理を作ろう。現在地のタイルが何かを取得する処理だ。
マリオが地面や壁やブロックをすり抜けられなくしていく上で、現在地のタイルが分かることは絶対に必要な情報だから、ガッツリ作り込んでいこう。
点のコスチュームを作る
まずは下準備として点だけのコスチュームを作ってみようか。こういう遠回りに見える一手間が実は後々の工数をグッと減らしたりするんだ。
ではコスチュームを新しく描こう。カンタンだから安心して。
ツールから筆を選んで。
そしたら真ん中らへんにチョンっと点を描こう!ワンクリックするだけだよ。
念のためセンターにピタッとあってるか、選択ツールで動かして確認しよう。
ピタッとね。
ちなみにこのセンターのアンカーにピタッと吸い付くような動きは「吸着」とか「スナップ」って呼ぶよ。
コレで動かすと……あぁ!マリオが点になってもうたw
よし、次いこう。
現在地のインデックスを算出する(作戦会議)
マリオがいる場所がグリッドのどこなのかを算出するよ。つまりグリッドのインデックスを計算で導き出すってことだ。
仮の数字を使って考え方を先に共有する!
たとえばマリオがグリッドのインデックス12のところにいるとしようか。
2ステップで算出していくよ。
ステップ1)座標の割り算
まずステップ1はXとYの座標をそれぞれ32で割る。32っていうのはタイルのサイズだね。
Y座標 ÷ 32
X座標 ÷ 32
仮にY座標が100で、X座標が75だとしよう。それらを32で割ると、Yが約3でXが約2になる↓
このY=約3とX=約2がステップ1で取りたい数字。切り下げ処理をしてY=3とX=2で考えていく。
これをステップ2でさらに特殊な式に当てはめてみよう。
ステップ2)特殊な式
まずY座標の数字を計算して、それにX座標にステージグリッドの高さを掛けたものを足すよ。
式は以下のものを使うよ。
最初のタイル(つまり1) + Y + X * ステージグリッドの高さ
この図を見てみて↓
分かりづらいところだから解説していくね。上の図を参考にしながら読み解いてね。
Y座標の計算
Y座標は最初の1タイル目と、さっきのY=3を足すよ。
1 + 3 = 4だね。
Yは4で決まり。
X座標の計算
次にX座標だ。X=2だったね。
こっちにはステージグリッドの高さを掛ける。今回の図の例だと高さは4だから、4 x 2 = 8になる。
YとXを足す
ここまで算出してきたYとXを足せば完成。
Y = 4、X = 8だから、
4 + 8 = 12
って感じで、現在地のステージグリッド上のインデックスは12であることが算出できる。
ステップ1 座標の割り算
じゃあコーディングしてみよう。この処理のためにブロック定義と変数をいくつか作っていく。けっこう複雑になっていくから読み返しながら進めてね。
ブロック定義「_タイルを調べる」を作る
XとY座標に該当するタイルを調べるブロック定義を作る。再描画は不要だよ。
実行しておく
カメラ制御する直前で実行しておくよ。
タイルが何列目にあるかを調べる
作戦会議で伝えたステップ1「座標の割り算」の処理を作っていくよ。これだね↓
座標 ÷ 32(タイルのサイズ)
まずはXからいこうか。
整数だけあればOKなので切り下げることで小数点以下を切り捨てる。
結果を変数に持たせる
このブロック定義内でしか使わないけど計算結果を変数に入れておこうと思う。
ここでしか使わないことを明示的に示すために接頭語としてアンダーバーを付けておくと分かりやすいよ。
接頭語で変数やブロック定義などの種類をパッと見で分かるようにする方法は、コーディング規約としてまとめてあるよ。興味がある人はチェックしてね。
この変数にさっきの結果をセットしておく。
タイルが何行目にあるか調べる
今度はY方向にも座標の割り算を行っていくよ。
こちらも変数に結果を格納しておく。
Xのときつくったブロックをマルッと複製して各所を修正しよう。
テストしておこう
タイルが何列目・何行目にあるか取れてるか、軽く実行しておこう。割り算が掛け算になってたり切り下げの位置が違ったりしてるとやたら大きな数字だったり小数点があったりしてるから、ちゃんと整数が取れてるか変数を表示させて見ておこう。
ステップ2 特殊な式
よし、じゃあ特殊な式に当てはめて割り算の結果をグリッドのインデックスに変換していこうか。
例の特殊な式をもう一度記載しておくね。
1 + Y + X * ステージグリッドの高さ
変数「_ステージグリッドのインデックス」を作る
少し長い名前になってしまうけど、ステージグリッドのインデックスを変数にしておく。
最初のタイルも変数化しておく
式に出てくる「1」が分かりにくいから後日見たときにパッと思い出せないと思うんだよね。だから敢えて変数にしておこうと思う。このブロック定義内でしか使わない変数だから接頭語にアンダーバーを付けておくね。
今更だけど32も変数にしておきたかった!一度セットしたらゲーム開始後は値が変わらないから定数として。名前は「タイルのサイズ(32)」とかがいいかな。ふぅ、あとから気づくことは多い。まぁ今回は直さなくていいか。
PythonとかJavascriptならテキスト言語だから一括置換みたいなこともできるけど、スクラッチは1つずつ変数に置き換えていくのが大変……(T_T)
初期化しておく
この変数には1を入れておくよ。
グリッドのインデックスを求める式を作る
用意するのはこちら↓
完成形はこちら↓
この演算結果を変数「ステージグリッドのインデックス」に持たせる。
動かしてみる!
動かしてみよう。どうかな?下の動画みたいにインデックスの値が正しく変わってるかな?
インデックスのタイルを取得する
このインデックスを使って、ステージグリッドからタイルのコスチューム番号を取得して変数に保持する。
変数「タイルのコスチューム番号」を作る
この変数は別の場所でも使うから接頭語にアンダーバーは不要だよ。
リストの値を取得する
リスト「★ステージグリッド(タイル設計図)」から値を取得しよう。
結果を保持する
この値を今作った変数に格納するよ。
結果を確認しよう
点がある位置のタイルコスチュームが正しいかどうか確認しよう。
↑空白はコスチューム番号2だから正しいね。
↑ゴールドブロックも9だから正しいね!
↑地面も10だから正しいね、うん、カンペキ!
衝突処理を作る
よし、準備は整った。いよいよ衝突判定を作っていくぞ!そして衝突したらストップするようにして、ブロックをすり抜けなくしていく。
ヨコ方向の衝突処理を作る
まずは衝突時に仮想X座標に修正を加える処理を作る。
条件ブロックを挿入する
タイルを調べたすぐあとに条件ブロックを挿入しよう。
空白以外か調べる
条件式にはタイルのコスチューム番号が2よりも大きいかどうかを判定する演算を仕込む。
2よりも大きいということは、空白コスチュームではない、ということを意味しているよね。現在地のタイルが空白タイル出ない場合は基本的に「衝突した」と判定していく。
これが衝突判定の基本的な考え方だ。
仮想X座標を修正する
まずは仮想X座標を修正しよう。スピードXの分だけ仮想X座標をマイナスするよ。そうすることで「止まる」ように見せることが出来る。
うし、続けてYだ。
タテ方向の衝突処理を作る
ちょっとだけ分かりづらいことするから注意。
仮想Y座標の加算処理を移動する
すでに作った「仮想Y座標をスピードYずつ変える」処理の場所を変えるよ。
変更前
「仮想Y座標をスピードYずつ変える」処理を「_カメラを制御する」の直前に移動しよう。ちょっと移動しづらいけど。
変更後
条件ブロックを複製して挿入する
この下に次の2つを複製する。
- ブロック定義「_タイルを調べる」
- さっき作った条件ブロック
この2つをまるっとコピペして、条件ブロック内の2箇所を修正しよう。
これでXとYの衝突判定と衝突処理が完成だ!
衝突するかテストする
さぁ、どうかなぁ?
おおぉ!ちょい分かりづらいかもだけど、止まってる!デバッグ用の変数表示を見ても仮想座標が止まってるのが分かるね。
うんうん、できたね!
マリオも止まる!
今はまだ点が止まるだけだから、次回はマリオのコスチュームに変えて衝突するところも作っていこう。そのままマリオが歩いたりジャンプしたりするところまで行けたらいいなと思ってる!
キー操作で歩いたりジャンプしたりすると、アスレチックみたいにブロックをぴょんぴょん飛び回ったりも出来るようになるぞ!いよいよ本格的なゲームのこうばしい香りがプンプンしてきたぜ!
このチュートリアルではみんなが作った作品をスタジオに掲載していこうと思ってるので、もし自分のアレンジを見てほしい!という人がいたらスタジオのコメントで教えてね。
あと挑戦したけど上手くいかなくて、書いてあるとおりにやったつもりだけど何故か動かない……みたいな人もコメントで状況を教えてくれたら、時間が割けるときにチェックしてみるよ。
- ① マップチップ(タイル)をグリッド状に並べる
- ② タイルをスクロールさせる
- ③ リストでグリッドを管理する
- ④ ステージを洗練させる
- ⑤ 衝突処理を作る (いまここ)
- ⑥ マリオを動かす!
- ⑦ キー長押しでハイジャンプ
- ⑧ 走るアニメーションをヌルヌル動かす
- ⑨ キュキュッとターンで土ケムリぶわぁ!
- ⑩ もはやマリオメーカー!自由自在にステージを改造する仕組み
- ⑪ 落ちる挙動を作ろう & 品質向上
- ⑫ ステージコードをエンコードする(セーブ)
- ⑬ ステージコードをデコードする(ロード)
- ⑭ コインをゲットしてがっぽり♪