概要
Logic Toolkitを使用して簡単なブロック崩しゲームを作成する方法を紹介します。
完成品はLogic Toolkitの同梱サンプル「BlockBreaking」と同様の内容になっています。
前提知識
- Unityエディタの基本的な使い方
学習内容
- オブジェクトの挙動制御にLogic Behaviorコンポーネントを使用する
- 共通の挙動を使いまわすにはLogic AssetとLogic Playerコンポーネントを使用する
- シンプルな機能であれば、メンバーアクセスのスクリプト生成機能によりコーディング作業を挟まずに挙動が組める
- Actionノード、Stateノード、Branchノード(フロー制御)などがグラフ内に混在できる
- Stateの遷移条件判定をSignal Evaluationノードで共通化できる
- Blackboardの変数で値を共有できる
- BlackboardのData Link機能により複数のオブジェクト間で変数を共有できる
撮影環境
このチュートリアルの画像および動画は以下の環境で撮影しています。
OS | Windows 11 |
Unity | 6000.0.0f1 |
Logic Toolkit | 1.0.0 |
テーマ | ダーク |
言語 | 英語 |
- Unity内の最低限のウィンドウのみ撮影しています
- 作成したノードの配置調整などについての説明は省略しています
プロジェクトの準備
チュートリアルを実践するプロジェクトを作成してください。
プロジェクトの作成
チュートリアル用にプロジェクトを作成します。
プロジェクト名 | LogicToolkit_Tutorial_BlockBreaking |
テンプレート | 3D (Built-In Render Pipeline) |
テンプレートが未ダウンロードの場合はダウンロードも行ってください
プロジェクトの作成方法については、Unityマニュアルの「Add and remove projects in the Unity Hub」を参照してください。
Logic Toolkitの導入
Logic Toolkitをプロジェクトに導入します。
Logic Toolkitの導入については、Logic Toolkitマニュアルの「導入手順」を参照してください。
チュートリアル用パッケージのインポート
ブロック崩しのオブジェクトを配置したシーンを予め作成したパッケージを用意しています。
“Tutorial_BlockBreaking” をダウンロード
LogicToolkit_Tutorial_BlockBreaking.unitypackage – 138 回のダウンロード – 14.60 KB上記リンクからパッケージをダウンロードしてプロジェクトにインポートしてください。
パッケージのインポート方法についてはUnityマニュアルの「ローカルアセットパッケージのインポート」を参照してください。
シーンを開く
- Assets/BlockBreaking/Scenes/BlockBreakingシーンを開く
Playerの挙動作成
Player(水色のパドル)の挙動を作成します。
パドルをADキーや左右キーで移動する挙動をLogic Behaviorコンポーネントを使用して実装します。
PlayerにLogic Behaviorの追加
- Playerオブジェクトを選択
- InspectorウィンドウのAdd Componentボタンをクリック
- コンポーネント追加メニューからLogic Toolkit/Logic Behaviorを選択してLogic Behaviorコンポーネントを追加
- Logic BehaviorのEditボタンをクリックし、Logic Editorウィンドウを開く
PlayerのLogic Behaviorを編集
Input.GetAxis("Horizontal")
による水平軸入力から移動速度を計算しRigidbody.linearVelocity
に代入することで、パドルの移動を実装します。
Updateノードの作成
- Startノードを削除する
- グラフ上をクリックしフォーカスがある状態で
Spaceキー
を押し、ノード作成メニューを開く - Scriptsタブを選択
- 一覧からEvents/Updateを選択してUpdateノードを作成
Rigidbody.linearVelocityの設定ノードの作成
Logic Toolkitのスクリプト生成機能を使用してメンバーにアクセスします。
- Updateノードの実行ポートをノードの右側付近にドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Rigidbody linearVelocity
と入力 - 一覧から
UnityEngine.Rigidbody
のlinearVelocity [Set]を選択 - ノードの種類選択メニューからActionを選択
Membersタブでメンバーのアクセススクリプトを作成した際に、まだスクリプト生成用のアセンブリが作成されていない場合は新規作成されます。
アセンブリが[Unselected]のままノードを作成した場合の名前はデフォルトのLogicToolkitGeneratedScripts
になります。
アセンブリのドロップダウンをクリックしメニューからCreate New Assemblyを選択すると、任意の名前のアセンブリを作成可能です。
またアセンブリ名の変更は非推奨です。
後から変更するとスクリプトの参照切れが発生するため、間違いのないように気を付けてください。
通常はデフォルトの名前で問題ありません。
サンプルのBlockBreakingではインポートした際の重複を避けるためにBlockBreaking_GeneratedScripts
という名前にしています。
スクリプト生成用のファイルはAssets/Logic Toolkit/Generated Scripts/アセンブリ名フォルダに作成されます。
基本的にスクリプト生成用のファイルを直接変更する必要はありません。
new Vector3ノードの作成
- Linear Velocityフィールドの入力ポートを左側付近にドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
new Vector3
と入力 - 一覧から
UnityEngine.Vector3
のnew Vector3(float x, float y, float z)を選択 - ノードの種類選択メニューからComputeを選択
Float Mulノードの作成
- Xフィールドの入力ポートを左側付近にドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
Float Mul
と入力 - 一覧からFloat Mul (Compute)を選択
Float Mulノードの編集
移動速度を5
に設定します
- Value 2フィールドの数値を
5
に設定
Input.GetAxisノードの作成
- Float MulノードのValue 1フィールドの入力ポートを左側付近にドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Input GetAxis
と入力 - 一覧から
UnityEngine.Input
のGetAxis(string axisName)を選択 - ノードの種類選択メニューからComputeを選択
Input.GetAxisノードの編集
水平入力を出力するように設定します。
- Axis Nameフィールドの文字列を
Horizontal
に設定
Speedの変数化(任意)
移動速度をFloat Mulに直接記述していると、後から見返す際にどこに速度を記述しているかが分かりにくいため、このような数値はブラックボードの変数にしておくと良いです。
- サイドパネルのBlackboardタブを選択
- Rootタブを選択
- +ボタンをクリックし、型選択メニューを開く
- 一覧からPrimitive/floatを選択
- 名前を
Speed
に設定 - 数値を
5
に設定 - Speed変数をグラフのFloat MulのValue 2フィールド付近にドラッグ&ドロップし、ノード作成メニューを開く
- Get Variable (Compute)を選択
- Speed取得ノードの出力ポートからFloat MulのValue 2フィールドの入力ポートへドラッグ&ドロップして接続
Playerの挙動確認
プレイ開始してPlayer(水色のパドル)の挙動を確認します。
Aキー
か左矢印キー
で左に移動することを確認Dキー
から右矢印キー
で右に移動することを確認- 壁に当たったら停止することを確認
Ballの挙動作成
Ballの挙動を作成します。
開始時にボールを斜め方向に移動開始し、Playerと衝突時には接触位置によって跳ね返り方向を調整する処理を実装します。
BallにLogic Behaviorの追加
- Player/Ball SocketsにあるBallオブジェクトを選択
- InspectorウィンドウのAdd Componentボタンをクリック
- Logic Toolkit/Logic Behaviorを選択してLogic Behaviorコンポーネントを追加
- Logic BehaviorのEditボタンをクリックし、Logic Editorウィンドウを開く
BallのLogic Behaviorを編集
Transform.SetParentノードの作成
後々キー操作によって移動開始を行うようにするため、初期状態ではPlayerと連動して動く設定になっています。
移動開始した際にPlayerの子からルート直下に変更するためTransform.SetParent
で親オブジェクトを変更します。
- Startノードの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Transform SetParent
と入力 - 一覧から
UnityEngine.Transform
のSetParent(Tranform parent, bool worldPositionStays)を選択 - ノードの種類選択メニューからActionを選択
Transform.SetParentノードの編集
- ParentフィールドのモードをValueに変更
- World Position Staysフィールドにチェック
Rigidbody.isKinematicノードの作成
初期状態ではRigidbodyのIs Kinematicが有効になっています。
ボールは移動開始と同時に壁やブロックなどに当たった際に物理的な反射を行ってほしいため、Is Kinematicを無効に切り替えます。
- Transform.SetParentノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Rigidbody isKinematic
と入力 - 一覧から
UnityEngine.Rigidbody
のisKinematic [Set]を選択 - ノードの種類選択メニューからActionを選択
デフォルトでIs Kinematicフィールドのチェックが外れているため、設定を変更する必要はありません。
Rigidbody.linearVelocityノードの作成
- Rigidbody.isKinematicノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- Actions/LogicToolkitGeneratedScripts/UnityEngine/Rigidbody/Set Rigidbody.linearVelocity (Action)を選択
Set Rigidbody.linearVelocityスクリプトはPlayerの挙動作成で作成済みのため、Scriptsタブからも選択できるようになっています。
もちろんMembersタブで同じメンバーを選択しても同じスクリプトが使用されますので、お好みで使い分けてください。
Vector3.operator *ノードの作成
- Rigidbody.linearVelocityノードのLinear Velocityフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
*
と入力 - 一覧から
UnityEngine.Vector3
のoperator *(Vector3 a, float d)を選択 - ノードの種類選択メニューからComputeを選択
Vector3.operator *ノードの編集
- Dフィールドの値を
8
に設定
Vector3.normalizedノードの作成
- Vector3.operator *ノードのAフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
normalized
と入力 - 一覧から
UnityEngine.Vector3
のnormalized [Get]を選択 - ノードの種類選択メニューからComputeを選択
Vector3.normalizedノードの編集
- TargetフィールドのX値を
1
に設定 - TargetフィールドのY値を
1
に設定
new Vector3
ノードを作成する必要なくフィールドに固定値を直接設定できます。
グループをまとめる(任意)
開始直後に斜め方向に移動開始する挙動を実装できました。
Startノードから繋がるノードをグループノードでまとめてみましょう。
- Startノードから繋がるノードのみをすべて選択した状態で、
Gキー
を押しグループノードを作成 - グループノード名を
Start moving the ball
に変更 - グループノードをマウスオーバーした際に表示される
...
アイコンをクリック - コメントに
The ball begins to move when play begins.
と入力
PubOnCollisionEnter.Callbackノードの作成
ここからはPlayerに接触した場合にパドルとボールの位置関係から反射方向を調整する処理を実装します。
- Startノードよりも下の方で
Spaceキー
を押し、ノード作成メニューを開く - Membersタブを選択
- 検索欄に
OnCollisionEnter Callback
と入力 - 一覧からの
LogicToolkit.Builtin.Messages.PubOnCollisionEnter
のCallbackを選択 - ノードの種類選択メニューからEventを選択
LogicToolkit.Builtin.Messages名前空間の型はMonoBehaviorのメッセージが呼ばれた際に、UnityEventを介して他のメソッドを呼び出すための組み込みコンポーネントです。
今回はOnCollisionEnter(Collision)メッセージをLogic Toolkitのイベントとして受け付けるように使用しています。
PubOnCollisionEnter.Callbackノードの編集
- TargetフィールドのRequireをチェック
TargetフィールドはInputComponent<PubOnCollisionEnter>
型のフィールドです。
Requireフィールドにより、対象オブジェクトに該当コンポーネントがない場合に追加してから取得する機能が備わっています。
今回はRequireをチェックするため、自オブジェクト(Ball)にPubOnCollisionEnterコンポーネントを追加していなくても実行時に追加するようなります。
オブジェクトの用途によってはその都度追加する分の処理負荷が問題になる場合もあります。
事前にオブジェクトにコンポーネントを追加しておくかどうかは検討したほうが良いでしょう。
Collision.gameObjectノードの作成
- PubOnCollisionEnter.CallbackノードのArg 0フィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 一覧からCollision/gameObject [Get]を選択
- ノードの種類選択メニューからComputeを選択
GameObject.CompareTagノードの作成
- Collision.gameObjectノードのGame Objectフィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 一覧からGameObject/CompareTag(string tag)を選択
- ノードの種類選択メニューからComputeを選択
GameObject.CompareTagノードの編集
- Tagフィールドの文字列を
Player
に設定
Branchノードの作成
- GameObject.CompareTagノードのResultフィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からFlow Controls/Branchを選択
Branchノードへの接続
- PubOnCollisionEnter.Callbackノードの実行ポートからBranchノードの入力ポートにドラッグ&ドロップして接続
Rigidbody.linearVelocityノードの作成
- BranchノードのTrueフィールドの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
Rigidbody linearVelocity
と入力 - 一覧からSet Rigidbody.linearVelocity (Action)を選択
Vector3.operator *ノードの作成
- Rigidbody.linearVelocityノードのLinear Velocityフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
*
と入力 - 一覧からVector3.operator *(Vector3 a, float d) (Compute)を選択
Vector3.operator *ノードの編集
- Dフィールドの数値を
8
に設定
Vector3.normalizedノードの作成
- Vector3.operator *ノードのAフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
normalized
と入力 - 一覧からGet Vector3.normalized (Compute)を選択
Vector3.operator -ノードの作成
- Vector3.normalizedノードのTargetフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
-
と入力 - 一覧から
UnityEngine.Vector3
のoperator -(Vector3 a, Vector3 b)を選択 - ノードの種類選択メニューからComputeを選択
Transform.positionノードの作成
- Vector3.operator -ノードのAフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Transform position
と入力 - 一覧から
UnityEngine.Transform
のposition [Get]を選択 - ノードの種類選択メニューからComputeを選択
Collision.transformノードの作成
- PubOnCollisionEnter.CallbackノードのArg 0フィールドの出力ポートを先ほど作成したTransform.positionノードよりも下側へドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 一覧からCollision/transform [Get]を選択
- ノードの種類選択メニューからComputeを選択
Transform.positionノードをもう一つ作成
- Collision.transformノードのTransformフィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
position
と入力 - 一覧から
UnityEngine.Transform
のposition [Get]を選択 - ノードの種類選択メニューからComputeを選択
データポートの接続
- Vector3.operator -ノードのBフィールドの入力ポートから最後に作成したTransform.positionノードのPositionフィールドの出力ポートにドラッグ&ドロップして接続
グループにまとめる(任意)
OnCollisionEnterから繋がるノードをグループノードでまとめましょう。
- PubOnCollisiionEnter.Callbackノードから繋がるノードのみをすべて選択した状態で、
Gキー
を押しグループノードを作成 - グループノード名を
OnCollisionEnter
に変更 - グループノードをマウスオーバーした際に表示される
...
アイコンをクリック - コメントに
Correct the bounce direction when the Ball hits the Player
と入力
Speedの変数化(任意)
Playerと同様移動速度を変数化しておくと後々便利です。
- サイドパネルのBlackboardタブを選択
- Rootタブを選択
- +ボタンをクリックし、型選択メニューを開く
- 一覧からPrimitive/floatを選択
- 名前を
Speed
に設定 - 数値を
8
に設定 - Speed変数をグラフのStartノード側のVector3.operator *ノードのDフィールド付近にドラッグ&ドロップし、ノード作成メニューを開く
- Get Variable (Compute)を選択
- Speed取得ノードの出力ポートからVector3.operator *ノードのDフィールドの入力ポートへドラッグ&ドロップして接続
- OnCollisionEnter.Callbackノード側にも同様にVector3.operator *ノードのDフィールド付近にドラッグ&ドロップし、ノード作成メニューを開く
- Get Variable (Compute)を選択
- Speed取得ノードの出力ポートからVector3.operator *ノードのDフィールドの入力ポートへドラッグ&ドロップして接続
Ballの挙動確認
プレイ開始してBallの挙動を確認します。
- プレイ開始と同時に右上方向に移動開始することを確認
- Player(水色のパドル)に当たった場合、当たった位置によって反射角度が異なることを確認
- パドルの左側に当たった場合は左方向に反射
- パドルの右側に当たった場合は右方向に反射
Blockの挙動作成
Blockの挙動を作成します。
Blockは何かが当たった場合に自オブジェクトを破棄する挙動とします。
今回はボール以外に当たるものがないため、当たった対象の判定は省きます。
Blockオブジェクトはプレハブとして用意しており、オブジェクトを使いまわす想定になっています。
ここでは直接Logic Behaviorを使用せず、Logic AssetをLogic Playerで再生する形式で挙動の使いまわしも行ってみましょう。
アセットの作成
Logicフォルダの作成
Logic Toolkit関連アセットの保存先フォルダを作成します。
名前は何でもよいですが、今回はLogic
というフォルダを作成することにします。
- ProjectウィンドウのBlockBreakingフォルダを選択
- +ボタンをクリック
- メニューからFolderを選択
- 名前を
Logic
に変更
Logic Assetの作成
- ProjectウィンドウでLogicフォルダを選択
- +ボタンをクリック
- メニューからLogic Toolkit/Logic Assetを選択
- 名前を
Block Logic
に変更 - Logic AssetのEditボタンをクリックし、Logic Editorウィンドウを開く
Block Logicの編集
PubOnCollisionEnter.Callbackノードの作成
- Startノードを削除
- グラフ上をクリックしフォーカスがある状態で
Spaceキー
を押し、ノード作成メニューを開く - Scriptsタブを選択
- 検索欄に
OnCollisionEnter Callback
と入力 - 一覧からPubOnCollisionEnter.Callback (Event)を選択
PubOnCollisionEnter.Callbackノードの編集
- TargetフィールドのRequireをチェック
GameObject.Destroyノードの作成
- PubOnCollisionEnter.Callbackノードの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
Destroy
と入力 - 一覧からGameObject.Destory(gameObject) (Action)を選択
UnityのDestroyメソッドはObject.Destroy(Object)
なのですが、InputGameObject
でSelfオブジェクトも指定できたほうが便利なため、組み込みとしてGameObject.Destroy(GameObject)を行うスクリプトを用意しています。
グループにまとめる(任意)
- 作成した2つのノードをすべて選択した状態で、
Gキー
を押しグループノードを作成 - 名前を
OnCollisionEnter
に変更 - グループノードをマウスオーバーした際に表示される
...
アイコンをクリック - コメントに
If this block is hit by something (only the ball this time), it will destroy itself.
と入力
BlockにLogic Playerを設定
Blockをプレハブモードで開く
- ProjectウィンドウのAssets/BlockBreaking/Prefabs/Blockプレハブをダブルクリック
Logic Playerを追加
- HierarchyウィンドウのBlockオブジェクトを選択
- InspectorウィンドウのAdd Componentボタンをクリック
- コンポーネント追加メニューからLogic Toolkit/Logic Playerを選択し、Logic Playerコンポーネントを追加
Logic Playerコンポーネントの編集
- AssetフィールドにBlock Logicを設定
プレハブモードの終了と保存
- Hierarchyのプレハブのヘッダ部の<ボタンをクリック
- 保存するかのダイアログが表示されるのでSaveボタンをクリック
Blockの挙動確認
プレイ開始してBlockの挙動を確認します。
- Ballが当たった際にBlockオブジェクトが破棄されることを確認
ゲームクリア判定の作成
Blockオブジェクトがすべて破壊できた場合はゲームクリアとします。
BlockオブジェクトはBlocksオブジェクトの子にすべて配置していますので、Blocksオブジェクトの子オブジェクト数が0の場合にクリアとしましょう。
BlocksにLogic Behaviorの追加
- Blocksオブジェクトを選択
- InspectorウィンドウのAdd Componentボタンをクリック
- Logic Toolkit/Logic Behaviorを選択してLogic Behaviorコンポーネントを追加
- Logic BehaviorのEditボタンをクリックし、Logic Editorウィンドウを開く
BlocksのLogic Behaviorを編集
Int Equalsノードの作成
- Startノードを削除
- グラフ上をクリックしフォーカスがある状態で
Spaceキー
を押し、ノード作成メニューを開く - Scriptsタブを選択
- 検索欄に
Int Equals
と入力 - 一覧からInt Equals (Event)を選択
Transform.childCountノードの作成
- Int EqualsノードのValue 1フィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Transform childCount
と入力 - 一覧から
UnityEngine.Transform
のchildCount [Get]を選択 - ノードの種類選択メニューからComputeを選択
GameObject.SetActiveノードの作成
- Int Equalsノードの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
GameObject SetActive
と入力 - 一覧から
UnityEngine.GameObject
のSetActive(bool value)を選択 - ノードの種類選択メニューからActionを選択
GameObject.SetActiveノードの編集
- TargetフィールドにCanvas/Game Clearオブジェクトを設定
以下のいずれかの方法で設定できます。- SelfをValueに変更し、オブジェクトフィールドでCanvas/Game Clearオブジェクトを設定
- Selfのまま、HierarchyウィンドウからCanvas/Game ClearオブジェクトをTargetフィールドにドラッグ&ドロップ
- Valueフィールドをチェック
クリア判定の挙動確認
プレイ開始してクリア判定の挙動を確認します。
- 全てのブロックにボールを当てて破壊すると、Game Clearオブジェクトがアクティブになることを確認
ゲームオーバー判定の作成
ボールが一番下に落下した場合はゲームオーバーとします。
判定方法はWall Bottomオブジェクトに接触した場合としましょう。
今回はボール以外に衝突するオブジェクトがないため、オブジェクトの種類の判定は省いています。
また落下したBallオブジェクトが残っていると不自然ですので破棄しておきます。
Wall BottomにLogic Behaviorの追加
- Walls/Wall Bottomオブジェクトを選択
- InspectorウィンドウのAdd Componentボタンをクリック
- Logic Toolkit/Logic Behaviorを選択してLogic Behaviorコンポーネントを追加
- Logic BehaviorのEditボタンをクリックし、Logic Editorウィンドウを開く
Wall BottomのLogic Behaviorを編集
PubOnCollisionEnter.Callbackノードの作成
- Startノードを削除
- グラフ上をクリックしフォーカスがある状態で
Spaceキー
を押し、ノード作成メニューを開く - Scriptsタブを選択
- 検索欄に
OnCollisionEnter Callback
と入力 - 一覧からPubOnCollisionEnter.Callback (Event)を選択
PubOnCollisionEnter.Callbackノードの編集
- TargetフィールドのRequireをチェック
Collision.gameObjectノードの作成
- PubOnCollisionEnter.CallbackノードのArg 0フィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
Collision gameObject
と入力 - 一覧からGet Collision.gameObject (Compute)を選択
GameObject.Destroyノードの作成
- Collision.gameObjectノードのGame Objectフィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
Destroy
と入力 - 一覧からGameObject.Destroy(gameObject) (Action)を選択
OnCollisionEnterとGameObject.Destroyの接続
- PubOnCollisionEnter.Callbackノードの実行ポートをGameObject.Destroyノードの入力ポートにドラッグ&ドロップして接続
GameObject.SetActiveノードの作成
- GameObject.Destroyノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
GameObject SetActive
と入力 - 一覧からGameObject.SetActive(bool value) (Action)を選択
GameObject.SetActiveノードの編集
- TargetフィールドにCanvas/Game Overオブジェクトを設定
以下のいずれかの方法で設定できます。- SelfをValueに変更し、オブジェクトフィールドでCanvas/Game Overオブジェクトを設定
- Selfのまま、HierarchyウィンドウからCanvas/Game OverオブジェクトをTargetフィールドにドラッグ&ドロップ
- Valueフィールドをチェック
ゲームオーバー判定の挙動確認
プレイ開始してゲームオーバー判定の挙動を確認します。
- BallがWall Bottomオブジェクトに当たった際に、Ballオブジェクトが破棄され、Game Overオブジェクトがアクティブになることを確認
Main Logicの挙動作成
ここまではゲームクリアとゲームオーバーの表示切替を別々のオブジェクトで行っていましたが、ゲームの進行をMain Logicオブジェクトで管理するように変更します。
ゲームの状態はBlackboard Assetで共有し、各オブジェクトはBlackboardのData Linkを介してゲームの状態にアクセスするようにします。
Blackboard Assetの作成
- ProjectウィンドウのLogicフォルダを選択
- +ボタンをクリック
- メニューからLogic Toolkit/Blackboardを選択
- 名前を
Main Scene Blackboard
に変更
Main Scene Blackboardの編集
作成する変数は以下の通りです。
変数名 | 型 | 説明 |
---|---|---|
IsPlaying | bool | ゲームのプレイ中(ボールが動いてブロックを壊せる間)にtrueとなる。 falseからtrueに切り替わった場合にボールが移動開始する。 trueからfalseに切り替わった場合はゲーム終了としクリア判定を行う。 |
IsGameClear | bool | ゲーム終了時にクリアした場合にtrueとなる。 ゲームオーバーの場合はfalseとなる。 |
IsPlaying変数の作成
- Main Scene Blackboardを選択し、InspectorウィンドウでBlackboardの+ボタンをクリック
- 変数作成メニューからPrimitive/boolを選択
- 名前を
IsPlaying
に変更
IsGameClear変数の作成
- Inspectorウィンドウで、Blackboardの+ボタンをクリック
- 変数作成メニューからPrimitive/boolを選択
- 名前を
IsGameClear
に変更
Main LogicにLogic Behavior追加
- Main Logicオブジェクトを選択
- InspectorウィンドウのAdd Componentボタンをクリック
- Logic Toolkit/Logic Behaviorを選択してLogic Behaviorコンポーネントを追加
- Logic BehaviorのEditボタンをクリックし、Logic Editorウィンドウを開く
Main LogicのLogic Behaviorを編集
Main Logicの状態の進行管理にStateノードを使用します。
作成するステートは以下の通りです。
ステート名 | 説明 |
---|---|
Game Start | ゲーム開始直後の状態。 Game Startステートがアクティブの間、Game Startオブジェクトを表示する。 Submitボタンを押した際にGame Playingステートに遷移する。 |
Game Playing | ゲームをプレイ中の状態。 ボールが移動し、ブロック崩しを楽しめる。 IsPlaying変数がfalseになったらIsGameClearを判定し、Game ClearステートかGame Overステートに遷移する。 |
Game Clear | ブロックをすべて破壊し、ゲームクリアした状態。 Game Clearオブジェクトを表示する。 Submitボタンを押した際にシーンをリロードする。 |
Game Over | ボールが落下して、ゲームオーバーになった状態。 Game Overオブジェクトを表示する。 Submitボタンを押した際にシーンをリロードする。 |
ステートは実行ノードの一種として用意しています。
いままで使用してきたActionノードやBranchノードなどとStateノードを接続することで一連の流れの中にステートも組み込めます。
Main Sceneデータリンクの作成
- サイドパネルのBlackboardタブを選択
- Data Linkタブを選択
- +ボタンをクリック
- 名前を
Main Scene
に変更 - Share TypeフィールドをSceneに設定
- Blackboard AssetフィールドをLogic/Main Scene Blackboardアセットに設定
Data Link機能を利用してBlackboardを参照すると、Share TypeとTagとBlackboard Assetが共通のData Linkは共有され、同一変数にアクセスできるようになります。
Game Startステートの作成
- Startノードの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からStateを選択
- 名前を
Game Start
に変更
GameObject.SetActiveコンポーネントの追加
- Game StartステートのComponentsフィールドの+ボタンをクリック
- Scriptsタブを選択
- 検索欄に
GameObject SetActive
と入力 - 一覧からGameObject.SetActive(bool value)を選択
いままではActionノードで使用してきたGameObject.SetActive(bool value)ですが、ActionComponentというスクリプトで実装されていますので、Stateノードなどのコンポーネントとしても利用可能です。
GameObject.SetActiveコンポーネントの編集
- MethodsフィールドをOn Activatedのみに変更
- TargetフィールドにCanvas/Game Startオブジェクトを設定
以下のいずれかの方法で設定できます。- SelfをValueに変更し、オブジェクトフィールドでCanvas/Game Startオブジェクトを設定
- Selfのまま、HierarchyウィンドウからCanvas/Game StartオブジェクトをTargetフィールドにドラッグ&ドロップ
- Valueフィールドをチェック
ActionComponentをStateノードに使用した場合は、Methodsフィールドが追加されます。
ActionComponentは処理をすぐに実行するだけのスクリプトですので、Methodsフィールドの設定で実行するタイミングを制御します。
今回のOn Activatedはステートがアクティブになったときに実行される設定です。
IsPlaying変数の設定コンポーネントの追加
- Main SceneデータリンクのIsPlaying変数をGame StartステートのComponentsの一番下にドラッグ&ドロップし、コンポーネント追加メニューを開く
- 一覧からSet Variableを選択
IsPlaying変数の設定コンポーネントの編集
- MethodsフィールドをOn Activatedのみに変更
GameObject.SetActiveコンポーネントの追加
- Game StartステートのComponentsフィールドの+ボタンをクリック
- Scriptsタブを選択
- 検索欄に
GameObject SetActive
と入力 - 一覧からGameObject.SetActive(bool value)を選択
GameObject.SetActiveコンポーネントの編集
- MethodsフィールドをOn Deactivatedのみに変更
- TargetフィールドにCanvas/Game Startオブジェクトを設定
以下のいずれかの方法で設定できます。- SelfをValueに変更し、オブジェクトフィールドでCanvas/Game Startオブジェクトを設定
- Selfのまま、HierarchyウィンドウからCanvas/Game StartオブジェクトをTargetフィールドにドラッグ&ドロップ
今回のOn Deactivatedはステートが非アクティブになったときに実行される設定です。
Input.GetButtonDownコンポーネントを追加
- Game StartノードのComponentsの+ボタンをクリック
- Membersタブを選択
- 検索欄に
Input GetButtonDown
と入力 - 一覧から
UnityEngine.Input
のGetButtonDown(string buttonName)を選択
bool型が戻り値のメンバーはEvaluateComponentというスクリプトで実装されます。
EvaluateComponentは何かを評価するためのノード用コンポーネントです。
今回はボタン押下を判定するInput.GetButtonDown(string buttonName)
をStateノードに使用して、Submitボタンの押下を評価してステートを遷移させます。
Input.GetButtonDownコンポーネントの編集
- Button Nameフィールドを
Submit
に設定
Game Playingステートの作成
- Input.GetButtonDownコンポーネントのSignalフィールドのシグナルポートをドラッグ&ドロップして、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からStateを選択
- 名前を
Game Playing
に変更
出力シグナルポートを直接実行ノードに接続すると、条件を満たしてシグナルがオンになったタイミングで接続先ノードに遷移します。
IsPlaying変数の設定コンポーネントの追加
- Main SceneデータリンクのIsPlaying変数をGame PlayingステートのComponentsにドラッグ&ドロップして、コンポーネント追加メニューを開く
- 一覧からSet Variableを選択
IsPlaying変数の設定コンポーネントの編集
- MethodsフィールドをOn Activatedのみに変更
- Is Playingフィールドをチェック
Bool Equalsコンポーネントの追加
- Game PlayingステートのComponentsの+ボタンをクリック
- Scriptsタブを選択
- 検索欄に
Bool Equals
と入力 - 一覧からBool Equalsを選択
IsPlaying変数の取得ノードの作成
データポートをドラッグ&ドロップして変数アクセスノードを作成する方法もあります。
- Bool EqualsコンポーネントのValue 1フィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
IsPlaying
と入力 - 一覧から
Compute/Variables/DataLink/Main Scene
のIsPlaying [Get] (Compute)を選択
Time.timeScaleノードの作成
ゲームの結果表示中はTime.timeScale
を0にしてポーズ状態にしてみましょう。
- Bool EqualsコンポーネントのSignalフィールドのシグナルポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Time timeScale
と入力 - 一覧から
UnityEngine.Time
のtimeScale [Set]を選択 - ノードの種類選択メニューからActionを選択
シグナルポートはStateだけでなくActionやTask、Branchなどのフロー制御ノードに遷移できます。
Branchノードの作成
IsGameClear変数を判定して処理を分岐します。
- Time.timeScaleノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からFlow Controls/Branchを選択
IsGameClear変数の取得ノードの作成
- BranchノードのConditionフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
IsGameClear
と入力 - 一覧から
Compute/Variables/DataLink/Main Scene
のIsGameClear [Get] (Compute)を選択
Game Clearステートの作成
- BranchノードのTrueフィールドの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からStateを選択
- 名前を
Game Clear
に変更
GameObject.SetActiveコンポーネントの追加
- Game ClearステートのComponentsフィールドの+ボタンをクリックし、コンポーネント追加メニューを開く
- Scriptsタブを選択
- 検索欄に
GameObject SetActive
と入力 - 一覧からGameObject.SetActive(bool value)を選択
GameObject.SetActiveコンポーネントの編集
- MethodsフィールドをOn Activatedのみに設定
- TargetフィールドにCanvas/Game Clearオブジェクトを設定
以下のいずれかの方法で設定できます。- SelfをValueに変更し、オブジェクトフィールドでCanvas/Game Clearオブジェクトを設定
- Selfのまま、HierarchyウィンドウからCanvas/Game ClearオブジェクトをTargetフィールドにドラッグ&ドロップ
- Valueフィールドをチェック
Game Overステートの作成
- BranchノードのFalseフィールドの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からStateを選択
- 名前を
Game Over
に変更
GameObject.SetActiveコンポーネントの追加
- Game OverステートのComponentsフィールドの+ボタンをクリックし、コンポーネント追加メニューを開く
- Scriptsタブを選択
- 検索欄に
GameObject SetActive
と入力 - 一覧からGameObject.SetActive(bool value)を選択
GameObject.SetActiveコンポーネントの編集
- MethodsフィールドをOn Activatedのみに設定
- TargetフィールドにCanvas/Game Overオブジェクトを設定
以下のいずれかの方法で設定できます。- SelfをValueに変更し、オブジェクトフィールドでCanvas/Game Overオブジェクトを設定
- Selfのまま、HierarchyウィンドウからCanvas/Game OverオブジェクトをTargetフィールドにドラッグ&ドロップ
- Valueフィールドをチェック
Signal Evaluationノードの作成
Game ClearステートとGame OverステートはともにSubmitボタンを押した際にシーンをリロードする挙動となっています。
遷移条件が場合はSignal Evaluationノードを使用すると判定を共通化できます。
- Game Clearステートのシグナルポートをドラッグ&ドロップして、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧からSignals/Signal Evaluationを選択
Stateのヘッダ部にあるシグナルポートはステートがアクティブの間オンになります。
このシグナルポートからSignal Evaluationノードを接続すると、ステートがアクティブの間の遷移条件判定が行えるようになります。
Input.GetButtonDownコンポーネントを追加
- Signal EvaluationノードのConditionsの+ボタンをクリック
- Scriptsタブを選択
- 検索欄に
Input GetButtonDown
と入力 - 一覧からInput.GetButtonDown(string buttonName)を選択
Input.GetButtonDownコンポーネントの編集
- Button Nameフィールドに
Submit
を設定
Game OverステートとSignal Evaluationノードの接続
- Game OverステートのシグナルポートをSignal Evaluationノードの入力ポート(Game Clearステートと接続されているポート)にドラッグ&ドロップして接続
同じ入力ポートに複数のシグナルワイヤーを接続している場合は、いずれか一つでもシグナルがオンの場合は真となります。
Time.timeScaleノードの作成
シーンのリロードの前にTime.timeScale
を1
に戻します。
- Signal Evaluationノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 検索欄に
Time timeScale
と入力 - 一覧からSet Time.timeScale (Action)を選択
Time.timeScaleノードの編集
- Time Scaleフィールドを
1
に変更
SceneManager.LoadSceneノードの作成
- Time.timeScaleノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
SceneManager LoadScene
と入力 - 一覧から
UnityEngine.SceneManagement.SceneManager
のLoadScene(string sceneName)を選択 - ノードの種類選択メニューからActionを選択
SceneManager.LoadSceneノードの編集
- Scene Nameフィールドを
BlockBreaking
に変更
Ballの挙動変更
IsPlaying変数がtrueになった際に移動開始するように挙動を変更します。
変更の準備
- Player/Ball SocketにあるBallオブジェクトを選択
- BallオブジェクトのLogic BehaviorをLogic Editorウィンドウで開いておく
Main Sceneデータリンクの作成
- サイドパネルのBlackboardタブを選択
- Data Linkタブを選択
- +ボタンをクリック
- 名前を
Main Scene
に変更 - Share TypeフィールドをSceneに設定
- Blackboard AssetフィールドをLogic/Main Scene Blackboardアセットに設定
IsPlaying変数の変更イベントノードの作成
- Startノードを削除
- Main SceneデータリンクのIsPlaying変数をStartノードがあった辺りのドラッグ&ドロップし、ノード作成メニューを開く
- 一覧からChange Variable Event (Event)を選択
Branchノードの作成
- IsPlaying変数の変更イベントノードのIs Playingフィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Scriptsタブを選択
- 一覧から
Flow Controls/Branch
を選択
Branchノードとの接続
- IsPlaying変数の変更イベントノードの実行ポートをBranchノードの入力ポートにドラッグ&ドロップして接続
- BranchノードのTrueフィールドの遷移ポートをTransform.SetParentノードの入力ポートにドラッグ&ドロップして接続
Blocksの挙動変更
すべてのオブジェクトが破壊できた場合のクリア判定をMain Logic側に通知するように変更します。
今回はMain Scene BlackboardをData Link機能で共有し、IsGameClear変数をtrueにした後、IsPlaying変数をfalseにすることでMain LogicがGame Clearステートに切り替わります。
変更の準備
- Blocksオブジェクトを選択
- BlocksオブジェクトのLogic BehaviorをLogic Editorウィンドウで開いておく
Main Sceneデータリンクの作成
- サイドパネルのBlackboardタブを選択
- Data Linkタブを選択
- +ボタンをクリック
- 名前を
Main Scene
に変更 - Share TypeフィールドをSceneに設定
- Blackboard AssetフィールドをLogic/Main Scene Blackboardアセットに設定
IsGameClear変数の設定ノードの作成
- Game ClearオブジェクトをアクティブにしているGameObject.SetActiveノードを削除
- Main SceneデータリンクのIsGameClearをGameObject.SetActiveノードがあった辺りにドラッグ&ドロップし、ノード作成メニューを開く
- 一覧からSet Variable (Action)を選択
IsGameClear変数の設定ノードの編集
- Is Game Clearフィールドをチェック
IsGameClear変数の設定ノードへの接続
- Int Equalsノードの実行ポートからIs Game Clear変数の設定ノードの入力ポートにドラッグ&ドロップして接続
IsPlaying変数の設定ノードの作成
- Main SceneデータリンクのIsPlayingをIsGameClear変数の設定ノードの右隣辺りにドラッグ&ドロップし、ノード作成メニューを開く
- 一覧からSet Variable (Action)を選択
IsPlaying変数の設定ノードへの接続
- IsGameClear変数の設定ノードの遷移ポートをIsPlaying変数の設定ノードの入力ポートにドラッグ&ドロップして接続
Wall Bottomの挙動変更
ボールが落下した場合のゲームオーバー判定をMain Logic側に通知するように変更します。
今回はMain Scene BlackboardをData Link機能で共有し、IsGameClear変数をfalseにした後、IsPlaying変数をfalseにすることでMain LogicがGame Overステートに切り替わります。
変更の準備
- Walls/Wall Bottomオブジェクトを選択
- Wall BottomオブジェクトのLogic BehaviorをLogic Editorウィンドウで開いておく
Main Sceneデータリンクの作成
- サイドパネルのBlackboardタブを選択
- Data Linkタブを選択
- +ボタンをクリック
- 名前を
Main Scene
に変更 - Share TypeフィールドをSceneに設定
- Blackboard AssetフィールドをLogic/Main Scene Blackboardアセットに設定
IsGameClear変数の設定ノードの作成
- Game OverオブジェクトをアクティブにしているGameObject.SetActiveノードを削除
- Main SceneデータリンクのIsGameClearをGameObject.SetActiveノードがあった辺りにドラッグ&ドロップし、ノード作成メニューを開く
- 一覧からSet Variable (Action)を選択
IsGameClear変数の設定ノードへの接続
- GameObject.Destroyノードの遷移ポートからIs Game Clear変数の設定ノードの入力ポートにドラッグ&ドロップして接続
IsPlaying変数の設定ノードの作成
- Main SceneデータリンクのIsGameClearをIsGameClear変数の設定ノードの右隣辺りにドラッグ&ドロップし、ノード作成メニューを開く
- 一覧からSet Variable (Action)を選択
IsPlaying変数の設定ノードへの接続
- IsGameClear変数の設定ノードの遷移ポートをIsPlaying変数の設定ノードの入力ポートにドラッグ&ドロップして接続
Main Logicの挙動確認
プレイしてゲームの流れの挙動を確認しましょう。
- プレイ開始直後、Ballが移動しないことを確認
- Playerの移動に合わせてBallが連動していることを確認
- Submitボタン(デフォルトでは
Spaceキー
もしくはEnterキー
)を押すと移動開始することを確認 - すべてのブロックを壊した場合に、Game Clearが表示されることを確認
- Game Clearが表示中にSubmitボタンを押すとシーンがリロードされることを確認
- シーンリロード後も繰り返し動作することを確認
- ボールが落下した場合に、Game Overが表示されることを確認
- Game Overが表示中にSubmitボタンを押すとシーンがリロードされることを確認
PhysicsのBounce Thresholdの設定(任意)
何度かプレイしていると、ボールが壁に当たった後、水平に移動して事実上進行不能状態に陥ることがあります。
これはUnityのPhysicsの設定により、衝突時の速度が一定値以下の場合は壁方向への速度を0にする仕様が働いているためです。
ブロック崩しでは必ずバウンドしてほしいため、PhysicsのbounceThresholdを0にすることで、この問題を解決できます。
設定するには以下のいずれかの方法があります。
- Project Settingsを設定
- メンバーアクセスによる設定
Project Settingsを設定
シーンによって変更する必要がない場合は、Project Settingsで設定することで簡単に解決できます。
- メニューからEdit/Project Settingsを選択
- Physics/Settingsカテゴリを選択
- Game Objectタブを選択
- Bounce Thresholdフィールドを
0
に変更
メンバーアクセスによる設定
シーンによって変更する必要がある場合は、メンバーアクセスによりPhysics.bounceThreshold
を設定できます。
- Main Logicオブジェクトを選択
- Startノードの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
- Membersタブを選択
- 検索欄に
Physics bounceThreshold
と入力 - 一覧から
UnityEngine.Physics
のbounceThreshold [Set]を選択 - ノードの種類選択メニューからActionを選択
- 作成したActionノードの遷移ポートをGame Startステートの入力ポートに接続
完了
以上でLogic Toolkitチュートリアル「ブロック崩しの作成方法」は完了です。
学習内容
学習した内容を振り返ってみましょう。
- オブジェクトの挙動制御にLogic Behaviorコンポーネントを使用する
- 共通の挙動を使いまわすにはLogic AssetとLogic Playerコンポーネントを使用する
- シンプルな機能であれば、メンバーアクセスのスクリプト生成機能によりコーディング作業を挟まずに挙動が組める
- Actionノード、Stateノード、Branchノード(フロー制御)などがグラフ内に混在できる
- Stateの遷移条件判定をSignal Evaluationノードで共通化できる
- Blackboardの変数で値を共有できる
- BlackboardのData Link機能により複数のオブジェクト間で変数を共有できる
完了を投稿(任意)
最後に、チュートリアル完了を記録としてSNSに投稿しておくと良いでしょう。