スクラッチでマリオのゲームを作る特大レッスン#14 迫りくるパタパタ①

スクラッチでマリオのゲームを作る特大レッスン#14 迫りくるパタパタ①
ok-scratch
マリオの敵モブの1つ、パタパタ。空中を跳ねながら襲ってきます。ノコノコに羽がついただけとはいえ、実装するとなると難しい!
難しさ

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

LOADING...

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

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

ここからは敵モブを追加していきます!今までと違う動きをする敵モブを追加します。

そう、ジャンプする敵モブです!ギャー😫!!

ジャンプは今までと違う動きですね。

今までと違う動き、ということはスライムとゴーストで使ってた「移動する」ブロックでは要件を満たせません😥

どうすれば新しい動きを追加することができるか、それも今回のチュートリアルで見ていきましょう。違う動きを追加する手順を押さえておけば、みんなのゲームでもユニークな敵モブを追加する役に立つと思います😁

ここではパタパタを実装していきます。といってもスーパーマリオのパタパタをガッツリ真似するのではなく、今回もスクラッチが用意してくれたコスチュームを利用して、パタパタっぽい動きの敵モブを作ります。

よぉし!スクラッチオン!(←スクラッチオンって使いたいだけ😋)

  • スクラッチオンってなに? スクラッチオンってなに?

    スクラッチオン(Scratch on)は海外のスクラッチャーさんがよく使う言葉で、たぶんまぁ「スクラッチしようぜ!」みたいな感じです。ノリです。わっしょい!みたいな(適当😅)

仕様を決める

今回のパタパタ風の敵モブは、カエルで代用しようと思います。

完成品を見る

ジャンプの完成サンプルはこんな感じ↓

上のカエルを見ると、ピョンと一定の高さでジャンプして、しばらくしてまたピョンとしてます。空中ではジャンプしません。地面に足が着いてるときだけジャンプします。

また、ジャンプ中は上がっているときも下がっているときもX方向に進んでいます。

下のカエルを見ると、頭がブロックに当たるとジャンプが中断されている様が見て取れます。

ok-scratch ok-scratch

自分のオリジナル作品を作るときは完成動画なんてないので、頭の中にある動きをなんとなく文字で書き出しておくと便利。

仕様一覧

仕様(要件とも言う)をまとめると次のようになります。

  • 一定の高さでY方向に上がり、そのあとは接地するまでY方向に下がる。
  • ジャンプ中は、X方向にも進む
  • ジャンプは連続して行われず、一定間隔を置いて繰り返される
  • ジャンプ中にブロックなど障害物に当たると、ジャンプは中断される。
  • 壁にあたったら反対方向にジャンプをする

コスチュームを作る

まずは外見から作っていきます。外見が決まるとイメージが湧くので、コーディングの効率も上がります。

ではコス(コスチューム)を選んでいきましょう!

キャラを選ぶ

スプライト「敵モブ」を選択する

デフォルトのキャラを探す

コードからコスチュームのタブに切り替えて、左下にあるネコマークにマウスを持っていきます。

絞り込みする

Frog 2-aを選ぶ

コスチューム名をカエル1にカエル

チョウチョウを消す

カエルのコスに含まれるチョウチョウは今回使わないので、削除しちゃってOKです。

カエルの全身をグループ化する

真ん中の+に合わせる(センタリング)

グループ化してから選択ツールでドラッグすると、真ん中にある+マークにピタッとくっつきます。

このセンタリング作業を行わないと、上下の動きや回転などがおかしくなります。(今回、回転する予定はありません)

弱点コスを用意する

カエル1を複製する

コス名を「カエル_弱点」にする

グループを解除する

胴体以外を消す

ここを踏まれたらカエルはダメージを受ける。それ以外ならプレイヤーがダメージを受ける。

カエルをスポーンさせよう

引き続きスプライト「敵モブ」を使います。コスチュームからコードのタブに切り替えてください。

スポーン位置を指定する

イベント「レベルの初期化が終わりました」を受け取ったときにブロックを追加します。

スタンバイさせる

「クローンされたとき」にブロックを追加します。

ブロック定義「敵モブ_カエル」を作る

定義位置を分かりやすい場所に移動する

サンプルのプロジェクトではブロックの役割によって配置場所を変えてあります。こうすることで散乱しやすいスクラッチのコードをまとめています。

  • わかりやすさ重視 わかりやすさ重視

    みんなのエディタではコメントブロックを用意してない人もいるかもしれませんが、その場合は自分にとって分かりやすい場所に定義位置を移動しておいてください😉

スライムの処理をコピペする

とりあえずここまでをテストしたいので、サクッとスライムのブロック定義をコピペしてしまいましょう😁

ブロック定義を使う

「クローンされたとき」で「敵モブ_カエル」を使おう。

テストする

これで動きをチェック!

問題なければ、とりまOK😁

ジャンプ処理を作ろう

いよいよジャンプです!今回の目玉。

ブロック定義「ジャンプする」を作る

定義を分かりやすい位置に移動する

今回は「移動する関連」のあたりで定義していきます。

ok-scratch ok-scratch

下にブロック定義「移動する」があって、ブロックの追加がしづらいですよね。そういうときはいったん「ジャンプする」は横に置いて、できあがったらエディタの「きれいにする」機能で整列させればOKです。

使う

先にカエルのブロック定義内で使っておきましょう。これから度々テストすることになるので。

ブロック定義「移動する」の代わりに「ジャンプする」を設置しました。

テストする

この段階で緑の旗を押してみてください。あれれ?カエルがいなくなってしまいましたね……。

  • 理由を説明します 理由を説明します

    さきほどまではブロック定義「移動する」に含まれていた次の2ブロックがブロック定義「ジャンプする」にないからです。

    - ブロック「X座標を◯◯にする」

    - ブロック「移動距離Xを◯◯ずつ変える」

    この2つがないと位置が更新されないので、スポーンされない状態になってしまったのです。

位置を更新する処理をコピペする

ブロック定義「移動する」から位置更新の2ブロックをコピペします。ちと見づらいね……画像をクリックしてからダブルクリックすると拡大できるかも。

(あ、スクショがちょっと違うかも……突発的な間違い探しゲーム!どこが違うでしょうw 緑の枠は正しいのでご心配なくm(_ _)m)

テストする

ツーっと移動してますねwスポーンはしてくれましたのでOK😁

重力を効かせる

空中でツーっと動くだけなので、しっかり地面に落ちてもらいましょう。

カンタンです。ブロック定義「Y軸に移動する」置くだけ。

テストすると……。

重力で落下してますね😁

高さを変える

ジャンプするからには高さをコントロールする必要があります。

地面にいるかどうか調べる

地面にいるときだけジャンプしたいので、ブロック定義「障害物に触れているか調べる」を再利用します。

変数「■はい(YES)」は定数として使っている変数で、中身は1です。定数については別チュートリアルを参照してください。

変数「スピードY」を変える

テストする

なかなかいい感じ😍

レンガにハマっても動き続けたり連続でジャンプしまくったり、直すところは多いけど基本的な動きはかなり近づきましたね!

まだ全然コード追加してないのに、今まで作ったブロック定義を駆使したおかげで楽にここまで来れました。

一定間隔を空けてジャンプさせる

ピョンピョン連続でジャンプしているので、間隔を空けたいと思います。そのためにはまず、移動距離Xを変えるブロックを消します。

変数「移動距離X」を変えるブロックを消す

しかし、こうするとカエルがジャンプしなくなってしまいました。なぜでしょうか。

  • 理由を説明します 理由を説明します

    カエルは地面に接触しているときだけジャンプするようになっています。しかし、ブロック定義「Y軸に移動する」の中で、地面からわずかに離れるように処理されているため、ジャンプしません。

    そこで次は、強引にY座標をコントロールしようと思います。

Y座標を少し下げる

テストする

どうでしょう、いい感じにジャンプとジャンプの間隔が空きました😝

  • 一連の処理をまとめると、こんな感じです↓ 一連の処理をまとめると、こんな感じです↓

    ブロック定義「ジャンプする」はループ内で使われているので、目に見えない程度にすこーしずつY座標を下げていけば、そのうち地面に接触します。

    そして接触すれば変数「スピードY」が10になってY方向に上がり、やがてブロック定義「Y軸に移動する」内で重力によって落下します。

X方向に移動する

垂直にピョンピョンするだけではなく、横にも移動したいですよね。

ブロック定義「移動する」からコードを拝借する

テストする

怖い怖い怖いw黙々と迫るカエル怖いw

ところで、ジャンプしなくなってしまいましたね……。

  • 理由を説明します 理由を説明します

    これはスポーン位置の運が悪かったというか、バグが発見できて運が良かったというか。

    ジャンプする間隔を空けるためにちょっとずつY方向にマイナス値を追加しましたよね。つまりちょっと地面に埋もれてしまっているんです。しかもX方向にも進んでしまって、坂に食い込んでしまったのです。

    そのため高さを変えても上手く地面から抜け出せず、横にだけズンズン進む進撃のカエルになってしまいました😂

  • このバグは坂がないと発生しない このバグは坂がないと発生しない

    ちなみにこのバグは、みんなの環境では発生してないかもしれません。

    上述したように、僕の環境ではたまたま坂の途中にスポーン地点があったので、X方向の移動時に坂に埋もれるようになってしまったからです。ただ、同じような状況になればみんなの環境でも発生するバグなので、一緒に対応していきましょう。

解決策としてY方向にプラスの補正値を追加します。

Y座標に補正値を追加する

以前、坂の判定用にプラス3をY座標に追加してあったので、ここでもプラス3を補正値として追加します……。いや、バリバリのマジックナンバーですね……😅

後で直そう、うん。

テストする

埋もれを修正する

ついでに!ブロック定義「埋もれを修正する」という処理を作ったの覚えていますか?これはブロック定義「リスポーンする」内で呼ばれています。

ジャンプでも埋もれは発生しやすいので、ここでも再利用していきます。

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

  • 再利用とは 再利用とは

    再利用というワードはIT業界ではわりとメジャーなキーワードです。

    というか、納期の厳しいシステム開発会社では、いかに1つの部品(ここでいうブロック定義やスプライトやバックパックなど)を何回も使い回せるか、それによって作業を減らせるか、ということにシニアエンジニアとかアーキテクチャとかが苦心しています。だって現実の部品と違ってプログラミングの部品は何回使ってもコスト0円だからね。

    再利用性の高さは、イケてるシステム開発会社の条件の1つだったりします。

ジャンプ中にX方向に移動する

垂直にピョンピョンする動きはバグも直って落ち着きました。しかし、今回の仕様では、X方向に進まなければなりません。

じつは今でもちょこっとずつX方向に動いてます。でもパタパタのようにジャンプしながらプレイヤーに襲いかかる敵モブを目指しているので、もっと大胆に横移動するように改変していきます😁

自スプライト内でしか使わないイベントを作る

ジャンプしている間はずっとX方向にも移動する処理を作る必要があります。

Y方向の動きとX方向の動きは同時並行で行われて、楕円を描くようにジャンプさせたいと考えています。

2つの動きを同時にループ処理をしたいので、1つのループでは実現できません。

そこで、イベントを使いたいと思います。(同時に◯◯したい、はイベントを使うときによくあるニーズ)

ということで、イベント「_敵モブ)ジャンプした」を作ります。

マイルールなのですが、自スプライト内でしか使わないイベントの接頭語はアンダーバー「_」と「スプライト名)」にしてます。

「_敵モブ)◯◯した」みたいなイベントは、敵モブ内でしか使わないイベントであることを暗に示しています。

(自スプライト内だけだから「◯◯しました」ではなく「◯◯した」という表現にもなってる、細かいけど……😅)

いわゆるコーディング規約の1つです。ただしマイルールなので、世間一般で「こうすべき」というルールではありません。

イベントを受け取る

このままでは特に動きに変わりはありません。

滞空時間を管理する

「ジャンプ中はずっと」という条件を作りたいので、プレイヤーでも使った「滞空時間」という変数を作ります。

初期化する

マイナス1なので、ちょっと気持ち悪いですけど、とりあえず。あとでリファクタリングします。

ok-scratch ok-scratch

ふと思った。進行方向のマイナス1は左向きに進む進行方向を意味しているので、マジックナンバーですね……。定数にしておけばよかった。これもあとで直すかもしれません。

滞空時間をセットする

ジャンプしたら変数「滞空時間」にプラスの値をセットします。

滞空時間を徐々に減らす

ジャンプ中に滞空時間がだんだん減るようにします。

地面にいるときだけジャンプする

ジャンプするのは、地面に接触しているときのみに限定します。

テストする

よぉく見ると、楕円ではなく分度器みたいな形でジャンプしてます

Y軸の頂点まで行ったら、ストンと落ちていますね。なぜでしょうか。

  • 理由を説明します 理由を説明します

    スピードYと滞空時間の値が同じなので、頂点のところで滞空時間が0とかマイナス1になっているから、その後X方向への処理は動かずに、ストンと落下しているのです。

    解決策として、滞空時間をスピードYの2倍にします。

滞空時間をスピードYの2倍にする

このマジックナンバーはあとで変数に直すので、20と直書きするのではなく演算で2倍にしておきます。

テストする

なんか2回続けてジャンプしてるし!w

  • 理由を説明します→坂のせいです 理由を説明します→坂のせいです

    坂のせいで着地した瞬間に(滞空時間が0になった瞬間に)すでに「障害物に触れている」ため、すぐ次のジャンプが始まっています。たぶんキレイな平地ならこうはならないはず。

    まぁ、この動きも面白いから今回はこれでいいかな、って思いました。イレギュラーを楽しむ気持ちを大切にしたい(言い訳……😅)

リファクタリング(改善)

ちょっとマジックナンバーが増えてきたので、一度リファクタリングに時間を使います。

リファクタリング)ブロック定義「ジャンプする」を改修する

引数を2つ作ります。

定義箇所を置き換える
呼び出し元を置き換える

これだけでもちょっと分かりやすくなりました。

リファクタリング)マジックナンバー「高さの調整値」を潰す

初期化する

置き換える

ブロック定義「ジャンプする」
ブロック定義「方向転換する」

リファクタリング)マジックナンバー「進行方向の−1」を潰す

右向きは今のところ不要です。

初期化する

置き換える

リファクタリング)滞空時間の判定をブロック定義化しておく

ブロック定義「障害物に触れているか調べる」と同じような使い方になります。

「画面を再描画せずに実行する」にチェックを忘れずに。

変数「滞空時間内かどうか」を作る

ブロックを定義する

置き換える

ブロック定義「ジャンプする」
イベント「_敵モブ)ジャンプした」を受け取ったとき

ふぅ、すっきりしました😁

まとめ

これでジャンプのベースは整いました。しかし、まだ今回の仕様のすべてをカバーしていません。

  • ブロックに当たったらジャンプを中止する
  • 壁に当たったら方向転換する

これらのヘビーな仕様が残ってます。さらには……

このようなバグも残ってます。

これらは次回チュートリアルにてタックルしていきます。まずはここまで完成させてください。

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

スクラッチゲーム攻略

スクラッチゲーム

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