PhotonUnity技術ブログ

よくわかる?! Photonの仕組み??!

 

・Photonとは??

Photonとは、リアルタイムマルチプレイ通信のプラットフォームになります!

ここでは、Unity用のパッケージであるPUN(Photon Unity Networking)について解説していきます。

同時接続(CCU)20人まで無料で使えます。

・導入事例:動物タワーバトルとか・・・VRチャットとか・・・

動物タワーバトル

聖剣伝説RISE

VR上での他のプレイヤー情報同期で最近はPhotonが主流で使われている印象です。

 

・目次

この先、解説を行う項目一覧です!

・部屋の概念
・部屋入室までの流れ(各種ステート紹介)
・Roomについて・・Roomとは?
・RoomのName CustomPropaty
・PlayerについてName CustomPropaty
・PhotonViewについて:需要!ゲーム中で同期されるオブジェクト
・PhotonViewのIsLocal
・PhotonViewのOwnerとOwner以外
・RPCについて
・まとめ

これらの項目を体型的に解説していきます!

・Roomの概念

Room(部屋)とは??

Roomとは、Photonにおいて各プレイヤーの通信の同期が行われる状態になります。

各プレイヤーや部屋、PhotonView(Photonの同期対象に指定するための重要なスクリプト)がアタッチされたオブジェクトのパラメーターがリアルタイムで同期されている状態になります。

部屋はPhotonのApiを通して作成可能です。

・Room入室までの流れ(各種ステート紹介)

こちらがRoom入室までのフローチャートになります。

・Room入室までのコードサンプル


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace FriendsHirataSoft
{
    public class FHConnectAndJoinLobby : MonoBehaviour
    {
        //任意のバージョン識別用の文字列を入れます。
        const string Version = "1";

        void Start()
        {
            //今回は、Lobbyへ遷移後に部屋一覧を確認したいので autoJoinLobbyをtrueにします。
            //部屋一覧に飛ばず直接部屋に遷移したい場合などにこのフラグをfalseにします。
            PhotonNetwork.autoJoinLobby = true;
        }

        public void ConnectToPhoton(){
            if (PhotonNetwork.connecting) return;
            PhotonNetwork.ConnectUsingSettings(Version + "");
        }

    }
}

上記のコードでは、ConnectToPhotonが実行された時にPhotonに接続されます。

また、Photon接続後に各種状態遷移後にLobbyにjoinした状態になります。

・Lobbyとは?

Lobbyにいる状態であれば、部屋作成や部屋一覧の取得、部屋への入室が可能です。

また、部屋の作成及び、部屋一覧の取得、選択した部屋への入室のサンプルコードは以下になります。

・部屋の作成


PhotonNetwork.CreateRoom("重複しない部屋名");

※すでに存在する部屋名で作成を試みた場合は、部屋の作成に失敗し、エラーが返って来ます。

・部屋一覧の取得


PhotonNetwork.GetRoomList()

GetRoomList()により部屋情報がRoomInfo[]の配列として返って来ます。

・部屋への入室


PhotonNetwork.JoinRoom("入室したい部屋名");

上記コードで部屋に入室できます。
部屋名は、RoomInfo.Nameから参照可能です。

・RoomのNameとRoomOptions,CustomPropety

PhotonのRoomには、NameとRoomOptionsとCustomPropetyという値を保持させることができます。

・Nameとは?

PhotonでRoomを作成するときに必ずNameをつけて作成されます。

Nameは重複するこでができず、(そのため各部屋の識別に使用することが可能です。)

部屋作成時にすでに同じNameのRoomがあった場合はエラーが返ってきます。

また、Roomには、CustomPropetyと呼ばれる任意のキーと値を入れて同期させることが可能なPropetyも用意されています。

・RoomOptionsとは?

部屋の各Optionを設定し値を同期できるようになっています。

以下のようなOptionを設定可能です。

  • ・IsVisible:Lobby上で部屋の一覧で表示されるか否か

  • ・IsOpen:部屋がOpenしているかどうか?(Lobbyでは部屋一覧で取得できるが、入室はできない状態)

  • ・MaxPlayers:部屋に入ることが可能な最大人数

  • ・CustomRoomPropety:任意の値を入れて同期可能です。詳しくは次の項の記載を参照

  • ・etc….その他にもプレイヤー切断時の設定や部屋の生存時間設定など部屋に関する設定を行うことができます。

・CustomRoomPropetyとは?

NameやRoomOptions以外で他に同期させたい値があるときなどに使用します。

中身はKeyとvalueがペアになっているDictionaryとなっています。

このCustomPropetyに例えば、

  • ・Roomのアイテム情報

  • ・RoomのMap情報

  • ・Roomのゲーム進行状況

  • ・部屋に付随する情報・・・etc・・・

等、Roomに付随する任意の値を入れて同期させることが可能です。

・Roomの実際のコードサンプル

・RoomのName


PhotonNetwork.room.name

・RoomのOption


 PhotonNetwork.room.MaxPlayers = 4;

・RoomのCustomRoomPropety

値を設定する場合

PhotonNetwork.room.SetCustomProperties(new ExitGames.Client.Photon.Hashtable() { { "キー名", "値" } });

Photon.Hashtableは「キー名」と「値」共にobject型となっていて任意の値を指定することができます。

値を取得する場合

float remainingTime = (キャストを行いたい型)PhotonNetwork.room.customProperties["キー名"];

PhotonNetwork.room.customPropertiesから「キー名」で取得後に任意の型にキャストして取得します。

・PlayerについてUserIdとCustomPropety

Playerとは、PhotonにおいてRoomに入室中の各クライアントを表す概念です。

コード上では、

PhotonNetwork player

から自分のプレイヤー情報を、

PhotonNetwork.playerList

からRoom中のプレイヤー情報一覧を獲得できます。

・PhotonPlayer.UserID

各プレイヤーを識別するためのID

・その他PhotonPlayer中の値

Scoreなどのゲーム中における代表的な値やNameなどは、PhotonPlayer中に初めからあるので

任意の値を入れて同期可能です。

・PhotonPlayer.CustomPropety

PhotonPlayer中の値で任意の同期させたい値を設定したいときに使用します。

中身はKeyとvalueがペアになっているDictionaryとなっています。

このCustomPropetyに例えば、

  • HPやATKなどのプレイヤーのステータス情報
  • 毒や麻痺などのステータス異常
  • バフやデバフなどの情報
  • etc・・・

等、Playerに付随する任意の値を入れて同期させることが可能です。

・Player実際のコード例

 

値を設定する場合

PhotonNetwork.player.SetCustomProperties(new ExitGames.Client.Photon.Hashtable() { { "キー名", "値" } });

Photon.Hashtableは「キー名」と「値」共にobject型となっていて任意の値を指定することができます。

値を取得する場合

float remainingTime = (キャストを行いたい型)PhotonNetwork.player.customProperties["キー名"];

PhotonNetwork.room.customPropertiesから「キー名」で取得後に任意の型にキャストして取得します。

・PhotonViewについて:需要!ゲーム中で同期されるオブジェクト

PhotonViewとはPhotonの同期対象に装着して使うスクリプトコンポーネントです。(重要!)

メッセージ送信(RPCとOnSerializePhotonView)に使われます。

アタッチされたゲームオブジェクトの位置情報やその他指定した値のリアルタイム同期が可能です。

 

・PhotonViewのOwnerとOwner以外

PhotonViewにはowner(型はPhotonPlayer)という値がありここで、そのPhotonViewを所有しているOwner情報を取得することができます。

またPhotonViewには、isMineという値がありここでPhotonViewを所有しているか否かを判別できます。

所有者とそれ以外の違いは以下になります。

  • 所有者->値を送信してする側
  • 所有者以外->値を受信する側

また、PhotonViewのオーナーになるには、以下の方法があります。

・Photon専用のPrefab生成メソッドを使う

PhotonNetwork.Instantiateを使うことで、自分がOwnerとなっているPhotonViewがアタッチされたPrefabをInstantiateできます。

生成例

PhotonNetwork.Instantiate("Prefab名", Vector3.zero, Quaternion.identity, 0);

こちら、PhotonNetwork.InstantiateというメソッドでPrefabをゲーム中にインスタンス化できます。
また注意点がありまして、対象のPrefabはResourcesフォルダの直下に入っている必要があります。

・所有権を切り替えるメソッドを使う

PhotonView.TransferOwnership(対象のPlayerId)を使うことで

所有権(Ownership)を他のプレイヤーに譲渡できます。

・PhotonViewのRPCについて

PhotonViewにはRPCの機能もあります。

RPC(RPC、リモートプロシージャコール)とは?

自分のプログラム上から別のアドレス空間(別のコンピュータ上)
にあるメソッドを実行する技術のことです。

・実際のコード例


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhotonRPCSample : MonoBehaviour {

    PhotonView photonView;

    void Start()
    {
        photonView = GetComponent();
    }

    //引数を何も指定しない場合
    void SampleRPC()
    {
        photonView.RPC("DoneRPC", PhotonTargets.All);
    }


    [PunRPC]
    void DoneRPC()
    {
        //なんらかの処理
    }

    //引数を指定する場合など
    void SampleRPC2(int val,float val2,string val3)
    {
        photonView.RPC("DoneRPC2", PhotonTargets.All,new object[]{val, val2, val3});
    }


    [PunRPC]
    void DoneRPC2(int val, float val2, string val3)
    {
        //なんらかの処理
    }
}

上記の例では、SampleRPCもしくは、SampleRPC2を実行した時にRPCが発火します。
引数を指定する場合は、object[]{val, val2, val3・・・・}というような形でobjectの配列で値を渡してやればOKです。

・まとめ

こちら、ざっくりとですがPhotonの大まかな概要や使い方などがざっくりイメージできたかと思います。

取り急ぎ、今回の解説で使いましたサンプルゲームを作成しましたのでこちらも合わせて見ると理解しやすいかもしれません。

最後まで見てくださりありがとうございました!