もくじ
まず最初に断っておきたいのだが、本記事で記載しているVisual Scriptingでステータス管理する手法についてはゲームデザイン的に良い見本ではないと思う。なのでこのようなやり方もあるんだなという気持ちで見て頂きたい。正直なところ、場当たり的にVisual Scriptingで実装してしまったので機能がバラバラに散らばってしまっている。本来、フローを見直すべきだろうが、ゲーム開発の学習者の作るカオスの見本として認識頂けるとちょうど良いだろう。
フリーフォントの入手・変更
ゲームタイトルやスコアテキストのフォントの種類を変更する。今回、Google Fontsから「 Bowlby One SC」をチョイスした。( 3.1)
Google Fontsページ内の「Download」ボタンをクリックし、Bowlby_One_SC.zipファイルをダウンロードしたら適当な場所に展開し作成された.ttfファイルをUnity EditorのAssetsフォルダへインポートする。( 3.2)
UI Textのフォントの変更はInspectorウィンドウからTextコンポーネントのCharacter → Fontプロパティの設定で変更する。今回、元々設定されていたフォントと比較するとデザインはあまり変わらないかもしれない。( 3.3)
ゲームステータス切り替えの下準備
現在の設定ではゲームが始まるとプレイヤーはすぐにプレイをスタートする必要がある。ゲームがスタートしてもプレイヤーがリアクションするまで待機できるようにしたい。
ゲームスタート時のタイトル画面を作成するには、タイトル画面用にもう一つシーンを作成してシーン切り替えでタイトル画面からプレイ画面へ切り替えるという方法もあるが、今回は、同一シーン内でタイトル画面からプレイ画面への切り替えを実装したい。
他に良い表現が思いつかなかったので、本記事ではそれぞれの場面のことを画面とかシーンと表わすことがあるかもしれないが、今回作成しているゲームはあくまでもUnityで言うところの1つのScene上に構成されているので注意したい。その1つのScene内でVisual Scriptingなどによって各ゲームオブジェクトの設定を変え、疑似的に各画面・シーンの切り替えを行うようにする。
ゲームタイトルの追加
ゲームタイトルを追加する。スコアテキストなどと同様にUI Textを追加してInspectorウィンドウでフォントサイズやカラー、種類などを変更する。Textプロパティにゲームタイトルを入力する。Shadowコンポーネントを追加してテキストに影を付けても良いだろう。( 3.4, 3.5)
Visual ScriptingとEnumによるゲームステータス管理
シーン切り替えにはいくつか方法があると思う。前述したが、タイトル画面用にもう一つシーンを追加して、まさしくシーン切り替えをする方法や最近のUnityではTimelineを使う方法もあると思う。今回は、EnumとVisual Scriptingを使い、以下の3つのステータスを管理することにしたい。
- Readyステータス (タイトル画面)
- Playステータス (プレイ画面)
- Deadステータス (ゲームオーバー画面)
Enumで3つのステータスを定数として定義し、Visual Scriptingで3つのステータスをゲームプレイの進行状況に合わせて遷移できるようにする。本当はVisual ScriptingのState Machineを使えば、もっとスマートにステータスの管理ができたと思うのだが、今回は、Script Machineだけで実装する。カスタマイズ前の古い変数フラグ等をそのまま残しているので、見た目上、若干ステータス管理がカオスになってしまっている。
Visual ScriptingとEnumの定義・参照・設定
現在、Visual Scriptingの内部にはEnumを定義する機能がない。そのため、厳密にはコードレスではなくなってしまうが、C#スクリプトを作成しEnumの定義ファイルを作成する。AssetsフォルダにScriptsフォルダを作成し、birdStateという名前で新規にC#スクリプトを作成する。( 3.6)
birdStateスクリプトをコードエディタで開き、3つのステータス(Ready, Play, Dead)を定義するコードを追加する。( 3.7)
一度定義すれば、Enumの変数をVisual Scriptingから利用できるようになる。Scene Variablesとして名前をstate、TypeをBird Stateという変数を追加する。Valueをクリックすれば、3つのステータスを選ぶことが可能である。( 3.8)
また、Visual Scripting内でのEnum変数の使い方だが、単に参照したい場合は、普通にGet Variableユニットを使えばよい。( 3.9)
一方、変数に別のステータスを設定したい場合は、Set Variableユニットを使うのだが、定義したEnumクラスをVisual Scriptingのユニットとして利用できるように設定する。メニューからEdit → Project Settings → Visual Scripting → Type Optionsを表示させて、「+」ボタンをクリックして「Bird State」をクリックする。その後、Regenerate Unitsボタンをクリックし、反映させる。( 3.10, 3.11)
前述のプロジェクトの設定を行うことでVisual ScriptingでBird StateのLiteralノードを追加でき、Set Variableユニットに好きなステータスを容易にセットすることができるようになる。( 3.12, 3.13)
また、ステータスによって処理を分岐させたいときは、Switch On Enumユニットというノードを使う。Enumの値によって処理を分岐させることが可能である。( 3.14, 3.15)
各ゲームステータスをVisual Scriptingで実装する
ここから「Readyステータス (タイトル画面)」、「Playステータス (プレイ画面)」、「Deadステータス (ゲームオーバー画面)」の3つのステータスに合わせて必要な処理をVisual Scriptingで実装していく。
タイトル画面=Readyステータスの処理フロー
タイトル画面ではプレイヤーがクリックしない限り、BirdゲームオブジェクトがJumpしないようにしたい。Bird Script Graphにステータスの判定処理を入れる。state変数がPlayステータス以外の場合はJumpできないように設定する。( 3.16) ※画像内の赤枠が変更範囲を示す。
また、Birdゲームオブジェクトは通常、重力によって下方に移動してしまうが、タイトル画面では静止状態にしておきたい。後続の処理を考慮し、ここではBirdゲームオブジェクトのY座標を常に初期値に設定するように実装する。まず、BirdゲームオブジェクトのY座標を格納する変数startPosYを作成し、Start Event後の処理フローでstartPosYにY座標を保存させる。
次にstate変数がReadyステータスの場合、startPosY変数で保存したY座標の値をBirdゲームオブジェクトに代入しBirdゲームオブジェクトを静止状態にする。( 3.19)
3.19 Ready - Bird Script Graph
Birdゲームオブジェクトを静止状態にしてしばらく放置していると見た目は何も衝突していないはずなのになぜかCollisionを検知してゲームオーバーになってしまうバグのような現象が発生した。
原因がはっきりとはつかめなかったのだが、BirdゲームオブジェクトのRigidbody 2DコンポーネントのBody TypeをDynamicにした状態でVisual Scripting側のTransform Positionによる座標操作を行うと何かしらの不整合が発生する可能性が考えられた。バグ回避のため、Body TypeをKinematicに変更した。( 3.20)
3.20 Rigidbody 2D Component - Bird GameObject
別途、state変数がPlayステータスに変更になるタイミングでBody TypeをKinematicからDynamicに戻す処理を追加する必要があるので覚えておく。
次に障害物の移動処理を抑制する。ColumnPool Script Graphで障害物のリストの初期設定とリスポーンの管理をしている。今のところは、これらはゲームがスタートするとこのプロセスも自動で開始される。そのため、これらのプロセスを自動で開始されないように変更する。Update Eventのリスポーン処理についてはstate変数の判定処理を入れて、Playステータス時のみ動くようにする。( 3.21)
障害物のリストの初期設定については任意のタイミングで実行するようにしたいので元々設定していたStart Eventを削除し「CreateColumnsList」という名前でCustom Eventを設定しておく。後でPlayステータスに移行するタイミングでこのイベント処理を呼び出す。以上の設定でタイトル画面のためのVisual Scriptingの処理の実装が完了する。( 3.22)
ReadyステータスからPlayステータスへの遷移
ReadyステータスからPlayステータスへ遷移する時、すなわち、タイトル画面からプレイ画面へ移り変わる時の処理フローを適宜、Visual Scriptingで組み込む。まずはGameControllerゲームオブジェクトにアタッチされているGameControl Script Graphにノードを追加していく。
GameControl Script GraphのUpdate Event部分にstate変数の判定処理を追加する。そして、state変数がDeadステータスの場合、Restart処理フローに分岐させる。( 3.23)
次にstate変数がReadyステータスの場合の処理フローを追加する。これがゲームスタート時の処理フローになる。処理フローの流れをリスト化する。( 3.25)
- マウスボタンのクリックを判定する
- StartText(タイトル文字)を無効化する
- BirdゲームオブジェクトのBody TypeをDynamicに変更する
- state変数にPlayステータスをセットする
- Custom EventのTriggerユニットを追加し、「CreateColumnsList」イベントを呼び出す
StartTextゲームオブジェクトとBirdゲームオブジェクトについては参照用としてObject Variablesを作成し設定しておく。( 3.24)
3.25 Start Game Flow - GameControl Script Graph
PlayステータスからDeadステータスへの処理を追加する
Bird Script Graphのゲームオーバー処理にstate変数をDeadステータスに変更する処理ノードを追加する。これで基本的なゲームステータスの処理については実装が完了となる。( 3.26)
3.26 Game Over Flow - Bird Script Graph
タイトル画面のBirdゲームオブジェクトをカスタマイズ
ゲームタイトルを表示している間、Birdゲームオブジェクトを上下に動かしたい。AnimatorとAnimationを使って実装しようとしたがなぜかTransformコンポーネントのPositionプロパティをAnimation側で変えてしまうとそれ以降、スクリプト等で操作がうまくいかなかった。
解決策がないか探したのだけれど、Animationを使った方向での対処策が見つからなかった。そのほかの対処策としてネットで下記のコードを見つけたので、それをベースにVisual Scriptingで実装してみた。
public class BaloonController : MonoBehaviour
{
public float MovingDistance = 20;
private float StartPos;
void Start()
{
StartPos = transform.position.y;
}
void Update()
{
transform.position = new Vector3(
transform.position.x,
StartPos + Mathf.PingPong(Time.time*2f, MovingDistance),
transform.position.z
);
}
}
Bird Script GraphのReadyの処理フロー内でMathf.PingPongという便利なメソッドを使って、Birdゲームオブジェクトの上下動を実現する。( 3.27)
3.27 Ready Flow - Bird Script Graph
これで今回のカスタマイズについては完了である。もしゲームデザインはあまり変えずにさらにカスタマイズするとすれば、他にはハイスコアを保存できるようにしたり、パーティクルエフェクトを追加するぐらいだろうか。Unity Editor上のゲームプレイビデオを下記に載せておくが、「 Space Flying Bird」では実際のゲームをWebGLで公開しているので参考にしてほしい。( 3.28)
3.28 完成ゲームプレイビデオ
次のページでは最後にカスタマイズ後のScript Graphをまとめておきたい。