「スクラッチでマリオのゲームをつく特大とくだいレッスン#12 リスポーンさせる 」の解説

さいじゃく
スクラッチでマリオのゲームを作る特大レッスン#12 リスポーンさせる
敵モブがスタックしたらリスポーンさせる手順がわかります!
スタータープロジェクト

リミックスしてスタート
ファイルをダウンロード
(Scratchデスクトップ用)

完成サンプル
Scratch公式サイト

敵がシーンや壁に埋もれてしまうことが確認できています。これを回避するには2通りの方法があります。

1つはリスポーンで、もう1つは埋もれを修正する方法です。

今回は両方とも実装します。

まず埋もれを修正にトライして、それでもダメならリスポーンするという流れです。

一番最初に作る処理は、そもそも埋もれているのかどうかを判定するロジックです。

見ていきましょう!

スクラッチでマリオのゲームを作る特大レッスン#12 リスポーンさせるを語るさいじゃく さいじゃく

今回の埋もれ修正のロジックは、最初ちょっとバグがあったのですが、MeIonbreadさんのご報告と協力で解決しました。記事内容は修正済みです。MeIonbreadさん、ありがとうございます。

敵モブをスタック回避させる

スタックするというのは動けなくなるとか固まるという意味です。現状では敵モブがシーンに埋もれて動けなくなるバグがあります。

今回はここにタックルしていきます。

リスポーンする

まずはシーンに埋もれた時のレスキューとして、最初にスポーンした場所に戻してしまうという方法を実装します。

変数「リスポーンタイマー」を作る

埋もれたらすぐにリスポーンさせるのでは、しょっちゅう敵がリスポーンしてしまい、ゲームが難しくなってしまいます。

そこでリスポーンタイマーという変数を作って、何秒か埋もれた状態が続いていた場合だけリスポーンさせるようにしたいと思います。

ブロック定義「リスポーンする」を作る

オプションにチェックを入れます。

右に1座標ズラして障害物に触れているか調べる

すぐに座標を戻す
障害物に触れていなければタイマーをリセットする

終わるときはリスポーンタイマーをゼロに戻します。

まだリスポーンタイマーに値を設定する前なので分かりにくいですが、このあとすぐにリスポーンタイマーに値を入れるので、とりあえず処理を止めるときにゼロに戻すという処理を入れておいてください。

処理を止める

障害物に触れていなかったので、リスポーンの必要性はありません。この場合はこれで終わりです。

同じことを左でも繰り返す

座標がプラマイ逆になっただけで、まったく同じ処理です。冗長ですが分かりやすいのでOKです。

左右が障害物に触れていた場合を作る

左右が何かに挟まった状態であると解釈して、タイマーをセットします。このタイマーで一定時間経過したらリスポーンの必要があります。

タイマーという値はブロックパレットの「調べる」にあります。

タイマーをセットしたらいったん処理を止めてOKです。

また、スクショではログを書いておきました。なぜタイマーをセットするのか、その理由を書いておきました。

一定時間たったか様子見をする

タイマーをセットした後もなおスタック状態が続いているかを調べます。

ステップ1

タイマーからリスポーンタイマーの値を引いています。

数字で解説します。

タイマーには現在時刻が入っています。

リスポーンタイマーには一瞬前の時刻が入っています。

そして、今の時間から一瞬前の時間を引くと「何秒経ったか」という差分が分かるのです。

ステップ2

差分が3秒よりも大きいかどうかを判断する式です。

3秒はこの段階では適当です。おそらく0.6秒くらいがいいかなと思います。

ステップ3

条件分岐ブロックを追加します。

またログを書いておきました。

このブロック定義は、各条件がNOであるとスクリプトを止める構造なので、ブツブツ切れているような作りになっています。こういう構造はログがないと分かりづらいので、こまめにログを書いてあります。

リスポーン処理をする

これがリスポーンの本質的な処理です。変数「初期化済みかどうか」を1から0に戻してから自分のクローンを作り、自分自身は消しています。

こうするとまた最初のスタンバイ状態に戻ります。

スクラッチでマリオのゲームを作る特大レッスン#12 リスポーンさせるを語るさいじゃく さいじゃく

おっと、0ではなく定数「■いいえ(NO)」を使うべきでしたね。

ブロック定義全体を確認する

動作確認する

埋もれを修正する

リスポーンに成功しました。しかし、スタックしたらリスポーンではなく、まずは埋もれた状態を改善できないかどうかを試みたいと思います。

プレイヤーのときに埋もれてしまったプレイヤーをレスキューするロジックを作りました。

敵モブでも同じように埋もれ修正を行います。それでもダメならリスポーンするという流れにします。

作戦としては、敵モブを上下左右に何座標か動かしてみて、一番近くのスペースを探します。そして見つかったスペースに敵モブをワープさせるという感じです。

まずはスペースを探すロジックを作ります。

ブロック定義「埋もれ修正する」を作る

オプションにチェックを入れます。

利用する
リスポーンの処理を整えておく

埋もれ修正後にリスポーンする部分を少し変更します。

ブロック定義「埋もれ修正する」の直後に、障害物に触れているかどうかを判定します。

触れていなければ埋もれ修正できたということです。

リスポーンタイマーをリセットしてスクリプトを止めます。

また、ログも修正してあります。

ログを追加する

リスポーンのところにもログを打っておくと分かりやすいです。

変数「埋もれ修正値」を作る

初期化する

30回繰り返す

30というのはまだ適当です。何座標まで埋もれ修正を試みるか、適切な数値は微調整しながら見つけてください。

あまり大きな数値にすると、埋もれ修正のレベルを逸脱してしまいます。微調整する際は、そのあたりのバランスを考えながら調整します。

埋もれ修正値を1ずつ増やす

XとYに埋もれを修正する

XとY両軸に2回ずつ埋もれ修正を試みます。2回というのは、プラス方向とマイナス方向の2回です。

つまりXの1回目は左、Xの2回目は右、Yの1回目は上、Yの2回目は下、という要領です。

X方向の埋もれ修正にトライする

まずはX方向、つまり横にずれたら脱出できないか試します。

X方向に敵モブをズラす

障害物に触れているか調べる

敵モブの位置を戻す

X軸の移動は「★カメラのX座標」と「スポーンするX座標」と「移動距離X」といった変数を駆使して行っているので、X座標を直接ずらしても解決になりません。

ではナゼ座標をズラしたかというと「現在地からズレたら埋もれが解決するのか」を知りたかったからです。

そのため、いったんこの段階でズラして分は戻しておきます。

障害物に触れていたか調べる

もう触れていなかったら埋もれを修正して終わり

埋もれから脱出できる座標が見つかったら、変数「移動距離X」に変数「埋もれ修正値」の値を追加して、脱出させます。

そしてこれ以上ループを繰り返す必要はないのでスクリプトを止めて終了です。

まだ触れていたら逆方向を調べる

まだ触れていたら、逆方向を調べる準備をします。

仮にX方向1回目のループなら、埋もれ修正値は1です。ここで「0 – 1 = -1」として次はマイナス1座標分X方向にズラす準備をします。

X方向2回目なら、「 0 – (-1) = 1 」となるのでプラス1に戻った状態でY方向のループに進みます。

Y方向の埋もれ修正にトライする

次は縦方向に脱出を試みます。

Y方向に敵モブをズラす

障害物に触れていたか調べる

もう触れていなかったら処理を止める

X座標のときは変数「移動距離X」への追加をする事情があったため、ズラした分を戻したり変数に加算したりしましたが、Y軸はシンプルなものです。

単純に見つけたスペースまでY座標をずらせばいいだけなので、単純にズラした分を元に戻さなければOKです。

まだ触れていたら逆方向を調べる

まだ埋もれていたら、Xのときと同じように、埋もれ修正値を反転し、ズラした座標も元に戻します。

そして逆方向を調べていきます。

X2回、Y2回のループが終わったら、今度は埋もれ修正値を1から2に変えて同じことを繰り返します。

これを合計30回繰り返すことで、上下左右に30座標までにスペースが見つかれば埋もれ修正します。

見つからなければリスポーンですね。

動作確認する

完成です!埋もれてもピョコっと上がってきます。ずっと埋もれてたらリスポーンしてくれます。

プレイヤーを微調整したら土台は完成!

長い道のりでした。

あとはちょっと微調整します。

そうしたらいったん完成です。

その後はマリオらしい敵モブを作ったり、コースを考えたり、ワクワクを盛り込みまくりましょう。