【WIP】これだけでPUNにおける通信は9割わかる

0. はじめに

◆ 必要なAssetのインストール

基本的な通信であれば、必要なのはPhoton Unity Networkingだけ。Asset Storeでインストールしましょう。
インストール諸々は記事いっぱいあるし簡単なんで自分でやリましょう。

◆ そもそもファイルがごちゃごちゃインストールされて何が何だか、、、

公式リファランスを見るとこうあります。

PUN(Photon Unity Networkingの略)は多数のファイルで構成されます。しかし重要なのはたった1つ: PhotonNetwork です。このクラスは必要とされるすべての関数と変数を含んでいます。さらに独自の要件がある場合、いつでもソースファイルを編集可能です。なにしろこのプラグインはPhotonの実装そのものなのですから。

インポートの際に多くのファイルがインストールされますがおどおどする必要はありません。つまるところPhotonに関して定義されたメソッドや変数に関する定義をいじりたい場合には PhotonNetwork という名のファイルだけ見ればいいんです。かと言って 基本的にはこれらのファイルは全くいじらなくても実装できます ので最初のうちは無視で行きましょう。

◆ どこにスクリプトを書くか

実際のところ、Photonに関するメソッドや変数はどのファイルでも同じように昨日するものがほとんどです。ですが僕のオススメはPhotonControllerや、NetworkManagerの様な名前の空のGameObjectを作成して、同名のファイルをアタッチしてあげる形です。接続に関するメソッドは全部そいつに任せてしまい、必要があれば他のクラスからそのメソッドを叩く様にすれば。

1. サーバー接続について

◆ PUNのサーバー接続の仕組み

PUNのサーバー接続は以下の図のように通信全体を統括する一つのマスターサーバーと複数のユーザーの個々のゲームサーバーの接続で成り立っています。
photonserver.png

☆ マスターサーバーとは

1つのサーバーでゲームを回してそれを傍受している様に思えますが実はそうではありません。Photonでの通信では、userそれぞれのサーバーでそれぞれゲームが回っていて、それをマスターサーバーが統括するという形になっています。

◆ 具体的なサーバー接続方法

1. ConnectUsingSettingsを使う場合

PhotonNetwork.ConnectUsingSettings(string gameVersion);

・サーバー接続の基本的なメソッド

これまでにWizard形式で設定していった PhotonServerSettings ファイルにしたがって Photon 及び Photon Cloud に接続するメソッド。普通に開発してたら使うのはまあこっちです。

・引数にはstringでGameVersionを取る

GameVersion ってなによと思うかもしれませんが、実はこれ文字列ならなんでもよくて、自分で勝手に決めてしまって大丈夫です。この GameVersion は 同一アプリでマッチングを分けたい場合(アプリのバージョンが違う場合等)にゲームバージョンをそれぞれ指定し、マッチングを回避する 目的で使用されます。ややこしく聞こえますが、平たく言えば

『モンスターハンターの 2nd と 3rd は同じゲーム名だけど色々違うとこあるから通信できちゃったら困るよね。だからVersionが違うもの同士はマッチングしないようにしよう』

ということです。使わないのであれば null を渡してしまってください。

2. ConnectToMaster を使う場合

static bool PhotonNetwork.ConnectToMaster
(
  string masterServerAddress,
  int    port,
  string appID,
  string gameVersion 
)       

設定ファイルを無視して全パラメータを自分で指定するやり方です。ややこしいし積極的に選択する理由を見つけられていないので使っていません。

◆ 接続に失敗した時

原因としては主に以下の3つが考えられます。呼び出される関数の違いにも注意しましょう。

1. ConnectUsingSettingsに登録された AppId が正しくない

Photon のホームページで取得した AppId と ConnectUsingSettings に登録されたものが対応してません、凡ミスですね。

OnFailedToConnectToPhoton()

が呼ばれます。ConnectUsingSettingsのInspector Viewで確認可能です。

Unity_5_5_2f1_Personal__64bit__-_Start_unity_-_FPS_Space_-_PC__Mac___Linux_Standalone__Personal___OpenGL_4_1_.png

2. ネットワークの問題

単純に接続に問題がある場合です。ネットワーク接続(WiFiなど)を見直しましょう。同様に

OnFailedToConnectToPhoton()

が呼ばれます。

3. PhotonServerSettingsに登録された Region が正しくない

PUNのマスターサーバーは世界各地に点在しています。きちんとJpのものを利用しましょう。ConnectUsingSettingsのInspector Viewで設定可能です。
Unity_5_5_2f1_Personal__64bit__-_Start_unity_-_FPS_Space_-_PC__Mac___Linux_Standalone__Personal___OpenGL_4_1_.png

2. ロビーとルームについて

◆ ロビーとルームの関係

通信をするにあたってuserはロビー及びルームに入るのですが、この微妙な命名のせいで直感的にわかりづらいですね。
ロビーはめっちゃ大きい家、ルームはその中にある部屋だと思ってください。リレーションっぽく書くと Lobby has many Rooms であり Rooms belongs to Lobbyです。

◆ ロビーについて

・ロビーのクラスについて

ロビーは TypedLobby クラスという名前のサーバー上の特定のロビー(と種別)を参照するクラスに司られています。NameLobbyType の属性を持ち、これらの値の組み合わせでロビーを判別しています

TypedLobby.TypedLobby ( 
  string    name,
  LobbyType type 
)   

LobbyType とはロビー種別のオプションで、enumで定義されています。なお詳しいVersionは不明ですが、古いサーバーでは使用できないらしいので注意してください。

Enumerator About
Default いずれかのサーバーで指定されない限りデフォルトでこの値になります。JoinRandomRoomにてプロパティマッチングでフィルタリングすることが可能です
SqlLobby
AsyncRandomLobby

・デフォルトの設定ではロビーは一つ

特にロビーに関する設定をいじらなかった場合、ロビーは1つだけ自動で作成され、これを使用することになります。このロビーを デフォルトロビー と呼びます。デフォルトロビーに入るには

#引数なしで
bool PhotonNetwork.JoinLobby()

というメソッドを使用します(引数なし)。

しかし、デフォルトロビー1つのみを使用する場合はこの記述を省略できる設定があります。 PhotonServerSettings ファイルを見つけてきて Inspector View で Auto-Join Lobby にチェックを入れましょう。

Unity_5_5_2f1_Personal__64bit__-_Start_unity_-_FPS_Space_-_PC__Mac___Linux_Standalone__Personal___OpenGL_4_1_.png

Photonサーバーへの接続と同時にデフォルトロビーにJoinする様になります。

・ロビーを複数用意することも可能

1つのロビーが持つルームの数に上限はないので、サービスが拡大するとルームの数が尋常ではないことになり管理しにくくなります。そこでロビーを複数用意することが可能になっています(それ以外にも理由は色々と考えられますが)。指定のロビーに参加するためには以下のメソッドを用います。

bool PhotonNetwork.JoinLobby( TypedLobby typedLobby ) 

引数に TypedLobby クラスのインスタンスを渡すことで、そのロビーに入ることができます。

・ロビーに入った時点で OnJoinedLobby() メソッドが呼ばれる

ロビーに入った瞬間実行したい処理はこのメソッド内に記載します。例えばロビーに入った瞬間に、そのロビーに存在するルームの中からランダムに一つ選んで入室したい場合は、

void OnJoinedLobby(){
  #このメソッドについては後述します
  PhotonNetwork.JoinRandomRoom();
}

の様に記述します。
しかし、詳しくは後述しますが Room一覧の取得はこの中でしてはいけない ので注意が必要です。Room一覧を取得する際には必ず void OnReceivedRoomListUpdate() というメソッド内で行うので注意しましょう。

◆ ルームについて

・ルームのクラスについて

RoomOptionsクラスについて

名前の通り、ルームに関する設定を司どるクラスです。たくさんの属性やプロパティを持っていますが、ここではよく使用するものに限定して紹介したいと思います。もし深く知りたければ以下の二つの記事をご参照ください。

  • < 属性 > maxPlayers (byte型)

  • < 属性 > customRoomProperties (Hashtable型)

    これこそがRoomOptionsの真骨頂です。Room全体で共有しておきたい事項をHashの形で

・ルームの作成

ロビーとは違いルームは実際にプレイヤー同士が通信を行う場所なのでユーザーが自由に作成し、参加できるべきです。そのためルームはデフォルトで様々な属性やメソッドを持っています。PhotonNetworkクラスには簡単なものから自分で設定を書き加えられるものまで、クラス作成のためのメソッドが複数用意されています。

1. CreateRoom(引数1つの場合)

最も簡単なルームの作成方法で

PhotonNetwork.CreateRoom (string roomName)  

の様に名前( Name )のみを与えてあげてルームを作成します。ロビー内において、ルームはこの Name で判別されるので、 1つのロビー内に同名のグループを複数作成することはできません 。別のロビーであればもちろん同じ名前のルームが存在していても全く問題ありません。
もしめんどくさかったり、一意的な(つまりダブりがない)Nameを与え続ける自信がなく、かつルームの名前にこだわりがない場合は null もしくは "" を引数として渡すと、サーバーが勝手にNameに割り当ててくれるので便利です。

2. CreateRoom(引数3つの場合)
以下のようにルームの名前( Name )、ルームのオプション( RoomOptions )、ロビーの情報( TypedLobby )を与えてルームを作成します。

PhotonNetwork.CreateRoom (
  string      roomName,
  RoomOptions roomOptions,
  TypedLobby  typedLobby 
)   

めんどくさい様に見えてかなり役に立ちます。

TypedLobbyにロビーを設定すると、 どのロビーがアクティブかに関わらずそのロビーの下にルームが作成されます。それだけではなく、仮にその条件のロビーが存在しない場合、勝手に作成してその下にルームを作成してくれます。破壊力がすごい、、、。ちなみに null を渡すと、自動的に現在アクティブなロビーの下に作成されるという優しい設計です。

・ルームへのJoin

Joinの仕方も様々です。

Special Thanks

うら干物書き … 実装に当たって、最初から最後までびっくりするくらいお世話になりました。わかりやすさ、及び情報量、どちらをとっても最高です。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.