PUN Classic (v1)、PUN 2、Boltはメンテナンスモードとなっております。Unity2022についてはPUN 2でサポートいたしますが、新機能が追加されることはありません。お客様のPUNプロジェクトおよびBoltプロジェクトが停止することはなく、将来にわたってパフォーマンス性能が落ちることはありません。 今後の新しいプロジェクトについては、Photon FusionまたはQuantumへ切り替えていただくようよろしくお願いいたします。

2 - ネットワークコールバック

<< 前章へ

Boltでは、その他のほとんど(あるいはその他全て)のUnity用ネットワーキングソリューションとは全く異なるやり方で複製が行われます。
OnSerializeNetworkView をUnityネットワーキングソリューションにおけるビルドで用いるなどのようにデータのシリアル化のために手動でコードを書くのではなく、Boltではネットワーク上でそれ自体が自動で複製されるよう、変換やアニメーション、カスタムプロパティを定義することができます。コードを書く必要は一切ありません。
このチュートリアルでも、低階層のネットワーキングコードを書くようなことはありません。Boltが全てやってくれるのです。

カメラの追加

最初にするべきはカメラの設定です。これにより何が起こっているのかを見ることができるようになります。しかし、カメラをシーンに置くのではなく、Boltを通じてそのコールバックに接続するようにします。
最終的なチュートリアルには、必要な機能を有している既に機能しているカメラが付属しています。本チュートリアルは第三者視点のカメラを作成することを目的としていないため、これを逐語的に利用します。

Assets/samples/AdvancedTutorial/prefabs/singletons/resources/PlayerCamera からカメラのプレハブを確認できます。関連するスクリプトは、Assets/samples/AdvancedTutorial/scripts/player/PlayerCamera.cs にあります。
カメラスクリプトはユーティリティーベースクラスから継承され、これはBoltSingletonPrefab<T>を呼び出すことでBolt内に定義されます。これは、Resources からプレハブを自動で読み込むのに用いられます。

最初のスクリプトをここで作成しましょう。フォルダ tutorial/scripts/Callbacks を作成し、TutorialPlayerCallbacks.csという名前のスクリプトを作成してください。その後、以下の手順にしたがってください:

  1. クラスをBolt.GlobalEventListenerから継承してください。
  2. 対象のシーン(ここでは Level2)を選択し、クラスに[BoltGlobalBehaviour("Level2")]注釈を適用してください。
  3. Bolt.GlobalEventListenerから継承されるSceneLoadLocalDoneメソッドをオーバーライドしてください。このメソッドについての詳細は、APIページを参照してください。;
  4. ファイルの最上部にusing Bolt.AdvancedTutorial;を挿入し、PlayerCameraクラスにアクセスできるようにしてください。
  5. SceneLoadLocalDone内でPlayerCamera.Instantiate()を呼び出します(引数は不要です)。
  6. 非常に重要な点ですが、この挙動はあらゆるシーンのあらゆるゲームオブジェクトに添付 しない でください。

C#

using Bolt.AdvancedTutorial;
using UnityEngine;

[BoltGlobalBehaviour("Level2")]
public class TutorialPlayerCallbacks : Bolt.GlobalEventListener
{

    public override void SceneLoadLocalDone(string map)
    {
        // this just instantiates our player camera,
        // the Instantiate() method is supplied by the BoltSingletonPrefab<T> class
        PlayerCamera.Instantiate();
    }
}
Callbacks Script
プレイヤーコールバックスクリプトのパス

ゲームを開始する前に、ここで何が起こっているのかを説明しましょう。
[BoltGlobalBehaviour("Level2")] は実際には何をしているのでしょうか。Boltが開始したとき、これは [BoltGlobalBehaviour("Level2")] を含み MonoBehaviour から何らかの形で継承されている 全て のクラスを見つけます。(Bolt.GlobalEventListener 自体は MonoBehaviour からの継承であるため、TutorialPlayerCallbacks もまた MonoBehaviour からの継承と判断されます)

それから、Boltはこれらの2つの条件にマッチングするクラスを検索し、自動でそれらのインスタンスを作成します。これは、Boltが起動しているときに存在し、Boltがシャットダウンされたときには破棄されるようにするためです。
作成される全てのインスタンスは、開始時にBoltが自動で作成するBoltBehavioursゲームオブジェクトに追加されます。これはシーン階層で確認することができます。

[BoltGlobalBehaviour]の挙動を設定するにはいくつかの方法があります。最もシンプルなものとして、その挙動がサーバー側で行われるかクライアント側で行われるか、あるいはその両方かを決めることがあります。
TutorialPlayerCallbacks クラスで行ったように何も指定しなければ、サーバー上とクライアント上の両方で動作することとなります。

C#

// only on the host
[BoltGlobalBehaviour(BoltNetworkModes.Host)]

// only on the client
[BoltGlobalBehaviour(BoltNetworkModes.Client)]

また、Boltの挙動を特定のシーン内においてのみ利用可能にすることもできます。例えば、ここでのシーンは Level2 と呼ばれています。

C#

// only when the current scene is 'Level2'
[BoltGlobalBehaviour("Level2")]

// only when the current scene is 'Level1', 'Level2' or 'Level3'
[BoltGlobalBehaviour("Level1", "Level2", "Level3")]

これらを組み合わせることもできます。

C#

// only when we are the host AND the current scene is 'Level2'
[BoltGlobalBehaviour(BoltNetworkModes.Host, "Level2")]

// only when we are the client AND the current scene is 'Level2'
[BoltGlobalBehaviour(BoltNetworkModes.Client, "Level2")]

これによって、アプリケーション全体またはシーン全体への挙動を簡単に定義できます。DontDestroyOnLoadでマーキングされたゲームオブジェクトをすべてのシーンに渡すことは不要です。重要 な点ですが、さきに述べたとおりどのような状況下でも手動でこれらのスクリプトをシーン内のオブジェクトに添付 しないで ください。Boltが自動で処理します。

カメラの開始

Window/Bolt/Scenes ウィンドウメニューを開き、Level2 シーンで Play As Server をクリックしてください。
これで Game ウィンドウ内でサーバーが開始し、カメラがインスタンスを作成することを確認できます。

Play the game as Server
ゲームをServeとしてプレイ。(1) *Level2* シーンをServerとして開始、(2) ゲームの実行、(3) スクリプトによってスポーンされた *PlayerCamera* オブジェクト、 (4) *BoltBehaviours* ゲームオブジェクト、(5) Boltで実行される `TutorialPlayerCallbacks` スクリプト

シーン階層を見ると、BoltBehaviours と名前のついたゲームオブジェクトを確認できます。これは Bolt の内部オブジェクトであり、この時点でこれを完全に可視化(HideFlagがない状態)しました。これで何が起こっているのかを常に知ることができます。
このオブジェクトに対するインスペクターをチェックすると、Boltが自動でインスタンス化する内部のすべての挙動を見ることができ、TutorialPlayerCallbacksの挙動は下部で見ることができます。SceneLoadLocalDoneコールバックでインスタンスが作成されたPlayerCameraを確認することもできます。

プレハブの作成

新規に空のゲームオブジェクトを作成し、それに TutorialPlayer と名前をつけてください。これの位置が(0, 0, 0)、回転が(0, 0, 0)、スケールが(1, 1, 1)となっているか確認してください。
これから用いるモデルは、bolt_samples/AdvancedTutorial/art/models/sgtBolt にあります。そのプレハブ名は sgtBolt4Merged-ModelOnly となっています。このプレハブのインスタンスをその階層にドラッグしてください。
sgtBolt4Merged-ModelOnly オブジェクトが、TutorialPlayer ゲームオブジェクトと同じ位置・回転・スケール値を有していることを確認してください。
その後、下図のように sgtBolt4Merged-ModelOnly オブジェクトを TutorialPlayer オブジェクトの子としてドラッグしてください。

Player prefab
Tutorial Playerプレハブ

チュートリアルフォルダ内に新たなフォルダを作成し、Prefabs と名前をつけてください。TutorialPlayer オブジェクトをこのフォルダにドラッグし、そこからプレハブを作成してください。この時点で、シーン階層にある TutorialPlayer オブジェクトは消去しても構いません。

Player prefab
Tutorial Playerプレハブ

TutorialPlayer プレハブを選択し、Bolt Entity コンポーネントを追加します。

Bolt Entity on prefab
プレハブ上のBolt Entity コンポーネント上のすべての警告(赤い感嘆符)は想定内です。次章で解決をおこないます。

Bolt Entity コンポーネントは、UnityまたはPhotonの Network View に緩く関連づけされています。しかし、Bolt内においてそれ以外のいくつかの目的も成しています。
最初にすべきは、2つのエラーを解決することです。これは、トップメニューバーのBolt/Compile Assemblyメニューオプションから行うことができます。

Assets/Bolt/Compile Assembly メニューを起動すると、Boltは全てのプレハブおよびその他のBoltに関連するアセットを検索し、それらのために非常に効率的なネットワークプロトコルをコンパイルします。これはbolt.user.dllアセンブリ内に保存されます。これは Assets/Photon/PhotonBolt/assembliesフォルダで確認できます。
Assets/Bolt/Compile Assembly コマンドの起動を行うケースはいくつかありますが、このチュートリアルではその全てをカバーします。

コンパイルが完了したら、プレハブにおける Bolt Entity コンポーネントは以下のようになります。

Tutorial Player Entity with new ID
Tutorial Playerエンティティと新しいID。

ご覧の通り、Boltエンティティには状態が欠けているので、この点を次でカバーします。

Bolt内の状態

詳細を進む前に、Boltにおける "状態" について定義しましょう。状態とは、ゲームオブジェクトのデータ、変換、アニメーションです。
Boltではエンティティに対して割り当てた全ての状態が、変換やアニメーションも例外なく、ネットワーク上に複製されます(Mecanimだけでレガシーはサポートされません)。

Unity用のその他のネットワーキングソリューションと比較し、Boltはネットワーク上にてデータを送信する際に大きく異なるアプローチをとります。
シリアル化非シリアル化補間 コードを手動で書く代わりに、BoltではUnity Editorの内部から便利なインターフェイスによりデータや相互作用の定義を行うことができます。
将来的にはDSLを追加し、これにより同じものをテキスト内で定義することができるようになります

ネットワーキングアセットの定義を行う上でBoltで利用可能な編集ウィンドウは2つあります。これはBolt/Assetsウィンドウにあります。
Bolt Assets ウィンドウを開くと、完成したチュートリアルプロジェクトに付属している既存のアセットのリストを確認することができます。
まず始めに、TutorialPlayerプレハブのための状態を作成しましょう。 Bolt Assets ウィンドウ内で右クリックをして、New State を選択してください。

Bolt Assets: These includes States, Objects, Commands and Events. Use this window to create a new *State* for our player.
Bolt Assets: これらには状態、オブジェクト、コマンド、イベントが含まれます。 このウィンドウを使用してプレイヤーの新しい *状態* を作成します。

Boltが自動的に編集ウィンドウを開かない場合、新たに作成された状態である NewState をクリックしてください。
以下の手順に従って、この新しい 状態 の設定をおこないます。

  1. この状態の名前を TutorialPlayerState と設定します。
  2. 新しい Property を作成します。
  3. Transform とリネームします。
  4. タイプを Transform に変更します。
  5. ReplicationモードをEveryone Except Controllerへ変更します。;
Setup the new Bolt State `TutorialPlayerState` for using during the Advanced Tutorial
アドバンストチュートリアルで使用する新たなBolt State `TutorialPlayerState`を設定

Transformに関する特別な設定については、そのままにしておいてください。
これらによって、プロパティの優先化やアルゴリズムの円滑化などのより複雑な点について設定が可能です。
Bolt/Compile Assemblyメニュー を再度実行します。

TutorialPlayer プレハブを再度選択し、Prefab & State / State の下の Bolt Entity コンポーネント上の ITutorialPlayerStateという状態を選択してください。
これはコンパイル後にBoltが生成するコードの一部です。状態 の定義に応じた内部レプリケーション実装用のネットワークインターフェイスです。
変更を保存するため、忘れずにプレハブ内の Apply ボタンを押してください。

Select the new State *ITutorialPlayerState* to be used by the *TutorialPlayer* prefab
*TutorialPlayer* プレハブで使用する新しいState *ITutorialPlayerState* を選択

現段階で、プレハブに行うことは以上です。後で、コード経由で State を使用しネットワーク上にのせるものを設定します。

シーン読み込みコールバック

ゲーム内にキャラクターをスポーンさせるためには、サーバー上のコールバックに接続してサーバーとクライアントの両方にプレハブのインスタンスを作成する必要があります。

TutorialServerCallbacksという新規スクリプトを tutorial/Scripts/Callbacks フォルダの下に作成してください。

New `TutorialServerCallbacks` script
新しい `TutorialServerCallbacks` スクリプト

C#

using UnityEngine;

[BoltGlobalBehaviour(BoltNetworkModes.Host, "Level2")]
public class TutorialServerCallbacks : Bolt.GlobalEventListener
{

    public override void SceneLoadLocalDone(string map)
    {
        BoltNetwork.Instantiate(BoltPrefabs.TutorialPlayer);
    }

    public override void SceneLoadRemoteDone(BoltConnection connection)
    {
        BoltNetwork.Instantiate(BoltPrefabs.TutorialPlayer);
    }
}

TutorialServerCallbacksのクラスはBolt.GlobalEventListenerから継承させてください。このクラスはBoltGlobalBehaviourでデコレーションしてください。これはサーバー上での稼働および Level2 のシーンのみに対するオプションです。

シーンの読み込みに関連する2つのコールバックをオーバーライドしていきます。

  1. SceneLoadLocalDone: ローカルのコンピュータがシーンの読み込みを完了すると呼ばれます。またこの挙動はサーバー上で実行するようマークされているため、サーバー上でのみアクティブとなります。
  2. SceneLoadRemoteDone:(BoltConnection connection) に渡されている接続のリモートのエンドがシーンの読み込みを完了した際に呼び出されます。この動作もサーバー上でのみ実行されるため、クライアントが現在のシーンの読み込みを完了したときに通知されます。

どちらのメソッドについても、TutorialPlayerプレハブのコピーをインスタンス化します。
BoltPrefabsクラスにはBoltエンティティのプレハブそれぞれに対するフィールドが含まれています。そのため、その全てについて簡単にアクセスすることができます。

サーバーのインスタンスを開始するには、Bolt Scenes ウィンドウの Play As Server ボタンを押してください。
シーンの前回の開始とはあまり大きな差はありませんが、階層を見ると、TutorialPlayer プレハブのインスタンスを確認することができます。

The *TutorialPlayer* prefab instantiated on the scene
シーンでインスタンス化された *TutorialPlayer* プレハブ
The TutorialPlayer prefab instantiated on the scene
シーンでインスタンス化された`TutorialPlayer`プレハブ

サーバーと接続する個別のクライアントを構築し、起動することもできます。階層内には TutorialPlayer プレハブのインスタンスを2つ確認できます。

次章へ >>

Back to top