トップ 一覧 検索 ヘルプ RSS ログイン

unity_photon_cloud_charの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
[[Roomの作成または参加|unity_photon_cloud_room_create_join]] > [[キャラクタの同期(位置と回転のみ)|unity_photon_cloud_char_pos_rot]]
----
!!![Photon Cloud] キャラクタの同期(Demoのmonsterprefab)

PlayerがLobby/Roomへの接続と、サンプルにあるmonsterprefabのキャラクタのマルチプレイの同期は確認できました。
次に「monsterprefab」はどうやって同期を取ってるのだろう?というのを調査。
Inspectorを見てみると、いくつかScriptが割り当てられています。
{{ref_image unity_photon_char.png}}
myThirdPersonController/PhotonView/NetworkCharacter/ClickDetector/AudioRpcのスクリプトが存在。
このうち「PhotonView」はPhotonで提供されているスクリプト(Photon Unity Networking/Plugins/PhotonNetwork内)。
それ以外が、Demoプロジェクトのスクリプト。

!!monsterprefabで使っているScript
!myThirdPersonController
Assetの「Character Controller」の「ThirdPersonController」を派生させたクラス。
idle/walk/run/jumpのアニメーションを割り当て、キー操作で移動制御する汎用のスクリプトです。
PC用で、モバイルでは操作できず。

!NetworkCharacter
Photon.MonoBehaviour派生クラス。
キャラクタの位置と回転を保持している。
OnPhotonSerializeView関数のコールバックで、他のプレイヤーとキャラクタデータを送受信している模様。
この実装がないと、他のプレイヤーと位置や回転の同期ができない。
徐々に目標の位置と回転に移行させることで、いきなりワープしてくるといった挙動を抑えている。

!ClickDetector
MonoBehaviour派生クラス。
キャラクタの攻撃時の判定を行う?
なくても動作。

!AudioRpc
Photon.MonoBehaviour派生クラス。
音データをRPCを使って他のプレイヤーで再生するクラス。

!!同期処理に最低限必要な実装

Photonでの最小限の同期を行うためには、

*Resourcesフォルダにキャラクタのprefabを配置する
*prefabに、ComponentとしてPhotonViewを追加
*prefabに、ComponentとしてNetworkCharacter(キャラクタ情報の送受信)を追加
*prefabのInspector上で、NetworkCharacterをPhotonViewのObserveにドラッグして割り当て
{{ref_image unity_photon_serialize_drag.png}}
を行い、
カラのGameObjectでPhoton.MonoBehaviour 派生クラスをComponentとして追加。
OnJoinedRoomでRoomに参加したときに、
 GameObject monster = PhotonNetwork.Instantiate("monsterprefab", Vector3.zero, Quaternion.identity, 0);
としてprefabをInstantiateで実体化することにより、キャラクタの位置と回転が同期しました。

!!同期を取るための通信手段
*OnPhotonSerializeView関数コールバックを使う
*PhotonViewのRPCを使う
*[[OnPhotonSerializeView関数コールバックを使う|unity_photon_cloud_char_pos_rot]]
*[[PhotonViewのRPCを使う|unity_photon_cloud_rpc]]

の2つが代表的。他にもあるようですが、とりあえずこの2つの手段でキャラクタの同期はなんとかなりそうです。

!OnPhotonSerializeView関数コールバックを使う
DemoでのNetworkCharacter.csは以下のようになっています(日本語コメントを追加)。
 using UnityEngine;
 
 public class NetworkCharacter : Photon.MonoBehaviour {
     private Vector3 correctPlayerPos = Vector3.zero;            // We lerp towards this
     private Quaternion correctPlayerRot = Quaternion.identity;  // We lerp towards this
     // Update is called once per frame
     void Update() {
         // photonViewが自分自身ではない場合、位置と回転を反映.
         if (!photonView.isMine) {
             transform.position = Vector3.Lerp(transform.position, this.correctPlayerPos, Time.deltaTime * 5);
             transform.rotation = Quaternion.Lerp(transform.rotation, this.correctPlayerRot, Time.deltaTime * 5);
         }
     }
 
     /**
      * プレイヤー同士の位置/回転情報の同期をとる.
      * 自分のキャラクタの位置と回転を送信、自分以外のキャラクタの位置と回転を受信.
      */
     void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
         if (stream.isWriting) {
             // We own this player: send the others our data
             stream.SendNext(transform.position);
             stream.SendNext(transform.rotation);
 
             myThirdPersonController myC = GetComponent<myThirdPersonController>();
             stream.SendNext((int)myC._characterState);
         } else {
             // Network player, receive data
             this.correctPlayerPos = (Vector3)stream.ReceiveNext();
             this.correctPlayerRot = (Quaternion)stream.ReceiveNext();
 
             myThirdPersonController myC = GetComponent<myThirdPersonController>();
             myC._characterState = (CharacterState)stream.ReceiveNext();
         }
     }
 }

Update関数内で「!photonView.isMine」により自分自身でない場合、位置と回転を徐々に目標の値に移行していってます。
OnPhotonSerializeViewコールバック関数は定期的に呼ばれ、
「stream.isWriting」がtrueの場合は、自分自身の位置と回転を他のプレイヤーに対して送信。
falseの場合は、他のプレイヤーの情報を受信し、privateに保持している位置と回転の値を更新。

!PhotonViewのRPCを使う
音を鳴らすのにRPCを使ってイベントを送信。
カラのGameObjectにRandomMatchmaker(Photon.MonoBehaviour派生クラス)をComponentに追加して、OnJoinedRoom関数内でmyPhotonViewとしてPhotonViewの参照を保持。
OnGUI関数内で、
 myPhotonView.RPC("Marco", PhotonTargets.All);
としている箇所でRPCを使っています。
第一引数の"Marco"は、prefabのComponentに追加されているAudioRpcスクリプト(Photon.MonoBehaviour派生クラス)で記載。
    [RPC]
    void Marco() {
        if (!this.enabled) return;
 
        Debug.Log("Marco");
 
        this.audio.clip = marco;
        this.audio.Play();
    }

----
[[Roomの作成または参加|unity_photon_cloud_room_create_join]] > [[キャラクタの同期(位置と回転のみ)|unity_photon_cloud_char_pos_rot]]
----
{{lastmodified}}