- スターター作品
- なし
- 今回の完成サンプル
- なし
u003cpu003eこの記事の内容も含んだu003ca href=u0022/lesson/3d-online-game-1/u0022u003e新しい3Dチュートリアルシリーズを連載u003c/au003eしました!u003c/pu003e
u003cpu003e2023/09/04追記)このチュートリアルで作った作品があればスタジオで教えてね!みんなが作った作品を観るのめっちゃ好きです!u003c/pu003eu003cpu003eu003ca href=u0022https://scratch.mit.edu/studios/33795626u0022 target=u0022_blanku0022 rel=u0022noreferrer noopener nofollowu0022u003ehttps://scratch.mit.edu/studios/33795626u003c/au003eu003c/pu003e
「3Dゲームを作りたい」これは、すべてのスクラッチャーが1回は考えることです(知らんけど)。
そして調べる、そしてけっこうな割合で挫折する。ここまでがセット。なんてったって難しい。「え?レイキャ……え?レイト……え?」ってなる。
難解な解説を切り抜けた一握りの勇者だけが作れる3Dゲームを、なんとかもっと多くの人がトライしやすくしたい……そんな崇高な思いからこの記事を書きました。(3Dゲームもっとたくさんやりたいだけ)
ちなみに3Dの作り方はスクラッチWIKIにも載ってる。参考にした作品やWikiのURLは全部サンプルプロジェクトに表記してあるので、気になる方はチェックしてみてください。Wikiだと完成像しか載ってないので、ここでは詳しくワンステップ解説していきたいと思います。
ということで今回作る3Dゲームの土台はこちら↓
u003cpu003eコレ↑見てるとスクラッチで3D逃走中とか、マリカーとか、FPSとか、なんか夢が広がりませんか!?u003c/pu003e
求めてたものだったかな?よし、じゃあさっそく作っていこう!
スクラッチエディタを開いてね。
スタータープロジェクトを使ってもいいし、まっさらなプロジェクトを新規作成してミニマップのコス作成から一緒にやっていくのもOK。
ミニマップを作ろう
とりあえずスクラッチキャットは消しておこう。ネコごめんね〜😀
スプライトの猫ボタンにマウスをあわせて、描くというアイコンを選択しよう。
コスを描く
四角形ツールを選ぶ。
色は真っ黒でOK。
全体が黒い四角になるように図形を作ろう。
通路を作る
消しゴムツールを選ぶ。
真ん中あたりから適当に消していこう。これが通路になるよ。
超適当w
真ん中が空白になってればとりあえずなんでもOKだよ。
名前を変えておく
ミニマップのコーディング
ミニマップのコーディングをしていこう。
位置を合わせる
まずはマップを真ん中に設置しよう。
xもyもゼロのところに合わせればOK。
マップは一旦終了!
プレイヤーのスプライトを用意する
つぎはプレイヤー。
このレッスンではFPS(ファーストパーソンシューティング)みたいに、自分自身は見えない3Dゲームの土台を作るから、プレイヤーはあくまでミニマップ上でしか表示されない予定だよ。
だからこのプレイヤーはミニマップ上に表示されるマーカーみたいなものだよ。
スプライトを作る
スプライト名を変える
コスじゃなくてスプライト名ね
小さい四角を描く
四角形ツールを選んでSHIFTを押しながら1 x 1の小さな黒い四角を描こう。
u003cpu003e1というのは、スクラッチではチェック柄の1マスのことです。超厳密に1じゃなくても平気。できるだけ1x1を目指して小さな小さな四角を作ってみよう。u003c/pu003e
センタリングする
ドラッグして真ん中のアンカーのところにピタッと合わせておいてね。これは重要だよ。ピタッとね。
プレイヤーが移動するロジックを書く
この四角をミニマップ上で動かしていく。
初期位置を指定する
白い通路(消しゴムで消したところ)の上ならどこでもOK。
この状態で実行すると僕の環境ではこんな↓かんじ。
ずっとループを置く
この中に具体的な移動処理を書いていくよ。
右キーが押された場合を作る
中には角度を変更するブロックを置く。
u003cpu003e今回はサンプルだからいいけど、本格的にゲームを作っていくならこの数値は変数で管理すればマジックナンバー(≒第三者がパッと見で何を意味するかわからない数字)にならずに済むのでオススメ。u003c/pu003e
左キーの場合も作る
右とほとんど同じなので複製しよう。
左向きに調整しよう。
角度を変えるブロックは、いったん外して改めて左に回転するブロックをはめよう。
角度は左右で同じにしておく。
上キーの場合を作る
このサンプルでは、ここに次から作るブロック定義を使っていきます。
ブロック定義「動く」を作る
とりあえず◯歩動かすブロックを設置する。
壁に当たる処理を作る
そしてマップの黒い部分に触れたらそれ以上は進ませたくないので、後退させる。
後退させる
歩いた分だけ後ろに下げれば、壁にあたって止まったように見えるという仕組みです。
u003cpu003eもっと厳密にピタッと止める方法もある。それはu003ca href=u0022https://scratch.coach/recipe/how-to-jump-precisely/u0022 target=u0022_blanku0022 rel=u0022noreferrer noopeneru0022u003eピタッとジャンプの処理が参考になるu003c/au003eかと思います。u003c/pu003e
上キーの条件文の中で使う
スピードはとりあえず適当に1にしておこう。このあたりはしっかり作り込んでから微調整すればいいので、最初は適当です。
下キーの場合も作る
また「もし」ブロックごと複製して下キーも作ろう。
テストする
ここまではなんの変哲もない迷路ゲームみたいなものだね。一応動作確認するとこんな↓かんじ。
これが如何にして3Dになっていくのだろうか……ワクワクするね!
距離を調べる
今回の3Dではプレイヤーとミニマップの壁の距離を調べて、その距離を数値にします。この数値の大小を使ってペンツールで立体的な描画を行います。ここでは描画の前提となる距離を数値化する処理を作っていきます。3Dの準備が始まるぞ〜!
プレイヤーからイベントを出す
まずはプレイヤーにイベントブロックを1種類だけ追加します。
イベントを追加する
「イベントを送って待つ」ブロックを置きます。送る、ではなくて送って待つ。送った先で距離を調べる計算をしてデータを更新してほしいので、待ちます。
動くたびにイベントを送る
まずは左右キーの条件文に追加します。
あとブロック定義「動く」にも追加しておきましょう。
距離を調べるスプライトを追加する
スプライト名を変える
まんま「距離を調べる」でOK。
コスを描く
プレイヤーと同じ1x1の黒い四角を作ってセンタリングしておこう。
センタリングはコチラも重要なのでしっかりピタッと。
距離を調べるロジックを作る
このコスを使って壁との距離を調べていくよ。
まずこのスプライトは見える必要がないので、いきなり透明にしておこう。
距離を調べるイベントを受け取る
ブロック定義「距離を調べる」を作る
再描画せずに実行するにチェックを入れておいてね。
ブロック定義を使う
ここからはこのブロック定義の中を作っていくよ。
リスト「距離リスト」を作る
名前は「距離リスト」でOK。ここでは「★距離リスト」にしてある。
変数「距離」を作る
変数「角度のオフセット」を作る
初期化する
まずリストから初期化する。
続いて変数「距離」を初期化する。
変数「角度のオフセット」は-48で初期化する。
さて、なにやら中途半端な「-48」という数値が出てきましたね。
今回の3Dでは視野を96度にしようと思ってます。視野というのは画面に映る範囲のことです。-48度からプラス48度の間の距離を測定していくので、測定処理のスタート地点という意味合いで角度のオフセットに-48を設定しています。
測定ループを追加する
1度ずつ96回の測定処理を行います。
プレイヤーと位置を合わせる
ここが測定のスタート地点です。
プレイヤーの向きを変える
ブロックパレット(サイドバー)から「調べる」にある次のブロックを見つけてください。
▽をクリックして次のように変えます。
演算ブロックなどと組み合わせて次のとおりに配置します。
これで変数「角度のオフセット」ずつプレイヤーの向きがグイッと変わりますね。
この処理は「再描画せずに実行」されるので、ユーザーにはこの測定処理の過程は見えてないので大丈夫。スクラッチの裏側で行われる一瞬の出来事です。
測定するループを置く
測定するループを置いて、条件式を作っていきます。
限界まで進ませる
ミニマップに当たるまでプレイヤーを進ませます。または、距離が80以上になるまで進ませます。この80という距離は、見える距離の限界値を表しています。大きければ大きいほど遠くまで見えることになります。
u003cpu003e逆に小さければ近くしか見えません。洞窟の中だと値が小さくなったり、外に出て明るくなったら値が大きくなったり、という調整ができそうですね。120くらいまでなら負荷的に大丈夫、と原作者であるErnieParkeさんが言っています。u003c/pu003e
1歩ずつ動かす
一歩ずつ前に進めていきます。同時に変数「距離」も1ずつ加算しておきます。
距離をリストに保存する
壁までの距離をリストに保持しておきます。これを96回繰り返します。
後処理をする
96回繰り返すループの最後に、2つ後処理を入れておきます。
- 変数「距離」を0に戻しておく(次の測定をゼロから始めるため)
- 変数「角度のオフセット」に1を加算しておく(-48の次は-47を調べるため)
テストする
この段階で動かすと次のようになります。
前方にある壁に近づくとリストの中身が小さくなって、前方を向いたまま後退するとリストの中身が大きくなってマックス80になる様子が見えるでしょうか。
u003cpu003e四角が1 x 1マスだから前方とか分かりづらいと思うけど、この動画の■は上が前のまま変わらず前後に動いてます。u003c/pu003e
測定後にイベントを送る
距離を調べ終わったら、この距離リストを使って壁を描画していきます。
この処理はまた別のスプライトに任せたいので、イベントを送って結果を待ちます。
新しいイベント「描画する」を作って、ブロック定義「距離を調べる」の次に配置しましょう。
ミニマップ関連は透明にする
さて、このあと壁の描画に取り掛かるのですが、このミニマップについてはリストの中身が壁に近づくと変わる、っていう動作の確認ができればもう見えなくてもOKです。
ミニマップを非表示にする
非表示と言えば幽霊ですね。
プレイヤーを非表示にする
これで緑の旗を押したら真っ白な画面になると思います!さぁ、いよいよここからです。
描画する
描画もスプライトを分けて管理しておきます。
コスチュームはいらないので、透明なままでOKです。コーディングに移りましょう。
イベントを受け取る
変数「壁ナンバー」を作る
この変数は距離リストの何番目を描画するかという指定に後ほど使います。
ペンを用意する
この描画スプライトではペンを使います。
拡張機能追加ボタンをクリックする
ペンは拡張機能なので追加する必要があります。カンタンです。
スクラッチエディタの左下にある拡張機能を追加するボタンをクリックします。
ペンを選ぶ
これだけでペンがブロックパレットに追加されたと思います。
ブロック定義「描画する」を作る
さぁ、ペンを使ってブロック定義を作っていきましょう。まずはブロック定義を作ります。
描画せずに実行するブロック定義です。チェックを忘れずに。
ブロックを置く
ついでにイベントを受け取ったあとに使うようにしておきましょう。
初期位置に移動する
X座標は画面左端めいっぱいのところ、という意味で-237.5です。Y座標はこのあと動的にどんどん変えていきます。
ペンの太さを決める
結果的に5くらいがちょうどいいですが、このあたりはあとで調整すればOK。最初は適当な数字にしておいても可。適当感を出すために7とかにしておきます。
ペンの色を決める
これが壁の色になります。
色は好みだけど薄めにしておくとメリハリが付くので下記画像を参考にしてみて欲しいです。
ペンを構える
ペンには「上がってる」状態と「下がってる」状態という2つの状態があります。上がってる状態は、紙からペンが離れている状態をイメージしたら分かりやすいかも。逆に下がっている状態は、紙にペンが接している状態のこと。
上がってる状態でペンを動かしても、紙にペンが接してないから何も描けない。
下がってる状態ならペンを動かせば描ける。
変数「壁ナンバー」を初期化する
1にしておきます。
描画処理を繰り返す
いよいよメイン部分です。繰り返しブロックを置きます。
遠くの壁ほど白くする
遠くにある壁、つまり距離リスト内の数値が大きい壁ほど白っぽくします。薄くするとも言える。明るくするとも言える。逆に近くにある壁ほど濃くする。そうすると目の錯覚で立体のように見えます。
この演算を作っていきます。
まずはこういう演算ブロックを用意してください。50+◯ x ◯です。
距離リストを順番に処理する
まず距離リストの1番目から順番に処理できるように変数「壁ナンバー」を利用して掛け算ブロックに割り当てます。
最大距離で50を割る
50を80で割った値を掛けて、値を調整します。
ループにハメる
最終的にこのような長いブロックが完成します。
近い壁は明るさが50くらいになって、遠くの壁は最大100になります。
u003cpu003eたとえば一番遠い壁の計算は次のようになります。u003c/pu003eu003cpu003e50 + 80 x (50 / 80) = 100u003c/pu003eu003cpu003e明るさ100は白っぽさマックスぅ〜みたいな感じになります。(説明が雑w)u003c/pu003e
壁を描く
まだ明るさが決まっただけで、何も描いてません。例えるなら筆に絵の具をチョンチョンってつけただけです。
描き始める位置を決める
現実でも距離が遠くなるほど壁は低く見えますよね。それを演算で表していきます。
1200は壁の高さです。距離が遠くなるほど壁の開始位置が上にになります。
u003cpu003e文字が全角でした(T_T) あとで気づいたけどマイナスが全角になってた。これ半角じゃないとおかしなことになるから、みんなも気をつけてね。u003c/pu003e
ペンを下ろす
ついにペンが紙に接しました!
ペンを動かす
上に向かってペンを動かします。今度は-1200ではなくプラス1200である点に注意。
遠くなるほど壁の終了位置が下になります。
ペンを上げる
ペンを横にズラす
ペンを上げてからじゃないと余計な線を描いてしまうので注意。
ペンの太さと同じ値だけズラす。
後処理
最後に次の壁ナンバーをセットしてループ終了!
テストする
動かしてみよう!
うぉぉぉぉぉ!立体的だぁぁぁ!できたかな?!おめでとう!
立体的な逃走中とか鬼ごっこ作りたい、マリカーみたいなの作りたい、なんならFPSっぽいシューティングゲーム作りたい、なんて創作意欲が目白押し間違い無しの3Dテクニック!どんどん作ってくれぃ!
まとめ
どうでしたか?できたかな?まだまだ精度は低いけど、必要十分な3D感は出てると思います。パフォーマンス面などで問題が残っているかもしれないけど、それは追々。
3Dゲームの作り方が需要ありそうなら、今回マジックナンバー使いまくりなのでリファクタリングとパフォーマンスチューニングのチュートリアルも作りたいなぁって思ってます。
ちなみに今回のテクニックはレイキャスティングと呼ばれている手法です。3Dを作るときはレイキャスティングとレイトレーシングという手法が主にあるのだけど、レイトレーシングは負荷が半端ないからスクラッチでは無理。レイキャスティングを極めていけば、それだけでも十分ハイクオリティな3Dゲームが作れるので問題ないです。
ちなみにレイトレーシングっていうのも体験してみたい!という人はマイクラがレイトレーシングにも対応したので設定してみるといいかも。3Dに興味ある人はぜひ。