スクラッチに挑戦している皆さん、どうも!スクラッチコーチです。
準備
このレッスンはマリオを作るシリーズの4レッスン目です。前回レッスンをやってない方はチェックしてみてください。
スクラッチでマリオのゲームを作る特大レッスン#03 壁・坂を攻略せよ
本家マリオと同じように壁なら止まり、坂なら登る処理が書けるようになります。「スクラッチでマリオ」シリーズの最終ゴールをチェック
最後までレッスンを進めるとこのようなマリオゲームの土台となるプロジェクトが完成する予定です。
当レッスンの完成品を確認する
画質が粗いですが、ゴールの旗にプレイヤーが触れると次のレベルが始まって、最後はクリアという文字が出る部分に注目してください。
各レベルによってシーンが違う点も、カンタンに管理できる仕組みを紹介します!
また、今回からメッセージを多用し始めます。メッセージはプロジェクトが複雑化する要因の1つです。これを上手に把握する方法も紹介します。
スクラッチプロジェクトをコピーして保存する
ファイル>コピーを保存する、を選んでプロジェクト名を「マリオプロジェクト004 ゴール」としておきます。
バグ修正からスタート
バグではないのですが、バグの温床になりそうな部分があるので、この段階で直しておきます。スクラッチはプロジェクトを作る前に完璧に設計してミスなく作り上げる、というプロセスを経る必要はありません。仕事ではありませんから、気楽にコーディングして気がついたタイミングで直せばいいのです。
すごく言い訳っぽくてスイマセン……レッスンなのだから完璧に設計して作り上げられればよかったのですが、バグ修正の練習にもなると思ってご容赦ください。
プレイヤーのジャンプ力を変数化しておく
マジックナンバーは極力減らしたいので、ジャンプ力である10を変数にしておきます。
変数「ジャンプ力」を作る
プレイヤーのスプライトに作ります。
初期化する
旗がおされたときに10になるように初期化しておきます。
上キーが押されたときに変数「スピードY」に変数「ジャンプ力」を入れます。
ステージをレベルに改名する
ステージ、というスプライトを作っていましたが、背景のこともステージと呼ぶので紛らわしいですね。背景は名前を変えることはできませんので、スプライトをレベルに変えます。
プレイヤーの変数「ステージに触れているかどうか」を改名する
ステージに触れているかどうか、という変数は「シーンに触れているかどうか」に改名します。レベルに触れているかどうか、だと分かりづらいので具体的に「シーン」としました。
プレイヤーのブロック定義「ステージに触れているか調べる」を改名する
同じくブロック定義もシーンで直しておきます。
ログやメモも適宜修正する
ログやメモなのでロジックには関係ありませんが、ステージという名称を使っていた箇所をレベルまたはシーンで修正しておきます。
変数「★カメラのX座標」に入る値を逆向きにする
今は右に進むと変数「★カメラのX座標」にマイナスの値が入ります。前提として右に横スクロールしていくので、右がプラスのほうが直感的です。直感的かどうかは重要なので、このタイミングでここも修正します。
プレイヤーの変数「スピードX」への加算処理を逆にする
直接★カメラのX座標を修正するのではなく、変数「スピードX」への加算処理を変えます。紛らわしいのでBeforeとAfterのスクショを掲載しておきます。
修正前
修正後
上のスクショ部分を、こう直してください。
- 右を押したら変数「スピードX」に変数「加速力」、つまり右でプラスの値が入ります。
- 左を押したら変数「スピードX」に「0 - 加速力」、つまり左でマイナスの値が入ります。
レベルのスプライトのX座標へ代入する式を変える
合わせてレベル(元ステージ)スプライトのクローンされたときの挙動も変えます。X座標に入る値を逆向きにします。
ここではゼロからマイナスする形で逆にしていますが、-1を掛ける方法でも構いません。
重力の初期化をレベルのスプライトに移す
いまはプレイヤーのスプライトで重力の初期化を行っています。しかし、重力をプレイヤーで初期化するのは違和感があります。重力を管理するのはステージかレベルのどちらかが良いでしょう。
今回はレベルに管理してもらいます。予定はありませんが、ひょっとしたら月面シーンや水中シーンのように重力の法則を変える必要があるかもしれないからです。
って書いたらとてもワクワクしてきました。最近のマリオは宇宙にも行くし、本当に宇宙シーンとか楽しいかも。しかし、宇宙でも敵モブを踏んでたおせるのだろうか……。無重力なのに。
プレイヤーのスプライトからは重力の初期化部分を消しておいてください。
動作確認する
これでバグ修正は終わりです。
挙動に変わりがないかチェックしておきましょう。
ゴールのスプライトを作る
ゴールは独特な振る舞いをするので、シーンの一部とはせず、スプライト化しておきます。
コスチュームを描く
ゴールっぽいコスチュームを描きます。
マリオっぽく旗をゴールに見立ててみました。この段階で色やサイズやデザインにはまったくこだわりません。旗のコスチュームを描くのが難しければ、ただの太い棒でも、いったんOKです。
スプライト名をゴールにする
とりあえずの処理を作る
旗の挙動はもう少しあとでちゃんと作り込みますが、いったんカンタンな処理だけ書いておきます。
画面右端から近寄ってくるような挙動にする
240が画面右端を表しています。そこにカメラの座標をマイナスすることで、プレイヤーが歩くごとに旗に近づくような視覚効果が得られます。
あ、マジックナンバー使ってしまった……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,,,と追加するだけでは、どのシーンが何レベルのときに表示されるべきか分かりません。
そこで命名規則によってレベルとシーンを関連付ける作戦で行きます。これは実際のシステム開発などでもよく使われる作戦です。
レベルで「次のレベルに進んでください」を受け取る
まずはレベルでメッセージ「次のレベルに進んでください」を受け取ったら初期化が始まるようにします。
移動前
移動後
旗がおされたときに、メッセージ「次のレベルに進んでください」を送るようにしておきます。これがないと何も始まりません。
こうしておくと後日「オープニングシーン」や「メニュー画面」みたいなものを追加するときも便利です。スタートという文字をユーザーが押したらメッセージ「次のレベルに進んでください」が送られる、みたいにしておけば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なので、正しいですね!
レベルが2に進めば、今度は「レベル2_シーン1」のコスチュームからスタートします。僕はレベル2ではシーンを2つ作ったので、合計数も2になります。レベル2のシーン数は何個でもOKですが、このロジックの正しさを確認するためにも3つ以外にしておくと良いでしょう。
コスチュームを元に戻す
まだレベルの初期化処理は続くので、コスチュームをシーン1に戻しておきます。
自分のクローンを作るループを置く
もともとあった「3回自分のクローンを作る」ループと同じことをします。ただし回数は変数「★今のレベルのシーン合計数」です。
メッセージ「レベルの初期化が終わりました」を作る
送る
これでレベルの初期化が終わりました。
レベルの初期化が終わったことを他のスプライトにお知らせして、それぞれの動きを開始してもらいます。
動作確認する
これで動かしてみてください。おかしいことが起きた人もいると思います。
おそらく正しくレベル2のシーンが表示されなかったのではないでしょうか。
実はまだ足りません。
今のまま動かすと、レベル1のシーンは正しく表示されるのですが、次のレベルに進めません。
左上に変数「★今のレベル」が出ています。ゴールしたあとに5に変わっている点に注目してください。
その理由は、変数「★今のレベル」です。1の次は2になってほしいですが、5になってしまっています。
なぜこうなるか予想がつくでしょうか。
答えは、クローンです。
レベルではクローンを作って各シーンを生成しています。レベル1のシーンは3つあるので、クローンも3つできています。
そしてクローン達もメッセージ「次のレベルに進んでください」を受け取ってレベルの初期化処理を始めてしまうのです。するとどうなるでしょうか。
- スプライト本体が変数「★今のレベル」にプラス1します。
- クローン1も変数「★今のレベル」にプラス1します。
- クローン2も変数「★今のレベル」にプラス1します。
- クローン3も変数「★今のレベル」にプラス1します。
まとめると「 1 + 4 」で5になってしまうのです。
解決策として、初期化処理をスプライト本体だけに行わせればOKです。
フラグを使って解決する作戦で行きます。
変数「クローンかどうか」を作る
レベルに変数を追加します。
本体用の初期化をする
スプライト本体は、変数「クローンかどうか」に否定の意味でゼロを持たせます。
クローン用の初期化をする
対してクローン側では肯定の意味で1を持たせます。
初期化処理に条件分岐を追加する
本体なら初期化処理を行い、クローンならクローンを削除してもらいます。
動作確認する
これで正しくレベル2にすすめると思います。試してみてください。
クローンも本体と同じ処理をしてしまい重複した結果が算出されてしまうというのは、クローンあるあるです。フラグを使えばいいんだと覚えておくと、色々な場所ですぐに問題解決が出来ます。
また、ここまでの実装でレベルの追加も簡単にできるようになりました。コスチュームを作って「レベル○_シーン○」という命名規則通りの名前にしてあげればいいだけです。
あとは好きなだけトリッキーな地形を描いていくだけでワクワクを大量生産できます。
レベルの初期化が終わったあとの処理
プレイヤーやゴールのスプライトに動いてもらいます。
プレイヤーのスプライトの初期化を行う
旗がおされたタイミングで初期化していましたが、これからはメッセージ「レベルの初期化が終わりました」を受け取ったときに初期化するように変えます。
こんなかんじです。↓
メッセージ「ゴールしました」を受け取ったらプレイヤーを止める
ゴールしてから次のレベルが始まるまでは、プレイヤーには動いてほしくないので、このタイミングでプレイヤーを止めます。
これをさっきゴールを作ったときではなく今追加した理由は、初期化処理がメッセージ「レベルの初期化が終わりました」をトリガーにして実行されるようになったからです。
旗がおされたタイミングで初期化されていた頃では、うっかりプレイヤーの動きを止めるとゲームがスタックして動かなくなります。
今なら、レベルの初期化のたびにプレイヤーの動きは再開されるので、安心して止めることができるようになったのです。
隠す・表示する処理も追加する
レベルの初期化が終わるまではプレイヤーには一度隠れてもらおうと思うので、このタイミングで隠す・表示するブロックも追加しておきます。
ゴールのスプライト
ゴールしたら隠す
ゴールしたら一度隠れるようにしておきます。
メッセージ「レベルの初期化が終わりました」を受け取り表示する
レベルの初期化が終わり、各シーンが所定の座標に配置されたら表示します。
表示後に処理を移す
旗がおされたタイミングで行っている処理を、各レベルの初期化が終わったタイミングで実行されるように変更します。
動作確認する
動作を確認するとレベルは順調に変わるのですが、レベル3はまだ作っていないため、挙動がおかしくなります。
この原因は、シーンの合計数をカウントしているところで起きています。
現在の作りだと、コスチューム名を「レベル3_シーン1」に変えてからシーンの数をカウントしていますが、そんなコスチュームは用意していないので合計数はゼロです。
するとレベルのクローンが1つも作られないため、地面がなくなってプレイヤーは落下してしまいます。
全クリアを作る
そこで、シーンの合計数がゼロだったら、それはもう全面クリアしたとみなします。
条件ブロックを追加する
シーンの合計数をカウントし終わった直後に、「もし」ブロックを追加します。
条件は、変数「★今のレベルのシーン合計数」がゼロだった場合、です。
メッセージ「全クリアしました」を作る
送って止める
メッセージを送り、その後に処理を止めます。シーンの合計数がゼロなのでこのあとの処理は必要ありません。
ステージに全クリア処理を記述する
ステージ(背景)に全クリアしたときの処理を書いておきます。ちょうどゴールしたときの処理を書いたのと同じです。
これはレベルのスプライトではなくステージです
ステージに背景を追加する
非常にカンタンですが、クリアの処理を追加しておきます。
ステージに「クリア」という背景を追加します。
全クリアしたら背景をクリアに変える
ステージの背景を初期化する
背景はいまのところ適当です。細部を詰める段階でマリオっぽい背景を一緒に描いてみたいとおもいます。絵心はあまりないですけど……。
プレイヤーを隠す
全クリアしたらとりあえずプレイヤーは隠しておきましょう。
プレイヤーのスプライトにこちらを追加してください。
これで全クリア処理はいったん終了にします。いまはクリアしたことが最低限わかればOKです。
つぎはゴールのスプライトを洗練していきますが、ゴールのスプライトに入る前に一点修正があります。
ローカル変数をグローバル化する
最初のレッスンで変数「1シーンの横幅」を作りましたが、これはレベルのスプライトに作ったローカル変数(このスプライトのみ、の変数)でした。
しかし、やはりこれは他のスプライトからも参照したいので「すべてのスプライト用」変数(グローバル変数)にしたいと発覚しました。
変数「1シーンの横幅」をグローバル化する
残念ながらスクラッチではローカル変数をグローバル変数に変更はできません。
ですが、この作業(グローバル化と勝手に命名してます)はまぁまぁ発生します。
完璧な設計をしてから作り込む、という手順を踏んでいる人は少ないので(たぶん)、よくあることだと言えます。
そこで地道にチェックしながら変更します。変数のグローバル化にはコツがあるので一緒にご紹介します。
まず既存の変数がどこで使われているか把握する
今あるローカル変数「1シーンの横幅」がどこで、何箇所使われているかを把握します。
直接目視で1つずつチェックする方法が王道ですが、ブラウザの検索機能を使うともう少しスムーズにできます。
ブラウザごとにやり方が違うかもしれませんが、メジャーな方法は載せておきます。
スクラッチのエディタで検索したいスプライト(今ならレベル)のコードが見える状態で次のとおりにします。
- Windowsなら、Ctrlキー《コントロールキー》とFキー《エフキー》を押す
- Macなら、Commandキー《コマンドキー》とFキー《エフキー》を押す
そうすると画面の右上などに検索窓が表示されます。
そこに「1シーンの横幅」と入力してください。するとページ内の「1シーンの横幅」という文字がハイライトされます。
ハイライトされた箇所が見えないという人は、手動でスクロールしてハイライトされている文字を探してください。
ちなみに、ブロックだけではなくてページ内のすべてを検索するので、関係ない場所もハイライトされている部分もあります。主にブロックパレット内です。
使用箇所が3箇所あると検索窓の右側に書いてあります。1つはブロックパレット(左側のサイドバー)内のブロックのことなので、実質2箇所で使われていることが分かりました。
新しいグローバル変数を作る
使われている場所を把握したら、新たに変数「★1シーンの横幅」を作ります。
変数の使用箇所を右クリックする
変数を置き換えていきます。
しかし「古い変数を消したり、ブロックから外して置き換える」のは悪手です。
変更するときは右クリックを使います。
右クリックすると変数を変更できます。
初期化しているところも変える
ここは普通にクリックして変更します。
これでグローバル化は終了です。もともとこのスプライト専用の変数だったので、他のスプライトで使われている箇所を探すといった複雑な作業は要りません。
グローバル化のコツ
コツをまとめておきます。
- ブラウザの検索機能で旧変数がどこで使われているか把握する
- 変数の使用箇所を変えるときは、必ず右クリックで変える
- 初期化している箇所は、普通にクリックして選択肢から変える
これを守るだけでもかなりグローバル化がスムーズに行なえます。
改めてゴールのスプライトに着手します。
ゴールのスプライトを改善する
ゴールのスプライトは、やっつけ仕事で作ったものなので洗練します。
そもそも現状ではゴールがいきなりシーン1に見えていますが、ゴールは必ず最終シーンに登場するようにしたいです。
最終シーンというのはレベルによって何番目か変わりますが、変数「★今のレベルのシーン合計数」を使えば分かりますね。
ということでここで作り込むゴールの仕様は、次の通りでいきます。
- 毎回必ず最終シーンにスポーンする
- ゴールが見える位置までプレイヤー(カメラ)が動かないと、隠れたまま
- 見える位置に来たら表示する
- 再び見えない位置に移動したら隠す
プレイヤーが触れたらゴールとみなすところは据え置きです。
表示と隠すブロックを追加する
追加前
追加後
表示する条件分を作り込む前に変数を新たに作ります。
ここではゴールを表示する演算を簡略化するために、次の3つの変数を駆使したいと思います。
- スポーンするシーンのX座標
- 画面右端からの座標
- スポーンするX座標
変数「スポーンするシーンのX座標」を作る
初期化用のブロックを置く
いったんこのように置いてください。
そして式を当てはめていきます。
最終シーンの数から1を引いたブロックを用意する
1シーンの横幅を掛ける
1シーンの横幅が仮に540で統一されていて、合計3シーンあるなら、「 540 * ( 3 - 1 ) 」という式ができます。
僕は540でしたが、みなさんは違ってていいです。全シーンの横幅が統一されていれば値は何でもOKです。
初期化する
変数「スポーンするシーンのX座標」の値を、作成した式で初期化します。
この式については少し解説しておきます。
まずここでやりたいことは、ゴールがスポーンするべき最終シーンのX座標を割り出すことです。そこでグローバル変数である「★1シーンの横幅」にシーンの数を掛けてX座標を割り出しています。
そこまでは大丈夫でしょうか。
問題は、なぜシーンの合計数からマイナス1しているのかという点です。なにか予想はつきますか?
分からなくても全然問題ないです!頭の体操程度に考えてみてください。
答えは、変数「★カメラのX座標」にあります。★カメラのX座標は最初ゼロですよね。しかし、★カメラの変数がゼロの場所は1シーン目の中央なのです。
1シーンが540座標なので、その中心である270座標目が★カメラのX座標のゼロ地点になっています。
最終シーンについても、最終シーンの中央よりも先にプレイヤー(カメラ)が進んでしまうと、画面右端に空白が表示されることになります。
現状では特に制限を設けてないので、最終シーンまでプレイヤーをすすめると空白が見えると思います。どこかのタイミングで空白部分は映らないように制限をかけます!
この空白を見せたくないので、最終シーンの最終座標も同じく中心点に定める必要があります。そうするとここでもマイナス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の地点にいるとき、下図のように画面右端にゴールが見えています。
240とはプレイヤーと画面右端との差分です。
この240も変数化しておくとベターですね。理解のために。
それを踏まえて改めて数値を書き込んでみます。
240 + 1030 - 1031なので、実質は240 - 1ですね。このときゴールはX座標239の位置にあります。
変数「スポーンするX座標」は固定値なので変わりませんが、変数「★カメラのX座標」はプレイヤーが右に進むほど増えます。プレイヤーがさらに100座標進んだとします。するとどうでしょうか。
240 + 1030 - 1131となり、実質は240 - 101 = 139となります。このときゴールは239から139に移動したことになります。
このあとにある「ゴールから離れたら再び隠す」という処理を作り終えると次のような挙動になります。
このように、プレイヤー(カメラ)が右に100進めばゴールも左に100動く、というのが今回の横スクロール世界でのプレイヤー以外の挙動の基本になります。
ゴールから離れたら再び隠す
ずっとゴールが見えっぱなしになってしまうので、離れたら隠します。見えっぱなしでも問題はないかもしれませんが、横スクロールの作法みたいなものですね。
メッセージ管理術
ここでメッセージの管理術を始めようと思いましたが、だいぶ長いレッスンになってきたので別記事にまとめておきます!(近日中にm(_ _)m!!) 更新しました!
参考までに現時点でのメッセージ関係図もこちら↓に追記しておきます!
ブロックを作る
次回はブロックを作ります。マリオといえばブロックを壊したりブロックに乗ったりできますよね。今回作ったゴールの動きはブロックにも転用可能です。
ただ、ゴールと違ってシーンの色んな場所にスポーンする必要があります。
また、プレイヤーがジャンプして下から触れたら壊れてほしいですよね。
そういった実装にもトライしていきます。
数日以内にまた更新予定です。この記事からもリンクを貼るので、ブックマークなどしておいてください。更新しました!
- ① 横スクロールを制覇せよ
- ② ジャンプせよ
- ③ 壁・坂を攻略せよ
- ④ ゴールして次へ (いまここ)
- ⑤ ブロックを壊せ
- ⑥ スタックを回避せよ (バグ修正の回)
- ⑦ コインをゲットせよ
- ⑧ 敵モブを召喚せよ1 (クローン化、スポーン、横移動など)
- ⑨ 敵モブを召喚せよ2 (方向転換や重力)
- ⑩ 敵モブを召喚せよ3 (アニメーション)
- ⑪ バトル開始1 (ダメージを受ける・与える)
- ⑫ バトル開始2 (ダメージのアニメーション、フィードバック)
- ⑬ 敵モブをリスポーンさせる
- ⑭ iPadに対応する
- ⑮ 迫りくるパタパタ (敵モブに新しい動きを追加する手順が分かる)
- ⑯ パタパタのバグ修正 (ジャンプのバグを直す)
- ⑰ 壁に埋もれるバグ修正 (バグがバグを呼ぶ、でも諦めない)