ブロック崩しの作成方法

概要

Logic Toolkitを使用して簡単なブロック崩しゲームを作成する方法を紹介します。
完成品はLogic Toolkitの同梱サンプル「BlockBreaking」と同様の内容になっています。

前提知識

  • Unityエディタの基本的な使い方

学習内容

  • オブジェクトの挙動制御にLogic Behaviorコンポーネントを使用する
  • 共通の挙動を使いまわすにはLogic AssetとLogic Playerコンポーネントを使用する
  • シンプルな機能であれば、メンバーアクセスのスクリプト生成機能によりコーディング作業を挟まずに挙動が組める
  • Actionノード、Stateノード、Branchノード(フロー制御)などがグラフ内に混在できる
  • Stateの遷移条件判定をSignal Evaluationノードで共通化できる
  • Blackboardの変数で値を共有できる
  • BlackboardのData Link機能により複数のオブジェクト間で変数を共有できる

撮影環境

このチュートリアルの画像および動画は以下の環境で撮影しています。

OSWindows 11
Unity6000.0.0f1
Logic Toolkit1.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.RigidbodylinearVelocity [Set]を選択
  • ノードの種類選択メニューからActionを選択

Membersタブでメンバーのアクセススクリプトを作成した際に、まだスクリプト生成用のアセンブリが作成されていない場合は新規作成されます。
アセンブリが[Unselected]のままノードを作成した場合の名前はデフォルトのLogicToolkitGeneratedScriptsになります。
アセンブリのドロップダウンをクリックしメニューからCreate New Assemblyを選択すると、任意の名前のアセンブリを作成可能です。
またアセンブリ名の変更は非推奨です。
後から変更するとスクリプトの参照切れが発生するため、間違いのないように気を付けてください。
通常はデフォルトの名前で問題ありません。

サンプルのBlockBreakingではインポートした際の重複を避けるためにBlockBreaking_GeneratedScriptsという名前にしています。

スクリプト生成用のファイルはAssets/Logic Toolkit/Generated Scripts/アセンブリ名フォルダに作成されます。
基本的にスクリプト生成用のファイルを直接変更する必要はありません。

new Vector3ノードの作成

  • Linear Velocityフィールドの入力ポートを左側付近にドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にnew Vector3と入力
  • 一覧からUnityEngine.Vector3new 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.InputGetAxis(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.TransformSetParent(Tranform parent, bool worldPositionStays)を選択
  • ノードの種類選択メニューからActionを選択

Transform.SetParentノードの編集

Rigidbody.isKinematicノードの作成

初期状態ではRigidbodyのIs Kinematicが有効になっています。
ボールは移動開始と同時に壁やブロックなどに当たった際に物理的な反射を行ってほしいため、Is Kinematicを無効に切り替えます。

  • Transform.SetParentノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にRigidbody isKinematicと入力
  • 一覧からUnityEngine.RigidbodyisKinematic [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.Vector3operator *(Vector3 a, float d)を選択
  • ノードの種類選択メニューからComputeを選択

Vector3.operator *ノードの編集

  • Dフィールドの値を8に設定

Vector3.normalizedノードの作成

  • Vector3.operator *ノードのAフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にnormalizedと入力
  • 一覧からUnityEngine.Vector3normalized [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.PubOnCollisionEnterCallbackを選択
  • ノードの種類選択メニューから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.Vector3operator -(Vector3 a, Vector3 b)を選択
  • ノードの種類選択メニューからComputeを選択

Transform.positionノードの作成

  • Vector3.operator -ノードのAフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にTransform positionと入力
  • 一覧からUnityEngine.Transformposition [Get]を選択
  • ノードの種類選択メニューからComputeを選択

Collision.transformノードの作成

  • PubOnCollisionEnter.CallbackノードのArg 0フィールドの出力ポートを先ほど作成したTransform.positionノードよりも下側へドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 一覧からCollision/transform [Get]を選択
  • ノードの種類選択メニューからComputeを選択

Transform.positionノードをもう一つ作成

  • Collision.transformノードのTransformフィールドの出力ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にpositionと入力
  • 一覧からUnityEngine.Transformposition [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.TransformchildCount [Get]を選択
  • ノードの種類選択メニューからComputeを選択

GameObject.SetActiveノードの作成

  • Int Equalsノードの実行ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にGameObject SetActiveと入力
  • 一覧からUnityEngine.GameObjectSetActive(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の編集

作成する変数は以下の通りです。

変数名説明
IsPlayingboolゲームのプレイ中(ボールが動いてブロックを壊せる間)にtrueとなる。
falseからtrueに切り替わった場合にボールが移動開始する。
trueからfalseに切り替わった場合はゲーム終了としクリア判定を行う。
IsGameClearboolゲーム終了時にクリアした場合に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.InputGetButtonDown(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 SceneIsPlaying [Get] (Compute)を選択

Time.timeScaleノードの作成

ゲームの結果表示中はTime.timeScaleを0にしてポーズ状態にしてみましょう。

  • Bool EqualsコンポーネントのSignalフィールドのシグナルポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にTime timeScaleと入力
  • 一覧からUnityEngine.TimetimeScale [Set]を選択
  • ノードの種類選択メニューからActionを選択

シグナルポートはStateだけでなくActionやTask、Branchなどのフロー制御ノードに遷移できます。

Branchノードの作成

IsGameClear変数を判定して処理を分岐します。

  • Time.timeScaleノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Scriptsタブを選択
  • 一覧からFlow Controls/Branchを選択

IsGameClear変数の取得ノードの作成

  • BranchノードのConditionフィールドの入力ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Scriptsタブを選択
  • 検索欄にIsGameClearと入力
  • 一覧からCompute/Variables/DataLink/Main SceneIsGameClear [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.timeScale1に戻します。

  • Signal Evaluationノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Scriptsタブを選択
  • 検索欄にTime timeScaleと入力
  • 一覧からSet Time.timeScale (Action)を選択

Time.timeScaleノードの編集

  • Time Scaleフィールドを1に変更

SceneManager.LoadSceneノードの作成

  • Time.timeScaleノードの遷移ポートをドラッグ&ドロップし、ノード作成メニューを開く
  • Membersタブを選択
  • 検索欄にSceneManager LoadSceneと入力
  • 一覧からUnityEngine.SceneManagement.SceneManagerLoadScene(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.PhysicsbounceThreshold [Set]を選択
  • ノードの種類選択メニューからActionを選択
  • 作成したActionノードの遷移ポートをGame Startステートの入力ポートに接続

完了

以上でLogic Toolkitチュートリアル「ブロック崩しの作成方法」は完了です。

学習内容

学習した内容を振り返ってみましょう。

  • オブジェクトの挙動制御にLogic Behaviorコンポーネントを使用する
  • 共通の挙動を使いまわすにはLogic AssetとLogic Playerコンポーネントを使用する
  • シンプルな機能であれば、メンバーアクセスのスクリプト生成機能によりコーディング作業を挟まずに挙動が組める
  • Actionノード、Stateノード、Branchノード(フロー制御)などがグラフ内に混在できる
  • Stateの遷移条件判定をSignal Evaluationノードで共通化できる
  • Blackboardの変数で値を共有できる
  • BlackboardのData Link機能により複数のオブジェクト間で変数を共有できる

完了を投稿(任意)

最後に、チュートリアル完了を記録としてSNSに投稿しておくと良いでしょう。