スクラッチでマリオのゲームを作る特大レッスン#04 ゴールして次へ

スクラッチでマリオのゲームを作る特大レッスン#04 ゴールして次へ
ok-scratch
横スクロールゲームで、プレイヤー以外のスプライトを動かす基本がわかります。
難しさ

任意)自分の作業中のスクラッチ作品URLを記録しておこう!再開するときに便利だよ。

LOADING...

※ この記録は今使ってるPCに保存されます。別のPCで作業するときは表示されません。

スクラッチに挑戦している皆さん、どうも!スクラッチコーチです。

準備

このレッスンはマリオを作るシリーズの4レッスン目です。前回レッスンをやってない方はチェックしてみてください。

スクラッチでマリオのゲームを作る特大レッスン#03 壁・坂を攻略せよ 本家マリオと同じように壁なら止まり、坂なら登る処理が書けるようになります。

「スクラッチでマリオ」シリーズの最終ゴールをチェック

最後までレッスンを進めるとこのようなマリオゲームの土台となるプロジェクトが完成する予定です。

当レッスンの完成品を確認する

画質が粗いですが、ゴールの旗にプレイヤーが触れると次のレベルが始まって、最後はクリアという文字が出る部分に注目してください。

各レベルによってシーンが違う点も、カンタンに管理できる仕組みを紹介します!

また、今回からメッセージを多用し始めます。メッセージはプロジェクトが複雑化する要因の1つです。これを上手に把握する方法も紹介します。

スクラッチプロジェクトをコピーして保存する

ファイル>コピーを保存する、を選んでプロジェクト名を「マリオプロジェクト004 ゴール」としておきます。

バグ修正からスタート

バグではないのですが、バグの温床になりそうな部分があるので、この段階で直しておきます。スクラッチはプロジェクトを作る前に完璧に設計してミスなく作り上げる、というプロセスを経る必要はありません。仕事ではありませんから、気楽にコーディングして気がついたタイミングで直せばいいのです。

ok-scratch ok-scratch

すごく言い訳っぽくてスイマセン……レッスンなのだから完璧に設計して作り上げられればよかったのですが、バグ修正の練習にもなると思ってご容赦ください。

プレイヤーのジャンプ力を変数化しておく

マジックナンバーは極力減らしたいので、ジャンプ力である10を変数にしておきます。

  • マジックナンバーとは? マジックナンバーとは?

    マジックナンバーというのはカンタンに言うと「パッと見では何を意味しているのか分からない数字」のこと。例えばいきなり「変数を10ずつ変える」とあったら「この10って何?いったいどこから来たの?勝手に変えていいの?」とよく分からないけど、10をジャンプ力という変数に入れておけば「10はジャンプ力ってことね」と見ただけで分かるようになる。

    マジックナンバーが多いプロジェクトは、リミックス難易度が高くなりがち。後日、自分で修正するときも困るから、どこかのタイミングでマジックナンバーを変数化しておくと便利。

変数「ジャンプ力」を作る

プレイヤーのスプライトに作ります。

初期化する

旗がおされたときに10になるように初期化しておきます。

上キーが押されたときに変数「スピードY」に変数「ジャンプ力」を入れます。

ステージをレベルに改名する

ステージ、というスプライトを作っていましたが、背景のこともステージと呼ぶので紛らわしいですね。背景は名前を変えることはできませんので、スプライトをレベルに変えます。

プレイヤーの変数「ステージに触れているかどうか」を改名する

ステージに触れているかどうか、という変数は「シーンに触れているかどうか」に改名します。レベルに触れているかどうか、だと分かりづらいので具体的に「シーン」としました。

プレイヤーのブロック定義「ステージに触れているか調べる」を改名する

同じくブロック定義もシーンで直しておきます。

ログやメモも適宜修正する

ログやメモなのでロジックには関係ありませんが、ステージという名称を使っていた箇所をレベルまたはシーンで修正しておきます。

変数「★カメラのX座標」に入る値を逆向きにする

今は右に進むと変数「★カメラのX座標」にマイナスの値が入ります。前提として右に横スクロールしていくので、右がプラスのほうが直感的です。直感的かどうかは重要なので、このタイミングでここも修正します。

プレイヤーの変数「スピードX」への加算処理を逆にする

直接★カメラのX座標を修正するのではなく、変数「スピードX」への加算処理を変えます。紛らわしいのでBeforeとAfterのスクショを掲載しておきます。

修正前
修正後

上のスクショ部分を、こう直してください。

  • 右を押したら変数「スピードX」に変数「加速力」、つまり右でプラスの値が入ります。
  • 左を押したら変数「スピードX」に「0 - 加速力」、つまり左でマイナスの値が入ります。

レベルのスプライトのX座標へ代入する式を変える

合わせてレベル(元ステージ)スプライトのクローンされたときの挙動も変えます。X座標に入る値を逆向きにします。

ここではゼロからマイナスする形で逆にしていますが、-1を掛ける方法でも構いません。

  • 「ゼロマイナス」と「掛けるマイナス1」どちら派ですか? 「ゼロマイナス」と「掛けるマイナス1」どちら派ですか?

    最近はゼロマイナスの方が好きです。掛けるマイナス1だと、単にプラマイを入れ替えたいだけなのか、それともこのマイナス1は何らかの条件でマイナス2やマイナス3になりうるのか、文脈を見ないと判断できないのに対して、ゼロマイナスなら「まぁ逆にしたいだけか」とパッと見で判断できるからです。もちろん100%ではないので過信はできませんが。

重力の初期化をレベルのスプライトに移す

いまはプレイヤーのスプライトで重力の初期化を行っています。しかし、重力をプレイヤーで初期化するのは違和感があります。重力を管理するのはステージかレベルのどちらかが良いでしょう。

今回はレベルに管理してもらいます。予定はありませんが、ひょっとしたら月面シーンや水中シーンのように重力の法則を変える必要があるかもしれないからです。

ok-scratch ok-scratch

って書いたらとてもワクワクしてきました。最近のマリオは宇宙にも行くし、本当に宇宙シーンとか楽しいかも。しかし、宇宙でも敵モブを踏んでたおせるのだろうか……。無重力なのに。

プレイヤーのスプライトからは重力の初期化部分を消しておいてください。

動作確認する

これでバグ修正は終わりです。

挙動に変わりがないかチェックしておきましょう。

ゴールのスプライトを作る

ゴールは独特な振る舞いをするので、シーンの一部とはせず、スプライト化しておきます

コスチュームを描く

ゴールっぽいコスチュームを描きます。

マリオっぽく旗をゴールに見立ててみました。この段階で色やサイズやデザインにはまったくこだわりません。旗のコスチュームを描くのが難しければ、ただの太い棒でも、いったんOKです。

  • 細部にこだわるタイミングは? 細部にこだわるタイミングは?

    旗に限らず、細部へのこだわりは色々完成してからでも十分間に合います。むしろ途中で前提が変わって、作り込んだ細部が無駄になるリスクを避けられるので後回しがいいと思います。ただ、これは個人差が大きそうですね。細部から入るほうが燃える!という方は、どんどん細部にこだわってください。僕は「細部は最後」派です。

スプライト名をゴールにする

とりあえずの処理を作る

旗の挙動はもう少しあとでちゃんと作り込みますが、いったんカンタンな処理だけ書いておきます

画面右端から近寄ってくるような挙動にする

240が画面右端を表しています。そこにカメラの座標をマイナスすることで、プレイヤーが歩くごとに旗に近づくような視覚効果が得られます。

ok-scratch ok-scratch

あ、マジックナンバー使ってしまった……240も変数にしておくと分かりやすいですね。

動作確認する

数字で説明もしておきます。

変数「★カメラのX座標」は最初ゼロです。なのでゴールは「240 - 0 = 240」の位置、つまり画面右端にあります。

そして、さきほどプレイヤーが右に歩くと変数「★カメラのX座標」にはプラスの値が入るように修正しました。つまり、右に10歩けば★カメラのX座標の値はプラス10です。

このとき、旗は「240 - 10 = 230」の位置に移動しています。

このように、プレイヤーが右に歩けば歩くほど旗は220、210……20, 10, 0とプレイヤーに近寄ってきます。視覚的にはプレイヤーが歩いて旗へ近寄っているように見えるはずです。

この考え方は今後敵モブやブロックを実装する際にも使うことになります。

プレイヤーに触れたらゴールとみなす

本家マリオでも、マリオが旗に飛びつくとゴールになりますね。ここでもプレイヤーが端に触れたらゴールとします。

メッセージ「ゴールしました」を作る

ゴールしたら他のスプライトにもそのことを伝えて、諸々の処理をするように作るので、メッセージを使います。

ゴールしたらメッセージを送り、スクリプトを止める

メッセージを送ったあとはゴールのスクリプトは止めます。ゴールの処理はまたあとで修正しますので、とりあえずこれでOKです。

背景「ステージ」にゴールの処理を書く

スプライトではなく、ステージにゴール時の処理を書きます。ステージにはどんな処理を書くか、厳密なルールはありませんが、僕の場合はゴール時のメッセージや背景音楽のコントロールなど、あえて専用のスプライトを用意するまでもない共通処理をよく書きます。

音はとりあえず適当にWinという音を選びました。

その下にブロック定義「メモ」を使って、後日ゴールの処理にこだわりたくなったら追加していく旨を書いておきました。

メッセージ「次のレベルに進んでください」を作る

送信する

今はゴール処理はなにもしませんが、本来はこのタイミングでコイン枚数を確認したり花火を打ち上げたりしたいです。そして一連のゴール処理が終わったら、次のレベルに進むという流れです。

そのため、メッセージを送信するブロックだけ今は置いておきます。

  • メッセージ多用は複雑化の序曲 メッセージ多用は複雑化の序曲

    メッセージを使いだすと一気にコーディングが複雑になります。みなさんはどう管理していますか?このレッスンの最後に僕なりのメッセージ管理術をご紹介します。

レベルによってシーンを分ける

簡易版ゴールができたので、いよいよレベルに着手します。

ゴールしたらレベル1からレベル2に切り替わる処理です。

現在、レベルにはシーン1,2,3というコスチュームがあります。このままシーン4,5,6,,,と追加するだけでは、どのシーンが何レベルのときに表示されるべきか分かりません。

そこで命名規則によってレベルとシーンを関連付ける作戦で行きます。これは実際のシステム開発などでもよく使われる作戦です。

  • 命名規則によってデータ同士を関連付ける作戦 命名規則によってデータ同士を関連付ける作戦

    ちなみにこれはCoC(コンベンション・オーバー・コンフィギュレーション)という作戦です。ざっくり意味を説明すると「いちいち設定ファイルとか作ってデータ同士を関連付けたりするのは手間だから、変数名とかファイル名とか工夫して省エネしようぜ」という作戦です。プログラミングに興味がある人はRuby On Railsとか聞いたことあるかもしれません。Ruby On RailsでもCoCの概念は取り入れられてます。もちろん他にも色々なところ(Javaとか)で採用される作戦です。

レベルで「次のレベルに進んでください」を受け取る

まずはレベルでメッセージ「次のレベルに進んでください」を受け取ったら初期化が始まるようにします。

移動前

移動後

旗がおされたときに、メッセージ「次のレベルに進んでください」を送るようにしておきます。これがないと何も始まりません。

ok-scratch ok-scratch

こうしておくと後日「オープニングシーン」や「メニュー画面」みたいなものを追加するときも便利です。スタートという文字をユーザーが押したらメッセージ「次のレベルに進んでください」が送られる、みたいにしておけばOKなので。いまは旗を押したらいきなりゲームが始まるという仕様で行きます。

レベルのコスチューム名を変える

命名規則を変えていきます。

まずすでにあるコスチューム名を「レベル1_シーン1」「レベル1_シーン2」「レベル1_シーン3」と変えます。

そして、どれでもいいのでコスチュームを複製して「レベル2_シーン1」という名前にします。レベル2_シーン2まで作っておいてください。平でもOKです。

変数「★今のレベル」を作る

初期化する

次のレベルに進むタイミングでプラス1する

これで旗を押したタイミングではゼロに初期化されますが、すぐにレベル1になります。

コスチューム名をレベルに応じて変える

「りんごとばなな」ブロックを2つ組み合わせることで、「レベル○_シーン1」というコスチュームに着替えます。

変数「★今のレベルのシーン合計数」を作る

今は「処理を3回繰り返す」というループを使っていますが、3回かどうかはレベルによって変わります。条件ブロック「もし〜なら」を使って、レベル1なら3回、レベル2なら2回、と直接書く方法でもOKですが、今回は変数を駆使して自動でシーン数を計算します。そのための変数がこれです。

初期化する

レベルが変わる度にゼロに戻します。

該当するコスチューム数を数える

すこし複雑です。

「○に○が含まれる」ブロックを置く

まずはこれを置いてください。

「りんご」を「コスチュームの名前」に変える

次に「りんご」のところに「コスチュームの名前」を入れます。

コスチュームの「名前」の部分は、デフォルトでは「番号」になっているかもしれません。クリックすれば「名前」に変えられます。

「り」をいったん「りんごとばなな」に変える

りんごを「レベル」に、バナナを変数「★今のレベル」に変える

「ではない」ブロックに入れ込む

これで「コスチュームの名前にレベル1が含まれてない」という意味が完成しました。

「まで繰り返す」ブロックに入れ込む

これで、

「コスチュームの名前にレベル1が含まれなくなるまでずっと繰り返す」

言い換えれば

コスチュームの名前にレベル1が含まれている間はずっと繰り返す

というループができました。

次のコスチュームにする

ループの中に「次のコスチュームにする」ブロックを置きます。

シーン合計数をカウントアップする

ループの一番最初に変数「★今のレベルのシーン合計数」をプラス1します。これがレベルごとにコスチューム数を数える本質的な処理を担うブロックです。

3回繰り返すループと置き換える

流れを解説します

このループに入る前に「レベル1_シーン1」に着替えているので、ループ条件である「コスチュームの名前にレベル1が含まれている」はクリアできるので変数「★今のレベルのシーン合計数」の値は「 0 + 1 = 1 」になります。

そして次のコスチュームに着替えるので、「レベル1_シーン2」になります。これもレベル1という文字が含まれているので、変数「★今のレベルのシーン合計数」は「 1 + 1 = 2 」になります。

そのあとにまた着替えて「レベル1_シーン3」になります。これもOKなので変数「★今のレベルのシーン合計数」は「 2 + 1 = 3 」になります。

さらに着替えます。すると今度は「レベル2_シーン1」になります。このコスチューム名には「レベル1」は含まれていません。だからループは終わります。

結果として変数「★今のレベルのシーン合計数」の値は3で終わります。レベル1のシーン数は3なので、正しいですね!

ok-scratch ok-scratch

レベルが2に進めば、今度は「レベル2_シーン1」のコスチュームからスタートします。僕はレベル2ではシーンを2つ作ったので、合計数も2になります。レベル2のシーン数は何個でもOKですが、このロジックの正しさを確認するためにも3つ以外にしておくと良いでしょう。

コスチュームを元に戻す

まだレベルの初期化処理は続くので、コスチュームをシーン1に戻しておきます。

自分のクローンを作るループを置く

もともとあった「3回自分のクローンを作る」ループと同じことをします。ただし回数は変数「★今のレベルのシーン合計数」です。

メッセージ「レベルの初期化が終わりました」を作る

送る

これでレベルの初期化が終わりました。

レベルの初期化が終わったことを他のスプライトにお知らせして、それぞれの動きを開始してもらいます。

動作確認する

これで動かしてみてください。おかしいことが起きた人もいると思います。

おそらく正しくレベル2のシーンが表示されなかったのではないでしょうか。

実はまだ足りません。

今のまま動かすと、レベル1のシーンは正しく表示されるのですが、次のレベルに進めません。

ok-scratch ok-scratch

左上に変数「★今のレベル」が出ています。ゴールしたあとに5に変わっている点に注目してください。

その理由は、変数「★今のレベル」です。1の次は2になってほしいですが、5になってしまっています。

なぜこうなるか予想がつくでしょうか。

答えは、クローンです。

レベルではクローンを作って各シーンを生成しています。レベル1のシーンは3つあるので、クローンも3つできています。

そしてクローン達もメッセージ「次のレベルに進んでください」を受け取ってレベルの初期化処理を始めてしまうのです。するとどうなるでしょうか。

  • スプライト本体が変数「★今のレベル」にプラス1します。
  • クローン1も変数「★今のレベル」にプラス1します。
  • クローン2も変数「★今のレベル」にプラス1します。
  • クローン3も変数「★今のレベル」にプラス1します。

まとめると「 1 + 4 」で5になってしまうのです。

解決策として、初期化処理をスプライト本体だけに行わせればOKです。

フラグを使って解決する作戦で行きます。

  • フラグとは? フラグとは?

    プログラミングにおける「フラグ」とは0か1が入る変数のことです。0を「falseふぉるす」「いいえ」「ちがう」、1を「trueとぅるー」「はい」「あってる」と見なして、「もし〜」などの条件文と組み合わせて処理を分岐するのに使われます。

変数「クローンかどうか」を作る

レベルに変数を追加します。

本体用の初期化をする

スプライト本体は、変数「クローンかどうか」に否定の意味でゼロを持たせます。

クローン用の初期化をする

対してクローン側では肯定の意味で1を持たせます。

初期化処理に条件分岐を追加する

本体なら初期化処理を行い、クローンならクローンを削除してもらいます。

動作確認する

これで正しくレベル2にすすめると思います。試してみてください。

ok-scratch ok-scratch

クローンも本体と同じ処理をしてしまい重複した結果が算出されてしまうというのは、クローンあるあるです。フラグを使えばいいんだと覚えておくと、色々な場所ですぐに問題解決が出来ます。

また、ここまでの実装でレベルの追加も簡単にできるようになりました。コスチュームを作って「レベル○_シーン○」という命名規則通りの名前にしてあげればいいだけです。

ok-scratch ok-scratch

あとは好きなだけトリッキーな地形を描いていくだけでワクワクを大量生産できます。

レベルの初期化が終わったあとの処理

プレイヤーやゴールのスプライトに動いてもらいます。

プレイヤーのスプライトの初期化を行う

旗がおされたタイミングで初期化していましたが、これからはメッセージ「レベルの初期化が終わりました」を受け取ったときに初期化するように変えます。

こんなかんじです。↓

メッセージ「ゴールしました」を受け取ったらプレイヤーを止める

ゴールしてから次のレベルが始まるまでは、プレイヤーには動いてほしくないので、このタイミングでプレイヤーを止めます。

これをさっきゴールを作ったときではなく今追加した理由は、初期化処理がメッセージ「レベルの初期化が終わりました」をトリガーにして実行されるようになったからです。

旗がおされたタイミングで初期化されていた頃では、うっかりプレイヤーの動きを止めるとゲームがスタックして動かなくなります。

今なら、レベルの初期化のたびにプレイヤーの動きは再開されるので、安心して止めることができるようになったのです。

隠す・表示する処理も追加する

レベルの初期化が終わるまではプレイヤーには一度隠れてもらおうと思うので、このタイミングで隠す・表示するブロックも追加しておきます。

ゴールのスプライト

ゴールしたら隠す

ゴールしたら一度隠れるようにしておきます。

メッセージ「レベルの初期化が終わりました」を受け取り表示する

レベルの初期化が終わり、各シーンが所定の座標に配置されたら表示します。

表示後に処理を移す

旗がおされたタイミングで行っている処理を、各レベルの初期化が終わったタイミングで実行されるように変更します。

動作確認する

動作を確認するとレベルは順調に変わるのですが、レベル3はまだ作っていないため、挙動がおかしくなります

この原因は、シーンの合計数をカウントしているところで起きています。

現在の作りだと、コスチューム名を「レベル3_シーン1」に変えてからシーンの数をカウントしていますが、そんなコスチュームは用意していないので合計数はゼロです。

するとレベルのクローンが1つも作られないため、地面がなくなってプレイヤーは落下してしまいます。

全クリアを作る

そこで、シーンの合計数がゼロだったら、それはもう全面クリアしたとみなします。

条件ブロックを追加する

シーンの合計数をカウントし終わった直後に、「もし」ブロックを追加します。

条件は、変数「★今のレベルのシーン合計数」がゼロだった場合、です。

メッセージ「全クリアしました」を作る

送って止める

メッセージを送り、その後に処理を止めます。シーンの合計数がゼロなのでこのあとの処理は必要ありません。

ステージに全クリア処理を記述する

ステージ(背景)に全クリアしたときの処理を書いておきます。ちょうどゴールしたときの処理を書いたのと同じです。

ok-scratch ok-scratch

これはレベルのスプライトではなくステージです

ステージに背景を追加する

非常にカンタンですが、クリアの処理を追加しておきます。

ステージに「クリア」という背景を追加します。

全クリアしたら背景をクリアに変える

ステージの背景を初期化する

ok-scratch ok-scratch

背景はいまのところ適当です。細部を詰める段階でマリオっぽい背景を一緒に描いてみたいとおもいます。絵心はあまりないですけど……。

プレイヤーを隠す

全クリアしたらとりあえずプレイヤーは隠しておきましょう。

プレイヤーのスプライトにこちらを追加してください。

これで全クリア処理はいったん終了にします。いまはクリアしたことが最低限わかればOKです。

つぎはゴールのスプライトを洗練していきますが、ゴールのスプライトに入る前に一点修正があります。

ローカル変数をグローバル化する

最初のレッスンで変数「1シーンの横幅」を作りましたが、これはレベルのスプライトに作ったローカル変数(このスプライトのみ、の変数)でした。

しかし、やはりこれは他のスプライトからも参照したいので「すべてのスプライト用」変数(グローバル変数)にしたいと発覚しました

変数「1シーンの横幅」をグローバル化する

残念ながらスクラッチではローカル変数をグローバル変数に変更はできません。

ですが、この作業(グローバル化と勝手に命名してます)はまぁまぁ発生します。

完璧な設計をしてから作り込む、という手順を踏んでいる人は少ないので(たぶん)、よくあることだと言えます。

そこで地道にチェックしながら変更します。変数のグローバル化にはコツがあるので一緒にご紹介します。

まず既存の変数がどこで使われているか把握する

今あるローカル変数「1シーンの横幅」がどこで、何箇所使われているかを把握します。

直接目視で1つずつチェックする方法が王道ですが、ブラウザの検索機能を使うともう少しスムーズにできます。

ブラウザごとにやり方が違うかもしれませんが、メジャーな方法は載せておきます。

スクラッチのエディタで検索したいスプライト(今ならレベル)のコードが見える状態で次のとおりにします。

  • Windowsなら、Ctrlキー《コントロールキー》とFキー《エフキー》を押す
  • Macなら、Commandキー《コマンドキー》とFキー《エフキー》を押す

そうすると画面の右上などに検索窓が表示されます。

そこに「1シーンの横幅」と入力してください。するとページ内の「1シーンの横幅」という文字がハイライトされます。

ハイライトされた箇所が見えないという人は、手動でスクロールしてハイライトされている文字を探してください。

ok-scratch ok-scratch

ちなみに、ブロックだけではなくてページ内のすべてを検索するので、関係ない場所もハイライトされている部分もあります。主にブロックパレット内です。

使用箇所が3箇所あると検索窓の右側に書いてあります。1つはブロックパレット(左側のサイドバー)内のブロックのことなので、実質2箇所で使われていることが分かりました

新しいグローバル変数を作る

使われている場所を把握したら、新たに変数「★1シーンの横幅」を作ります。

変数の使用箇所を右クリックする

変数を置き換えていきます。

しかし「古い変数を消したり、ブロックから外して置き換える」のは悪手です。

変更するときは右クリックを使います

右クリックすると変数を変更できます。

初期化しているところも変える

ここは普通にクリックして変更します。

これでグローバル化は終了です。もともとこのスプライト専用の変数だったので、他のスプライトで使われている箇所を探すといった複雑な作業は要りません。

グローバル化のコツ

コツをまとめておきます。

  1. ブラウザの検索機能で旧変数がどこで使われているか把握する
  2. 変数の使用箇所を変えるときは、必ず右クリックで変える
  3. 初期化している箇所は、普通にクリックして選択肢から変える

これを守るだけでもかなりグローバル化がスムーズに行なえます。

改めてゴールのスプライトに着手します。

ゴールのスプライトを改善する

ゴールのスプライトは、やっつけ仕事で作ったものなので洗練します。

そもそも現状ではゴールがいきなりシーン1に見えていますが、ゴールは必ず最終シーンに登場するようにしたいです。

最終シーンというのはレベルによって何番目か変わりますが、変数「★今のレベルのシーン合計数」を使えば分かりますね。

ということでここで作り込むゴールの仕様は、次の通りでいきます。

  • 毎回必ず最終シーンにスポーンする
  • ゴールが見える位置までプレイヤー(カメラ)が動かないと、隠れたまま
  • 見える位置に来たら表示する
  • 再び見えない位置に移動したら隠す

プレイヤーが触れたらゴールとみなすところは据え置きです。

表示と隠すブロックを追加する

追加前

追加後

表示する条件分を作り込む前に変数を新たに作ります。

ここではゴールを表示する演算を簡略化するために、次の3つの変数を駆使したいと思います。

  • スポーンするシーンのX座標
  • 画面右端からの座標
  • スポーンするX座標

変数「スポーンするシーンのX座標」を作る

初期化用のブロックを置く

いったんこのように置いてください。

そして式を当てはめていきます。

最終シーンの数から1を引いたブロックを用意する

1シーンの横幅を掛ける

1シーンの横幅が仮に540で統一されていて、合計3シーンあるなら、「 540 * ( 3 - 1 ) 」という式ができます。

ok-scratch ok-scratch

僕は540でしたが、みなさんは違ってていいです。全シーンの横幅が統一されていれば値は何でもOKです。

初期化する

変数「スポーンするシーンのX座標」の値を、作成した式で初期化します。

この式については少し解説しておきます。

まずここでやりたいことは、ゴールがスポーンするべき最終シーンのX座標を割り出すことです。そこでグローバル変数である「★1シーンの横幅」にシーンの数を掛けてX座標を割り出しています。

そこまでは大丈夫でしょうか。

問題は、なぜシーンの合計数からマイナス1しているのかという点です。なにか予想はつきますか?

ok-scratch ok-scratch

分からなくても全然問題ないです!頭の体操程度に考えてみてください。

答えは、変数「★カメラのX座標」にあります。★カメラのX座標は最初ゼロですよね。しかし、★カメラの変数がゼロの場所は1シーン目の中央なのです。

1シーンが540座標なので、その中心である270座標目が★カメラのX座標のゼロ地点になっています。

最終シーンについても、最終シーンの中央よりも先にプレイヤー(カメラ)が進んでしまうと、画面右端に空白が表示されることになります。

ok-scratch ok-scratch

現状では特に制限を設けてないので、最終シーンまでプレイヤーをすすめると空白が見えると思います。どこかのタイミングで空白部分は映らないように制限をかけます!

この空白を見せたくないので、最終シーンの最終座標も同じく中心点に定める必要があります。そうするとここでもマイナス270することになります。

1シーン目の中心地点までの270座標と、最終シーンの中心点以降の270座標をプラスするとちょうど1シーンの横幅と同じ値になります。そのためシーンの合計数からマイナス1すると都合よく計算がうまくいくのです。

動くものを見ないとピンとこないかもしれませんので、悩みすぎずに先に進みましょう。

変数「画面の右端からのX座標」を作る

次は、ゴールがスポーンする位置を画面の右端から何座標目にするかを表す変数です。変数とはいっても、これは決め打ち用の変数です。今のところ一度初期化したら値を変えるつもりはないので、変数ではなく定数とも言えます。

初期化する

右から50座標目くらいにスポーンさせたいと思います。

変数「スポーンするX座標」を作る

初期化する

この変数のために前述した2つの変数を用意しました。ここでの初期化には「スポーンするシーンのX座標 - 画面右端からのX座標」という演算を入れてください。

この演算の解説は先に進んでからにします。

表示する条件を追加する

ようやく「もし」ブロックの式が入ります。

変数「スポーンするX座標」が変数「★カメラのX座標」より小さくなったら、ゴールが表示されます。

もう1つ変更してから解説します。

X座標をカメラに合わせてズラす

動作確認する

これで動かしてください。最終シーンにさしかかる50座標手前からゴールが画面右端に見え始めます。そして画面右端から50座標目からはプレイヤーに近づくように動くはずです。

妙な表現ですが、実際「ゴールが近づいている」のであって、プレイヤーが近づいているわけではありません。横スクロールの実現に★カメラのX座標を使っているためです。プレイヤーは常にX座標はゼロ地点から動いていないのです。

各変数と演算を解説します

さて、先延ばしにしてきた解説ですが、動作確認まで出来たのでここで行いたいと思います。

解説すべき点は次の2つです。

  • 表示する条件文について
  • X座標に入れた演算について

表示する条件文について

スポーンするX座標が★カメラのX座標より小さくなったら表示する、というのはどういうことか、数字で解説していきます。

変数「スポーンするX座標」の値

これには1030が格納されています。内訳は下図のとおりです。

変数「★カメラのX座標」の値

これはユーザーが右キーを押すとスピードXに加速力が加算されていき、スピードXの値がどんどん変数「★カメラのX座標」に追加されていく仕様です。

なので、右に進めば進むほどプラスの値が入っていきます。0から始まり、やがて1030の地点を過ぎるでしょう。

このタイミングこそが、これ↓です。

X座標に入れた演算について

そしてこのX座標に値をセットする演算です。

この240とは何でしょうか。プレイヤー(カメラ)が1031の地点にいるとき、下図のように画面右端にゴールが見えています。

ok-scratch ok-scratch

240とはプレイヤーと画面右端との差分です。

この240も変数化しておくとベターですね。理解のために。

それを踏まえて改めて数値を書き込んでみます。

240 + 1030 - 1031なので、実質は240 - 1ですね。このときゴールはX座標239の位置にあります。

変数「スポーンするX座標」は固定値なので変わりませんが、変数「★カメラのX座標」はプレイヤーが右に進むほど増えます。プレイヤーがさらに100座標進んだとします。するとどうでしょうか。

240 + 1030 - 1131となり、実質は240 - 101 = 139となります。このときゴールは239から139に移動したことになります。

このあとにある「ゴールから離れたら再び隠す」という処理を作り終えると次のような挙動になります。

このように、プレイヤー(カメラ)が右に100進めばゴールも左に100動く、というのが今回の横スクロール世界でのプレイヤー以外の挙動の基本になります。

ゴールから離れたら再び隠す

ずっとゴールが見えっぱなしになってしまうので、離れたら隠します。見えっぱなしでも問題はないかもしれませんが、横スクロールの作法みたいなものですね。

メッセージ管理術

ここでメッセージの管理術を始めようと思いましたが、だいぶ長いレッスンになってきたので別記事にまとめておきます!(近日中にm(_ _)m!!) 更新しました!

https://scratch.coach/2022/01/26/how-to-manage-messages/
ok-scratch ok-scratch

参考までに現時点でのメッセージ関係図もこちら↓に追記しておきます!

ブロックを作る

次回はブロックを作ります。マリオといえばブロックを壊したりブロックに乗ったりできますよね。今回作ったゴールの動きはブロックにも転用可能です。

ただ、ゴールと違ってシーンの色んな場所にスポーンする必要があります。

また、プレイヤーがジャンプして下から触れたら壊れてほしいですよね。

そういった実装にもトライしていきます。

数日以内にまた更新予定です。この記事からもリンクを貼るので、ブックマークなどしておいてください。更新しました!

https://scratch.coach/lesson/mario005/
完成サンプルがあるよ
おつかれさま!今回のチュートリアルには完成サンプルがあるから、作ってて分からなくなったり、 動作確認をしたいときはチェックしてみてね。
ブクマよろしくお願いします! ブクマよろしくお願いします!
どんどん追記・更新していくので、ブックマークやシェアよろしくお願いします!

スクラッチゲーム攻略

スクラッチゲーム

    • 厳選されたスクラッチ人気作品リストがレビュー付きで楽しめます
      趣味に関するスクラッチ作品例
      勉強になるスクラッチ作品