はじめに
この記事ではUnity 2021から標準パッケージになったVisual Scriptingで、Chromeの恐竜(chrome://dino/)ライクなシンプルな横スクロールゲームを作成する方法を解説します。

この記事の対象としては、以下のような方を想定しています。
- Unityを少しでも触ったことがある方
- Visual Scriptingに興味がある方
環境
Unity 2021.2.6f1
Visual Scriptingとは
Visual Scriptingとは、コーディングの代わりにグラフを作成してプログラムを記述可能なシステムです。

これには以下のような利点があります
- 「なんとなく」で使えるため非エンジニアでも触りやすい
- C#で記述したプログラムと共存可能
- Play中にも処理を変更できるためプロトタイプ作成などにおいて素早くトライアンドエラーをまわせる
- 実行中の処理が可視化されるため、簡単な処理ならデバッグがしやすい
(↓実行中のグラフで、処理の流れが可視化されている&線上にそのフレームの値が表示されている)

この機能はUnity 2020まではBoltと呼称されていたパッケージでしたが、Unity2021から名前を変え標準パッケージとなりました。
そのため、Unity2021をインストールするだけで利用が可能です。
作るもの
今回の記事では、Visual Scriptingを使用して↓のような簡略版恐竜ゲームを作ります。
(白丸が恐竜、黄色長方形がサボテンだと読み替えてください。)

必要な機能
これを作る上で、まず最低限必要な機能を書き出してみます。
- 障害物が左に動く
- ボタン押下に応じてプレイヤーがジャンプ
- 数秒おきに障害物を生成
- スコア表示
- 死亡処理(スコアなどの停止)
なんとなく似たゲームができそうですね。
ただ、全て実装すると記事が長くなりすぎるので、今回は基礎として1と2を作るところを目標にします。
では、作っていきましょう。
実践
プロジェクトの作成
まずはプロジェクトの作成です。
- Unity Hubの新規作成から
Unity 2021.2.6f1を選択 - テンプレートに
2Dを選択して作成を選択
GameObjectの配置
ここで、先にGameObjectをある程度まとめて配置してしまいましょう。
今回のゲームの登場人物はプレイヤー、床、障害物の3つです。
今回は面倒なので工数削減のため、プレイヤーは白い丸、床は白い長方形、障害物は黄色の長方形で代用します。
プレイヤーの配置
- Hierarchyで右クリック -> 2D Object -> Sprites -> Circle をクリック
- GameObjectの名前をPlayerに変更
- Add ComponentでCircle Collider 2Dを選択
- Add ComponentでRigid Body 2Dを選択
床の配置
- Hierarchyで右クリック -> 2D Object -> Sprites -> Square をクリック
- GameObjectの名前をFloorに変更
- Add ComponentでBox Collider 2Dを選択
障害物の配置
- Hierarchyで右クリック -> 2D Object -> Sprites -> Square をクリック
- GameObjectの名前をTreeに変更
- Add ComponentでBox Collider 2Dを選択
- Spriteの色を黄色に変更(任意)
障害物の動きの作成
今回のゲームでは右から左に障害物が線形に移動していきます。
この動きをVisual Scriptingを用いて作成してみます。
コンポーネントのアタッチ
まず、TreeにAdd ComponentでVisual Scripting->Script Machineを選択してください。
(Boltを使ったことがある方はとりあえずScript Machine = Flow Machineだと思って大丈夫です。)

すると以下のような2つのコンポーネントがアタッチされます。

ここで、Script MachineコンポーネントのSourceという項の選択により、Script MachineコンポーネントはGraphとEmbedどちらかのモードを選択できます。
それぞれの違いは以下の通りです。
- Graph : グラフをファイルとして保存する。再利用可。
- Embed : グラフがコンポーネントに埋め込まれる。(基本的には)再利用不可。コンポーネントをRemoveするとグラフも消える。
基本的にはGraphを選択して一つ一つ保存した方が良いと思われますが、今回は説明の簡略化のためEmbedを使用します。
SourceにEmbedを選択するとTitleを付けられるようになるので、今回の機能としてTreeMovementと入力してください。

ちなみに、Convertを選択することでEmbedで作成したグラフを後からファイルに書き出すことも可能です。
(詳しくはこちらを参照してください)
グラフの作成
次に、Script MachineコンポーネントのEdit GraphをクリックしてScript Graphウィンドウを開きましょう。

最初に開いた時はウィンドウが小さく肝心のグラフが見えない場合があるので、その時は横幅を広げましょう。
このウィンドウの見方をざっくり解説すると以下のような感じです。
- 左上 : Graph Inspector
- 選択したグラフの詳細を表示
- 左下 : Blackboard
- 変数の管理
- 右 : グラフエディタ
- 実際に処理を記述する場所
最初は、基本右側を使うんだなくらいの認識で大丈夫です。
ノードの配置
では、実際にグラフを作成していきましょう。
まず、グラフ上で右クリックをしましょう。すると、ノードの作成ポップアップが開くと思います。
ここでいうノードとは、処理のひとかたまりだと考えて下さい。(C#でいう関数のようなもの)
↓ ノードの一例: Rigidbody.AddForce()

今回は左に移動してほしい、つまり障害物のポジションを移動させたいので、translateと入力し、Transform: Translate(X,Y,Z)を選択してください。(C#でいうtransform.Translate()と考えて大丈夫です)

すると以下のようになると思います。
この状態ではノードが何にもつながっていないため、処理が走りません。
次はこのノードを線でつないで処理を記述していきます。
処理の記述
ここでやりたいことは右から左へ位置を移動させる、つまり「毎フレーム -x 方向にポジションを移動させる」ことです。
毎フレーム行う処理を記述する場合、On Updateイベントを用います。(C#でいうUpdate()です。)
今回は、On UpdateイベントからTranslateノードを繋ぎます。
こうすることで毎フレームTranslateノードの処理が呼ばれることになります。
また、左方向に移動させたいのでXにマイナスの数値を入力しましょう。

この状態でPlayすれば、Treeというオブジェクトがひとまず左に動いてくれるはずです。
(上記の状態だとフレームレートによってTreeが動く速度が変わってしまうため、最終的には以下のようにdeltaTimeを乗算しましょう。)

プレイヤーのジャンプ
障害物の動きが出来たところで、キーの押下に応じてプレイヤーがジャンプする動きを実装します。
ここで、プレイヤーは接地状態、ジャンプ状態という2つの状態を行き来する、とも考えられます。
それぞれの状態は以下の通りです
- 接地状態 : キーを押下でジャンプ状態へ移行する。
- ジャンプ中 : この状態に入った瞬間上方向に飛び上がる。床に触れた時接地状態へ移行する。
この状態遷移を簡単に実現できる機能がState Machineです。
今回はこのState Machineを用いてジャンプを実装します。
コンポーネントのアタッチ
ではさっそくState Machineを作成しましょう。
Playerオブジェクトを選択して、Add ComponentからState Machineを選択してください。
ここでもSourceにGraphかEmbedを選べますが、今回は例によってEmbedを選択し、TitleにJumpableと入力してください。

State Machineについて
ここでEdit Graphを押すと以下のような画面が出るはずです。

画面構成は基本Script Machineと同じですが、右側が状態遷移図となっています。
この状態遷移図の"状態"とは、Script Machineのことだと考えてもらって大丈夫です。
ここで、中央のStartをクリックすると先程のScript Machineの編集画面と似たものが出てきたのがわかると思います(下図)。

状態の作成
それでは、状態を作っていきましょう。
まず、右クリック->Create Script State を選択して、TitleにJumpingと入力します。
また、初期状態であるStartの名前を変更してGroundedとします。

これで、ジャンプ中の状態Jumpingと接地中の状態Groundedが作成できました。
遷移の作成
次に、遷移を作成していきます。
Groundedを右クリック->Make Transitionで矢印をJumpingにつなげます。
同様にJumpingからGroundedへも矢印をつなげます。

しかし、線をつないだだけでは”なにがあったら状態が変わるか”が記述できていません。
次は、この遷移条件を記述します。
遷移条件
まず、GroundedからJumpingへの遷移を作成しましょう。
今回はGroundedからJumpingへの遷移条件は、「何かのキーが押された」こととします。
GroundedからJumpingへの遷移の間にある黄色の6角形をダブルクリックしましょう。
すると以下のような画面が出るはずです。

次にOn Updateノード、Input Get Any Keyノード、Ifノードを作成し、以下のようにつないでください。

これで、「Grounded状態で何かのキーが押されていたらJumping状態へ遷移する」という処理になります。
次は、JumpingからGroundedへの遷移を作成しましょう。
今回はJumpingからGroundedへの遷移条件は、「Floorという名前のオブジェクトと接触した」こととします。
上と同様に今度はJumpingからGroundedの遷移の間にある黄色の6角形をダブルクリックし、以下のようなグラフを作成してください。

これで、「Jumping状態でFloorという名前のオブジェクトと接触したらGrounded状態へ遷移する」という処理になります。
ジャンプ処理
遷移も記述できたところで、肝心のジャンプ処理を記述していきましょう。
ジャンプ処理は、今回「Jumping状態に入った瞬間、上方向に力をかける」ことで実現します。
では、早速Jumpingをダブルクリックして以下のように処理を記述しましょう。
ここで、On Enter Stateは「この状態に入った直後に発火するイベント」、On Exit Stateは「この状態から出る瞬間に発火するイベント」です。

なお、このままでは上に飛ぶ力が強すぎるかもしれません。
その場合、Add ForceノードのForce値や、Rigidbody2DのGravity Scaleを調整しましょう。
(記事の上の方で貼った動作例ではRigidBody2DのGravity Scaleを10にしています。)
これで、プレイヤーのジャンプは実現できました。
今回の例ではState Machineをそれほど活用できていませんが、最終的には各状態でAnimationの管理を行ったり、状態を増やしてより多彩な処理を行ったりということが可能です。
まとめ
今回はVisual Scriptingを用いたシンプルな横スクロールゲームの制作方法を紹介しました。
Visual Scriptingを用いてノードをつないだグラフを作成することで、わかりやすく簡単に、障害物を動かしたりプレイヤーをジャンプさせたりできました。
Visual Scriptingでは、処理をグラフィカルに見ることができるため非エンジニアでもわかりやすい点や、素早くトライアンドエラーがまわしやすい点などがメリットとして挙げられます。
また、今回紹介したState Machineはゲーム制作の上で色々な応用が考えられる強力な機能だと思います。
今回使用していない機能(カスタムイベント・サブグラフなど)も沢山あるので、興味があれば調べてみて下さい。
「Visual Scripting使ったことないけどどういうものか気になる!」と思っている方がこの記事を読むことで「Visual Scriptingなんとなくわかったぜ!」となっていれば幸いです。
最後に
この記事は サムザップ Advent Calendar 2021 の12/16の記事です。
昨日の記事は @ozaki_shinya さんによるUnityでシーン遷移時にパラメーターを渡す方法でした。
明日は@higuchi_yutaさんの「【Unity】ATBシステムにおける新ルールの実装コストを削減した設計」です。


