Photon Bolt | 他プレイヤーが作ったゲームオブジェクトをDestroyする


はじめに

Photon BoltはUnityで簡単にオンラインゲームを作れるUnityソリューションです。
今回は僕自身が困った他人が作ったゲームオブジェクトを破壊する方法を僕自身のために書いていこうと思います。

やりたいこと

他人が作ったゲームオブジェクト(エンティティ)をDestroyしたい。

起きている問題

Photon BoltBoltNetwork.Destroy()を行うと、オンライン上のゲームオブジェクトを破壊することができますが、他プレイヤーが生成したゲームオブジェクトを破壊することはできません。

他人が作ったゲームオブジェクトをBoltNetwork.Destroy()すると、以下のように表示されて正常に破棄されません。

Only the owner can destroy an entity, ignoring call to Destroy().

オーナーシップの概要

エンティティのオーナーシップを参照。

オーナーシップはBoltNetwork.Instantiate()でエンティティを生成した者にのみ付与され、それを譲与することはできません。

オーナーのデバイスでBoltEntity.isOwnerするとtrueを戻します。
今回はこれを使って他人のゲームオブジェクトを破壊します。

実際に組んでみる

1. イベントを作成する

イベントを使うことでルームに参加している人の一部もしくは全員に同じ処理を実行させることができます。

  1. BoltタブのAssetsBolt Assetsを開く
  2. ウィンドウ上で右クリックしてNew Eventをクリック
  3. Event名を DestroyRequest にする
  4. New Propertyから新しいプロパティを作成し、その型をEntityに設定
  5. 新しいプロパティの名前を entity にする
  6. BoltタブからCompile Assemblyでコンパイルする

ゲームオブジェクトを破壊するリクエストとエンティティ(Bolt Entity)を送信するためのイベントを作成しました。エンティティを破壊するときはこのイベントを呼び出します。

Compile Assemblyは、Bolt上に何か変更を与えた時に毎回行ってください。

2. イベントを受け取る処理を書く

ここでは、ゲームオブジェクトの破壊をリクエストを受け取る機能を付けます。

  1. 新しいスクリプトを作成し、名前をNetworkCallbacksに変更
  2. classよりも上にusing Bolt;を追加
  3. MonoBehaviourGlobalEventListenerに変更
  4. 以下のコードをクラス内に記述し、Compile Assembly を実行
    public override void OnEvent(DestroyRequest evnt)
    {
        //送られてきたentityの持ち主が自分かどうかを確認し、そうであればDestroyする
        if (evnt.entity.IsOwner)
            BoltNetwork.Destroy(evnt.entity.gameObject);
    }
3. イベントを送信する処理を書く

2. イベントを受け取る処理を書くで作成した受付係に送信する機能を作ります。

  1. 今までBoltNetwork.Destroy()していた部分を以下に上書き
    //破壊したいゲームオブジェクトのエンティティ
    BoltEntity ent;

   //シングルプレイの場合、リクエストを送らずそのまま破壊
    if (BoltNetwork.IsSinglePlayer)
        Destroy(gameObject);
    else
    {
        //DestroyRequestを作成し、entityにentをセットしてから送信
        var request = DestroyRequest.Create();
        request.entity = ent;
        request.Send();
    }  

※送信できるのはBoltEntityのみです。GameObjectをそのまま送信することはできないのでGetComponent<BoltEntity>()してから送信しましょう。

  1. Compile Assembly を実行

注意点

ネットワークを使用しているので当然「破壊リクエスト」→「ネットワーク上で破壊」→「クライアントで破壊」までのプロセスでラグが発生します。

その間にもう一度「破壊リクエスト」を送信してしまうと、存在しないエンティティとしてエラーが発生してしまいます。

「破壊リクエスト」を送信する前に、オブジェクトのコライダーを無効化したり、リクエスト中の新たなリクエストを無視するなど対策が必要です。

間違えていたら

もしこの記事の内容に間違えがあったらコメントで指摘をお願いします