「Flappy Bird」をUnity Visual Scriptingで作ってみよう(4/5)

障害物の生成とスコアのカウントアップ

Posted by 51n1 on 05 May, 2021

もくじ

1. Flappy Birdスタイルゲームを作成する
2. プレイヤーの移動とアニメーション
3. テキストの表示と背景のスクロール
4. 障害物の生成とスコアのカウントアップ
5. Script Graphまとめ

障害物を設置する

Box Collider 2D Rigidbody 2D

障害物となるSprite、ColumnSpriteをHierarchyウィンドウへドラッグ&ドロップで追加し、Sprite RendererコンポーネントのSorting LayerをMidgroundに変更する。( 4.1)

PositionのYを-4に変更。Box Collider 2Dを追加し、コライダーの幅を障害物となる柱の幅に合うように調整する。( 4.2)

4.1 Sorting Layer - ColumnSprite GameObject

4.2 Box Collider 2D - ColumnSprite GameObject

ColumnSpriteゲームオブジェクトを複製して2つ目のColumnSpriteゲームオブジェクトを作成する。InspectorよりTransformコンポーネントのRotationのZを180に変更し180度回転させる。また、PositionのYを8に変更し画面上の方に移動させる。

2つのColumnSpriteゲームオブジェクトをColumnsゲームオブジェクトにまとめる。Birdゲームオブジェクトの通過検出のためのBox Collider 2Dコンポーネントを追加し、物理的な挙動は不要なのでIs Triggerにチェックを入れる。コライダーのサイズは2つの障害物の間を覆うぐらいで位置はすぐ後ろ辺りに設置する。また、Rigidbody 2Dコンポーネントを追加し、Body TypeをKinematicに変更する。( 4.3)

ColumnsゲームオブジェクトにScript Machineコンポーネントを追加し、Columnという名前でScript Graphを設定する。( 4.4)

Columnsゲームオブジェクトにもう一つScript Machineコンポーネントを追加し、「 グラウンドとバックグラウンドをスクロールさせる」で作成したScrollingObject Script Graphを設定しておく。

4.3 Box Collider 2D and Rigidbody 2D - Columns GameObject

4.4 Column Script Graph - Columns GameObject

スコアのカウントアップ処理を設定する

Visual Scripting Prefab

チュートリアルビデオでは、障害物の柱を通過した場合のスコアのカウントアップの処理をGameControlスクリプトに実装していくのだが、ここではGameControllerゲームオブジェクトのGameControlスクリプトグラフとColumnsゲームオブジェクトに追加したColumnスクリプトグラフに分けて処理を追加していく。

まずはScene Variablesとしてint 型のscore変数を追加する。Birdが通過したかという判定にはタグを使う。あらかじめBirdゲームオブジェクトのタグとしてPlayerを割り当てておく。( 4.5, 4.6)

4.5 score - Scene Variable

4.6 Tag - Bird GameObject

ColumnスクリプトグラフにはOn Trigger Event 2Dユニットを始点としてTagがPlayerならCustom Event Triggerユニットを使ってGameControlスクリプトグラフに設定するCustom EventのScoreUpを呼び出すようにする。カスタムイベントの参照先となるGameControllerゲームオブジェクトはあらかじめScene Variablesとして設定しておく。( 4.7)

GameControlスクリプトグラフではCustom EventのScoreUpが呼び出されると、score変数に1を追加し、ScoreTextゲームオブジェクトのテキストをアップデートするフローが実行される。( 4.8)

4.7 Column Script Graph - Columns GameObject

4.8 Score Up - GameControl Script Graph

Columnスクリプトグラフの設定が完了したらColumnsゲームオブジェクトをPrefab化しておく。HierarchyウィンドウのColumnsゲームオブジェクトは必要ないので削除しておく。Prefab化した際にScript Graphで定義した一部の変数の参照が外れる場合があるので注意。( 4.9, 4.10)

4.9 Columns GameObject

4.10 Columns Prefab

Object Poolで障害物をリスポーンさせる

Visual Scripting Prefab

初心者にとってはここが今回のゲーム制作で少々苦労するところかもしれない。どちらかといえば、Object Poolという考え方はC#スクリプトでコーディングする方がすんなり理解できるだろう。理解するためにコードを丁寧に読む方がよい。だが、Object Poolという仕組みをVisual Scriptingで組み立てたScript Graphから読み取るというのはプログラミング初心者にはちょっとわかりづらい概念である。

Object Poolという仕組みを使わなくても障害物をランダムにリスポーンさせる方法はいくつか存在する。以前の記事「 Unity入門シューティングゲームをBolt化してみよう(3/6)」で作成したRock ControllerとRock Generatorのマクロのように同様の処理を実装することはできる。ただ、この方法ではPrefabでオブジェクトを生成して使用後に破棄したとしても、状況によっては最悪メモリを食い尽くしてしまう可能性がある。

ここからは僕の私見が入るので間違っているかもしれないがおおむね言いたいことは合っていると思う。正直なところ、僕にはOS側のメモリ管理がどうなっているのかということまではわからないのだが、UnityでDestroyの命令を出せば、OS側できちんとメモリ領域を解放してくれるのなら、これについて何も気にすることはないだろう。だが、もしOSがちゃんとメモリ解放してくれない場合、ゲーム実行中、ループで半永久的にオブジェクトを生成し続けた場合、メモリ領域を使い果たし、最悪OS自体のフリーズや強制終了という事態が発生する。

その最悪の状態を防止するというのがこのObject Poolという仕組みなのだと理解している。またパフォーマンス的にもこっちの方が良いらしい。半分ぐらい僕の想像でながながと書いてしまったが、Object Poolというのはあらかじめ決められた数のオブジェクトだけ生成してプールしておいて、ゲーム内ではその数以上は生成せずに、生成した数のオブジェクトだけを使い回しましょうということである。5つだけ生成すると定義しておけば、ゲーム実行中、5つ分のオブジェクトのメモリだけを考慮して使えば良いというとてもメモリに優しい処理だということになる。まあ、概念自体はとてもシンプルだが効率的な仕組みである。

ちょっと話しが脱線してしまったが、ゲーム作りに戻り、Object Poolの仕組みを実装してみたい。GameControllerゲームオブジェクトにもう一つScript Machineコンポーネントを追加し、ColumnPoolという名前でScript Graphを作成し、設定する。( 4.11)

Edit GraphボタンをクリックしてColumnPoolスクリプトグラフをScript Graphウィンドウに表示させる。まずは障害物のPrefabを格納するリストを作成する。Start EventユニットからFor Loopユニットをつなげて障害物のPrefabを5つリストに格納するグラフを組み立てる。ここではC#で言うところのprivate変数はGraph Variablesとして、public変数をObject Variablesとして定義し使用する。Visual ScriptingのObject VariablesはInspectorに表示させて値をInspectorで変更することができる。( 4.12)

4.11 ColumnPool Script Graph - GameController GameObject

4.12 Create Columns List - ColumnPool Script Graph

次にUpdate Eventユニットから処理を組み立てるのだが、このフローグラフは少し長くなってしまったので見ても良くわからないかもしれない。処理内容としては、Scene変数のgameOverがfalseの場合にリスポーン間隔として指定した秒数待って、先ほど作成したリストから障害物ゲームオブジェクトを1つ取得してその位置を再設定して表示させる。また、指定の秒数後に次のリストに登録されている障害物Prefabを同様に表示させる。その繰り返しで5つの障害物Prefabの位置を変えてループさせる。

まとめると、まずリスポーン可否のチェック処理を行い、リスポーン可ならPrefabからインスタンス化した障害物ゲームオブジェクトの位置を戻すという処理となる。( 4.13, 4.14)

4.13 Check whether column can respawn

4.14 Reposition a obstacle

リストのインデックス番号をカウントアップする。もし5以上なら0にリセットする。( 4.15)

4.15 Increment column index

ColumnPoolスクリプトグラフの全体の設定については「 Script Graphまとめ - ColumnPool Script Graph」を参照。

Flappy Birdスタイルゲーム完成

これでチュートリアルビデオで解説されているFlappy Birdスタイルのゲームの作成が完了である。障害物の高さについてはGameControllerゲームオブジェクトのInspectorからColumnMinとColumnMaxで調整できる。障害物の通り抜けられる隙間を広く取り過ぎたのでだいぶぬるいゲームとなっているが、隙間を狭めたり、SpawnRateを短くすると難易度を上げられるだろう。( 4.16)

4.16 Finished making a flappy bird style game

最後のページに各ゲームオブジェクトに設定したScript Graphをまとめてみたので必要に応じて参考にしてほしい。