週刊SleepNel新聞

SleepNel所属のぽうひろが日々の個人開発で気になったことを綴ります。

Unity Photon(PUN+) の使い方 ロビー・ルーム編(3/5)

第2回ではPhoton、PUN(+)の導入手順などを説明しました。

PUN+はこちらで購入できます!

今回はいよいよ実践。Photonの重要な概念であるロビーとルームについて説明します。

Photonにはロビーとルームという概念があります。
ロビーはプレイヤーの待機空間、ルームは対戦部屋と考えると分かりやすいです。
Photonに接続したらまずはロビーに入る必要があります。
導入編でPhotonServerSettingsの設定でAuto-Join Lobbyにチェックを入れたと思いますが、これによってPhoton接続と同時にロビーに入ることができます。
ロビーに入らないとルームを見ることはできません。

まずはPhotonManagerという空のGameObjectを作り、PhotonManager.csを作成して
アタッチしましょう。
f:id:pouhiroshi:20160529073132p:plain

通常MonoBehaviourを継承したクラスを作りますが、Photonを使う場合は
Photon.MonoBehaviourを継承したクラスにします。

public class PhotonManager : Photon.MonoBehaviour

ではPhotonに接続するコードを書きましょう。
ConnectPhotonというメソッドを定義し、PhotonNetwork.ConnectUsingSettingsを呼び出します。

PhotonNetwork.ConnectUsingSettings("v1.0");

ConnectUsingSettingsの引数に指定しているv1.0という文字列ですが、
これは何でも構いません。
もしリリース後のアップデート対応などで、アプリを最新化していないプレイヤーと
最新化済みのユーザ同士で対戦させたくない場合、最新側で例えばv1.1などとして、
文字列を変えれば、ロビー空間を別にすることができ、バージョンの違いによる不具合を
出さないようにすることができます。

さて、PhotonNetwork.ConnectUsingSettingsすると、
Auto-Join Lobbyなので、勝手にロビーに入ります。
ロビーに入るとPhotonManagerで定義したOnJoinedLobbyがコールバックで呼ばれます。

void OnJoinedLobby ()
{
    Debug.Log ("PhotonManager OnJoinedLobby");
}

ロビーに入らないと、ルームに対する操作(ルーム一覧、入室、作成)ができません。
OnJoinedLobby内でルーム一覧取ったりすると良いですね。

ではこの状態で動かしてみましょう。
Photon接続ボタンを作って、PhotonManagerのConnectPhoton()を呼び出すようにします。
f:id:pouhiroshi:20160529073609p:plain

f:id:pouhiroshi:20160529073535p:plain

はい、コンソールログに
PhotonManager OnJoinedLobbyというログが出ましたね。
これでPhoton接続、ロビー入室できました。

次にルームを作って入室しましょう。
PhotonManager.csにCreateRoomというメソッドを定義して、呼び出すことにします。

//ルーム作成
    public void CreateRoom(){
        string userName = "ユーザ1";
        string userId = "user1";
        PhotonNetwork.autoCleanUpPlayerObjects = false;
        //カスタムプロパティ
        ExitGames.Client.Photon.Hashtable customProp = new ExitGames.Client.Photon.Hashtable();
        customProp.Add ("userName", userName); //ユーザ名
        customProp.Add ("userId", userId); //ユーザID
        PhotonNetwork.SetPlayerCustomProperties(customProp);

        RoomOptions roomOptions = new RoomOptions ();
        roomOptions.customRoomProperties = customProp;
        //ロビーで見えるルーム情報としてカスタムプロパティのuserName,userIdを使いますよという宣言
        roomOptions.customRoomPropertiesForLobby = new string[]{ "userName","userId"};
        roomOptions.maxPlayers = 2; //部屋の最大人数
        roomOptions.isOpen = true; //入室許可する
        roomOptions.isVisible = true; //ロビーから見えるようにする
        //userIdが名前のルームがなければ作って入室、あれば普通に入室する。
        PhotonNetwork.JoinOrCreateRoom (userId, roomOptions, null);
    }

入室に成功するとOnJoinedRoomがコールバックで呼び出されますので、
ここでキャラクターなどのプレイヤー間で共有するGameObjectを作成すると良いです。
確認のため、一旦ログを出すだけにします。

//ルーム入室した時に呼ばれるコールバックメソッド
void OnJoinedRoom() {
    Debug.Log ("PhotonManager OnJoinedRoom");
}

ではまたこの状態で動かしてみましょう。
今度はルーム作成&入室ボタンを作ります。
ボタン押下で、PhotonManagerのCreateRoomを呼ぶようにします。
f:id:pouhiroshi:20160529073732p:plain

ロビーに入ったらルーム作成できるように、ボタンのInteractableチェックをOFFしておき、OnJoinedLobbyでチェックを入れるようにします。

void OnJoinedLobby ()
    {
        Debug.Log ("PhotonManager OnJoinedLobby");
        //ボタンを押せるようにする
        GameObject.Find ("CreateRoomB").GetComponent<Button> ().interactable = true;
    }

まずはPhoton接続ボタンを押します。
f:id:pouhiroshi:20160529073814p:plain

OnJoinedLobbyログと、ルーム作成&入室ボタンがActiveになりましたね。
f:id:pouhiroshi:20160529073951p:plain

ルーム作成&入室ボタンを押してみましょう。
OnJoinedRoomログが出ました。
f:id:pouhiroshi:20160529074005p:plain

これでルーム入室まで完了しました。

ルーム入室したら、他のプレイヤーが入室してくるのを待つことになります。
ルームの一覧はロビーにいる時しか見ることができません。(ルームに入っていると
見えない)
ルーム一覧はRoomInfo[] rooms = PhotonNetwork.GetRoomList();
で取得できます。
OnJoinedLobbyでルーム一覧を取りたいところですが、
実はこのGetRoomList();が曲者で、ただ単純に呼び出してもルーム一覧が取れません。
ルーム一覧は非同期で遅れたタイミングでサーバから結果が返ってくるらしく、
そのタイミングでOnReceivedRoomListUpdate関数がコールバックされるので、

そこでGetRoomListを呼び出して最新の一覧を取得することになります。

RoomInfoにはルーム作成された時のroomOptions.customRoomPropertiesForLobby
で設定したプロパティを取得することができます。
これを使ってルーム一覧を表示してみましょう。

//ロビー入室時に呼ばれるコールバックメソッドを定義
    void OnJoinedLobby ()
    {
        Debug.Log ("PhotonManager OnJoinedLobby");
        //ボタンを押せるようにする
        GameObject.Find ("CreateRoomB").GetComponent<Button> ().interactable = true;

    }

    //ルーム一覧が取れると
    void OnReceivedRoomListUpdate(){
        //ルーム一覧を取る
        RoomInfo[] rooms = PhotonNetwork.GetRoomList();
        if (rooms.Length == 0) {
            Debug.Log ("ルームが一つもありません");
        } else {
            //ルームが1件以上ある時ループでRoomInfo情報をログ出力
            for (int i = 0; i < rooms.Length; i++) {
                Debug.Log ("RoomName:"   + rooms [i].name);
                Debug.Log ("userName:" + rooms[i].customProperties["userName"]);
                Debug.Log ("userId:"   + rooms[i].customProperties["userId"]);
                GameObject.Find("StatusText").GetComponent<Text>().text = rooms [i].name;
            }
        }
    }

ここからは2端末でテストします。1台はUnityEditor上、もう1台はAndroid
実行します。

Android版でビルドします。
シーンをビルド対象に入れるのをお忘れなく!
(BunldeIdentifierをちゃんと設定する必要があるみたいです。)

では、テストをしましょう。Android版でロビー入室、ルーム作成までします。
f:id:pouhiroshi:20160529074327p:plain
ルームに入りましたね。

この状態で、UnityEditor側で実行します。

ルームリストが見れました。
f:id:pouhiroshi:20160529075914p:plain

ではルーム入室ボタンをつけましょう。
f:id:pouhiroshi:20160529080056p:plain
ルーム入室はPhotonNetwork.JoinRoom(string roomName)でできます。
roomNameはPhotonNetwork.JoinOrCreateRoom (userId, roomOptions, null);
でuser1という名前で作っていますので、
PhotonNetwork.JoinRoom(“user1”);
で入ることができます。

public void JoinRoom(){
		PhotonNetwork.JoinRoom("user1");
}

//ルーム入室した時に呼ばれるコールバックメソッド
void OnJoinedRoom() {
	Debug.Log ("PhotonManager OnJoinedRoom");
	GameObject.Find("StatusText").GetComponent<Text>().text = "OnJoinedRoom";
}

やってみましょう。
f:id:pouhiroshi:20160529075958p:plain
部屋に入れましたね!

次は、さらに突っ込んでオブジェクトの同期について説明したいと思います!!


ではでは!