奥行きを実装して真の三次元空間を創る(爆速オンライン3Dゲームの作り方 #09)

奥行きを実装して真の三次元空間を創る(爆速オンライン3Dゲームの作り方 #09)
グリフパッチ(動画)
ok-scratch(執筆)

和訳解説は動画作者のグリフパッチさんご本人から許可をいただいて掲載しております。
チャンネルはYOUTUBE ( by griffpatch )からどうぞ。

奥行きを実装することで「壁の前」と「壁の後ろ」という別次元の情報を空間に持たせる。真の3Dはここからだった!
スターター
プロジェクト
リミックス用プロジェクトへ
難しさ

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

LOADING...

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

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

ゴンザレスからの挑戦状

エンティティが描画されて、敵が見えるようになった。でも敵がいない道を探して遠回りすれば問題ないよね!ってアレ!?壁の向こう側にいるはずの敵が見えちゃってる!?これじゃあ速攻で見つかっちゃうじゃんか……ダメダメ!なんとかしないと、しかし壁の向こうにいる敵をどうすれば壁の向こうに描画できるのだろうか……あぁなんだか頭がこんがらがりそう(T_T)

今回の目標「奥行きを実装して奥から順番に描画する」

いまは外見上は3Dだけど、実際は目の錯覚でそう見えるだけで、XとYの2次元空間に過ぎない。だから壁の向こうにナノがいるはずでも、それが反映されないで何でもかんでも前に来ちゃう……これじゃあ壁に隠れながら進んだり、トーストをくわえた少女が角を曲がったらイケメンとぶつかるイベントも起こせないよね!(え?いらない?)

ということで今回はXとYにくわえてZに相当する3つ目の次元、奥行きを実装していこうと思う。

↓これが目標の状態。

ok-scratch ok-scratch

今回の最後には真の3Dが僕らを待っているぞ。

マップを見えるようにしておく

このあとの処理でいったん見えるようにしといたほうが便利なので修正しておくね。

ok-scratch ok-scratch

もしすでにマップが見えるようになっているなら、そのままでOKだよ〜

幽霊をゼロにセットしよう。

ok-scratch ok-scratch

あと、スプライト「エンティティ」の緑の旗が押されたときに、ドラッグできるようにするブロックを置いておくとデバッグしやすい(スクショ取り忘れた)

CHECK! 壁の裏側に敵を配置したらどうなるかテストする

冒頭の漫画はいったいどういうことなのか、最初に現状を確認しておこう。

↓こんな感じで、エンティティを壁の中に移動してみたら分かるよ。

なんと壁の前側に描画されてしまった!

本来このナノは壁の向こう側に存在しているのだから、見えてはいけないよね。しかし現段階では「壁の向こう」みたいな概念は存在していないんだ。すべてが手前に描画されてしまう世界になっている。

ここからは奥行きを実装して、何が手前で、何が奥にあるのか、という情報を世界に与えていくよ。

それにはリストを使った描画の管理が必要になる。さぁ、いよいよ手強い部分に差し掛かってきたぞ。

ok-scratch ok-scratch

けっこうな難所だけど、一緒に乗り越えていこう!

リストで描画を管理する

さっそくリストを使った描画の仕組みを作っていこう。

新しいリスト「描画X」を作る

スクショだと末尾にリストって書いてあるけど、リストなのはブロックの色で分かるから余計だなと思い「描画X」という名前に変えました。

新しいリスト「描画距離」

こちらも末尾のリストという文字は消しました。

初期化しておくよ。

スプライト「レイキャスター」を開く

ペン関連のブロックを移動する

このブロックをドラッグアンドドロップで、スプライト「ペン」に移動しよう。

移動したらスプライト「レイキャスター」からは緑のペンブロックは消してしまってOKだ。

こんな感じになるはず↓

描画に必要な情報をリストに入れる準備をする

次は定義「_シングル・レイ」を見つけて。

↓この線のとこで切り離してみて。

「レベルカラーに触れたら」っていう条件ブロックを横にどけて、↓こんな状態にしておいて。

定義「_描画する」を作る

再描画せずに実行するにチェック入れてね。引数が3つもあるんだ。

  • タイプ
  • X
  • 距離

定義「_シングル・レイ」の最後で実行しよう。

↓このスクショを見て引数に次の3つを入れておいて。

  • タイプ:空白
  • X:変数「x座標」
  • 距離:変数「距離」

条件ブロックを作って囲もう

いま置いた定義ブロックを「もし〜でなければ」ブロックで囲もう。そしてタイプのところにペンの色を入れておいて。

定義「_描画する」の中で、各引数を各リストに格納するぞ。

奥行きを実装するために必要な情報をリストに格納できた!

残りのペン関連ブロックを、スプライト「ペン」に移動する

さっき切り離しておいたペン関連ブロックを、ドラッグアンドドロップでスプライト「ペン」に移動しよう。移動後は消しちゃってOKだ。

CHECK! リストにデータが格納されるかテストする

実行すると↓こんな感じになるぞ。

ペンで描画する

スプライト「ペン」を開こう。

さっき準備したリストの中身を使って、実際にペンを入れていくぞ。

定義「_描画する」を作る

さっきスプライト「レイキャスター」でも同名の定義を作ったけど、今度はスプライト「ペン」でも作るよ。引数はいらないよ。

↓この一連のブロックを追加しよう。

「描画Xの長さ」回繰り返すループを置こう。

変数「行#」を作る

行#《ナンバー》を作るよ。

ループの直前で、1で初期化しておこう。

ループの中で変数「行#」を1ずつ加算するよ。

定義「_行を描画する」を作る

ok-scratch ok-scratch

行を描画する、ってあんまり聞かない日本語だよね。実際使われてないと思うw ちょっと図解しておこうと思うので↓これを見ておいてね。

ここまで作ったロジックだと、ペンって上から下に1行ずつ描いていくよね。定義「_行を描画する」の行は、この1行のことなんだ。

おっけぃ。

実行する

ループの中で実行しよう。実行する場所はさっき置いた変数「行#」の前に置いてね。

変数「タイプ」を作る

色々作るものが多いけど、今度は「タイプ」っていう変数を作るよ。

定義「_ 行を描画する」の中でいろいろな値をいれていくよ。

タイプ

値は、リスト「描画タイプ」の「行#」番目にしよう。

X座標

これをまるっと複製する。

複製後に各値を調整して、X座標についても同じようなブロックを作る。

距離

距離も作るよ。複製しよう。

同じように各値を調整しておこう。

移動しておいたブロックをくっつける

さっきスプライト「レイキャスター」から移動しておいたペン関連ブロックをガチャン!っとくっつけよう。

とりまこれでOK!

メッセージ「ペイントする」を受け取ったとき

テストの前にここで定義「_描画する」を置いておこう。

CHECK! 壊れてないかテストする

色々変えたから、壊れてないかテストしておこう。

だいたいOKだね。

でもナノが画面の端にいるのが不自然な瞬間があるね。ずっと端っこから監視しているみたいだ……これは直さないと、敵に見つかっちゃいそうだね。

さっき置いた定義「_描画する」の場所を変更しよう。↓こんなかんじ。

↓ここに置けばナノが画面から消えるはず。ちょっとしたタイミングの問題なんだ。

あと、壁のカラーが無くなってたね。

定義「_行を描画する」で、変数「タイプ」をペンの色に設定しよう。

CHECK! ナノが画面外に消えるかテストする

これでナノが画面外にスムーズに消えるかな。

うん、大丈夫そうだね!ナチュラルな動きになった。

奥から順番に描画していく

奥行きを実装するメインの処理に取り掛かるよ。

3Dで奥行きを実装するというのはどういうことかと言うと、奥にあるモノから順番に描画していくということなんだ。

基本的には後から描画されたものほど、前に表示されるという法則がある。

だから奥から順番に描画すれば、前のモノほど前に、後ろのモノほど後ろに表示されるんだ。

つまり↓コレが実現できるってこと!

やってみよう!

スプライト「プレイヤー」を開く

定義「_レイキャスターを初期化する」でダミー値をリスト「描画距離」に追加しよう。

残りの2リストについても追加するブロックを置いておこう。

変数「★描画インデックス」を作る

インデックスとして使う変数を用意するぞ。

  • インデックスってなに? インデックスってなに?

    インデックスというのはリストの何番目かという数字です。リストじゃなくても例えば図書館の本棚を想像してみて。本棚の5番目にある本のインデックスは5。19番目にある本のインデックスは19みたいなイメージ。

    プログラミングだとインデックスという言葉は必須知識の1つだから、もし知らなかったらこの機会に覚えよう。

    ちなみにメジャーなプログラミング言語だとインデックスは1番目が0になる。2番目が1になる。でもスクラッチだと1番目は1だし、2番目は2になってるから注意。

2で初期化する。

スプライト「レイキャスター」を開く

定義「_描画する」に「◯まで繰り返す」ブロックを置いて、元々あったリストに関するブロックはいったん外しておこう。

◯まで繰り返す、の条件に使う演算を用意しよう。

↓このブロックを準備して。

この引き算は「★描画インデックス - 1」を作っておいて。(スクショ取り忘れたm(_ _)m)

これを「◯ > 距離」っていう比較演算の左側にセットしてみよう。

最終的には↓こんな感じになるはずだ。

適切な位置にインデックスをセットする

使うブロックはカンタンだけど処理は複雑なところ。とりあえず実装していこうか。

ループの中で★描画インデックスをマイナス1ずつ変えていこう。

このループの直下で、もう1つ「◯まで繰り返す」ブロックを置こう。

ここの条件にも比較演算子を入れる。ただしさっきとは逆向きの比較をするぞ。「◯ < 距離」を置こう。

左側にはシンプルに、リスト「描画距離」の「★描画インデックス」番目、を入れよう。

↓この画像をみて上下の条件式が違うことを再確認しておこう。

この中で変数「★描画インデックス」をプラス1ずつ変えよう。上のループとは何もかも逆だね。

この2つのループを通して変数「★描画インデックス」は適切な位置にセットされる。ところで適切な位置とはなんだろうか?

適切な位置の演算を解説

読んでもよくわからん、という人は飛ばしてもOK。

現時点で理解は必須ではないけど、一応解説しておく。

まず2つのループを作ったよね。1つ目はインデックスをマイナス1していくループ。2つ目はインデックスをプラス1していくループ。

1つ目のループ

この1つ目のループでは何をしていたのかを見ていこう。

サンプルとして↓こんな感じのリストがあったとしよう。矢印は距離の長さを表しているよ。

↓★描画インデックスの1つ上と、引数の1つである「距離」を比較するんだよね。

↓引数「距離」より、リストの中身が長かったらループを止めるんだよね。

ここまでが1つ目のループ。

これで終わりでもいいんだけど、さらに2つ目のループを作ったね。

2つ目のループ

↓2つ目では引数「距離」より、リストの中身が短かったらループを止めるんだよね。

こうすることで、確実に描画距離リストが「奥のモノがリストの上」に来るようになる。

これこそが今まで使っていた「適切な位置」の正体なんだ。

ok-scratch ok-scratch

なんだか複雑なことをしているなぁと思うかもだけど、実はこういうリストの並べ替え処理っていうのはシステム開発でもゲーム制作でも高頻度で発生する超一般的なコーディングなんだ。専門的には「ソート」とか呼ばれてる。数学の公式みたいにパターン化されているものはアルゴリズムなんて呼ばれたりする。

適切な位置を各リストに反映する

このインデックスを使って、例の3つのリストに値をセットしよう。

これで奥行きを反映した描画の準備は整った!

CHECK! 奥から描画されるかテストする

このテストはいつもとは違う手順で行う。描画は一瞬で行われるから、目で確認するには工夫が必要なんだ。

まずスプライト「ペン」を開いてほしい。

いったんプロジェクトを止めるために停止ボタンを押そう。

その後、定義「_描画する」をクリックしよう。

そうすれば……

こんな感じでテストできると思う!奥からペンで描かれている様子がバッチリわかるね!

あーでもちょっと待って。

↓肝心のナノがまだ壁の前に描画されてしまうみたい。

それもそのはず。奥行きが実装されたのは壁だけであって、まだエンティティ(スタンプ)は何も変わってないもんね。

スタンプも奥行きを反映する

エンティティも今作ったリストで管理されるように直していこうか!

スプライト「レイキャスター」を開く

定義「_描画する」をドラッグアンドドロップして、スプライト「エンティティ」にコピーしよう。両方のスプライトに定義「_描画する」が存在するようにしたいから、消さないでね。

スプライト「エンティティ」を開く

定義「_画面を回転させる」で、いまコピーした定義「_描画する」を実行しよう。

引数「タイプ」

タイプにはコスチューム番号を入れる。とりあえず1にしておこうか。

引数「X」

「相対距離X * (★DV / 相対距離Y)」という演算を作ろう。↓この矢印を参考に作ってみて。

引数「距離」

ここには変数「相対距離X」を入れよう。

↓最終的にはこんな感じ。

そして、この定義ブロックを条件ブロックで囲んでみて。

条件式で、相対距離Yがゼロよりも大きいかどうかを調べる。

自分の前にいるエンティティに奥行きを適応する準備ができた。

スプライト「ペン」を開く

メッセージ「ペイントする」を受け取ったときの処理をごっそり外すよ。横にどけておいて。

ok-scratch ok-scratch

↑後で使うよ

そして最初に「隠す」ブロックを置こう。

定義「_行を描画する」を改修する

ちょっと複雑な改修作業をするよ。

いまって↓こんな感じだよね。

これを「ペンの明るさ」で切り離してから、変数「高さ」のブロックを、変数「距離」の下に持ってきて。

↓こんなかんじにする。

ok-scratch ok-scratch

↑ちょっと複雑な作業だからスクショを見て再度確認してね。

変数「高さ」ブロックの直下に条件ブロックを挟もう。

条件式でタイプが10未満かどうか調べる。

ok-scratch ok-scratch

いきなり10っていう数字が出てきたね。これはこのゲームで使えるエンティティ(敵やアイテムなど)の上限だよ。もちろん10じゃなくて50でも100でもOK。とりあえず10個にしておく、ってかんじ。定数(変数)を作って管理してもOK。

定義「_エンティティをスタンプする」を作る

さっき『メッセージ「ペイントする」を受け取ったとき』から外しておいたブロック群をここにくっつけよう。

ok-scratch ok-scratch

↑ブロック群の最後に「ドラッグできるようにする」があるけど、これはなくてもOK!

↓こんなかんじになるよ。

これを加工していく。

まず距離と高さの処理は消しちゃって。

さらに最後の「ドラッグできるようにする」がある場合は消しちゃおう。

そしてこの定義を、さっき追加した条件ブロックの中で実行する。

ココ以降は壁を描画する処理になるから、エンティティをスタンプする場合は処理をここで止めちゃおう!

なんか加工しまくったら結局くっつけたブロックのほとんどを外して、いったん↓ここまでシンプルにしてもらったほうが分かりやすいかも……。

あらためてX座標とY座標をセットしていこう。YはゼロでOK。

そしてペンのスタンプブロックを実行する。

CHECK! ナノが壁に隠れるようになったかテストする

やっほーーーい!ナノが壁の向こう側に描画されたぁ!!長かったね……w

まとめ

今回は奥行きを実装するのがメインだったね。しかしこれで3D空間が真の意味で3Dになったよ。XとYと奥行き、この3つの次元がそろって始めて3D(3次元)だからね。ふぅー!

これでスクラッチキャット氏も壁に隠れながらスターを探せるに違いない。っと、あれ?なんかスクラッチキャットが迷子になってない!?なんてこった!次回もチェックしてみてくれ。

グリフパッチさんの動画

このチュートリアルは世界No.1スクラッチャーとして名高いグリフパッチさんの動画を参考にしているよ。ただし手順を一部変えているところもあるんだ。

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

スクラッチゲーム攻略

スクラッチゲーム

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