🐷

Unity Photonチュートリアル その3

2021/09/20に公開

6.

がなくて

7. プレイヤーネットワーキング

https://doc.photonengine.com/ja-jp/pun/current/demos-and-tutorials/pun-basics-tutorial/player-networking

作成したプレイヤーのプレハブをPUN環境内で動作するように修正する。

Transformの同期
Transcriptコンポーネントを利用して、姿勢をネットワークで同期できるようにする。
PhotonTransformViewコンポーネントをプレハブに追加、追加したPhotonTransformViewをPhotonViewのObservableに追加する。
PhotonTransformViewのSynchronize PositionとRotationにチェックを入れる。

Animatorの同期
プレハブにPhotonAnimatorViewコンポーネントを追加。
PhotnViewのObservableに追加する。
Syncronized ParametersでSpeed, Direction, JumpをDiscreteに設定、HiをDisabledに設定する。
Animatorから同期するパラメータはできる限り最小限にすることが推奨。
Discreteは10回/secの頻度で同期を行い、Continueはすべてのフレームの同期を試みる。
Continueを利用する場合は、取りこぼしがなくなるがより多くのデータ通信が必要となる。

ユーザ入力の同期
ユーザが操作しているプレイヤーのプレハブ以外は別のユーザが操作しているプレハブになるため、自身のプレハブのみを操作されるようにする。
photonView.IsMineを使用することで自分の操作するプレハブかをスクリプト内で判定できる。

PlayerAnimatorManagerのUpdateの先頭でIsMineを使って自身のプレハブでない場合はreturnするように処理を追加。
ここで、PhotonNetwork.IsConnectedがtrueかどうか(オンラインであるかどうか)を合わせて評価するようにして、オフラインでの動作確認ができるようにしておく。

カメラの制御
入力と同様に、自分のプレイヤーのカメラからの映像を表示するため、自身のカメラのみ追従するような実装をいれる。
PlayerManagerのStartの先頭でGameraWorkコンポーネントを取得して、自身のプレハブであるときに、CameraWorkのOnStartFollowingをコールするようにする。
その後、CameraWorkコンポーネントのFollow On Startのチェックを外して、生成時に勝手に追従しないようにしておく。

ビームの制御
ビームも同様に自身のプレハブでないときはトリガーを検知しても表示しないようにする。
ProcessInputsの処理をIsMineでtrueになっているときのみ実行するようにする。
このままだと、自身のプレハブがビームを打っていることしか確認ができないため、IsFiringのフラグを同期するようにする。
ビームのフラグはPhotonで管理されているプロパティではなく、自前で用意したプロパティなので手動で同期を実装する必要がある。

IPunObservableを実装し、OnPhotonSerializeViewの関数内でフラグの同期処理を実装する。
修正したら、PlayerManagerのスクリプトもPhotonViewのObserve対象に追加する。

体力の同期
ビームと同様に、体力もオンラインで同期すべき自前のプロパティなので、OnPhotonSerializeViewでHealthプロパティの同期処理を実装する。

8. プレイヤーのインスタンス化

https://doc.photonengine.com/ja-jp/pun/current/demos-and-tutorials/pun-basics-tutorial/player-instantiation

GameManagerのStart(ルームに入室のタイミング)でプレイヤーのインスタンス化を行う。
GameManagerの公開フィールドにplayerPrefabを持たせて、StartメソッドでPhotonNetwork.Instantinateでインスタンスを作成する。
インスタンス化するプレハブはResourcesフォルダに配置する必要がある。
インスタンス化する座標のY軸を少し上にしてすり抜けないようにする。
PlayerManagerのスクリプトにLocalPlayerInstanceのフィールドを追加、Awakeで自身のphotonViewの時にLocalPlayerInstanceに自身のゲームオブジェクトを設定する。
GameManagerでインスタンス化する際にLocalPlayerInstanceがnullであることをチェックする。
この実装を入れることで、プレイヤーが増えて新しいシーンがロードされる際の無駄なインスタンス化を避ける。

最後に、レベルのロード時にフィールドのサイズが変わった際にフィールド外にいることを考慮してレベルのロード時にフィールド外に出てしまった場合は、中央に戻す実装を追加する。

9. プレイヤーUI

https://doc.photonengine.com/ja-jp/pun/current/demos-and-tutorials/pun-basics-tutorial/player-ui-prefab

プレイヤーUIを作成して名前と体力を表示する。
PlayerManagerでプレハブ化したUIをインスタンス化して、プレハブをプレイヤーに追従させる。

作業用に、適当なCanvasがあるシーンを開く。
スライダーをCanvasに追加。レイアウトと色を調整する。
追加したスライダーのchildにテキストを追加。
テキストをPlayer Name Textという名前にする。
スライダーにCanvasGroupのコンポーネントを追加。
InteractableとBlocks Raycastをfalseにする。
作成したスライダーをプレハブ化する。
作業用に作成したオブジェクトをシーンから削除する。

PlayerUIのスクリプトを作成して、作成したプレハブにアタッチする。
PlayerUIのTextにはPlayer Name Textを、Sliderにはスライダーのコンポーネントをアタッチする。

PlayerUIのスクリプトにPlayerManagerのフィールドを追加。PlayerUIにSetTargetのメソッドを追加。
Updateメソッドの中でスライダーに体力を設定するように実装。

プレイヤープレハブのインスタンスを作成するタイミングで、UIのインスタンスも作成するようにする。
PlayerManagerのスクリプトにplayerUiPrefabのフィールドを追加。
StartメソッドにplayerUiPrefabのインスタンス生成の実装と、playerUiPrefabのSetTargetをコールする実装を追加。
SetTargetの呼び出しは、直接インスタンスに対して行うこともできるが、SendMessageを使ってコールすることもできる。

Playerがいなくなった際に、Player UIを削除する。
PlayerUIのUpdateでtargetがnullになっていたら自身のゲームオブジェクトを削除する。
自身で自身のオブジェクトを削除することで、Photonによってプレイヤーのオブジェクトが削除されたときに合わせてUIも消えるようになる。

PlayerUIのAwakeでCanvasを検索して自身の座標をキャンバスに合わせて配置するようにする。
GameObject.Findを使用しているが、この方法はパフォーマンスがよくないので非推奨。

最後に、作成したUIのインスタンスがプレイヤーを追従するようにする。
フィールドを追加して、座標を計算してLateUpdateで座標を設定する。
カメラのWorldToScreenPointを使用することで、ワールド座標から対象の座標を計算することができる。

Discussion