1 - ロビー
サーバーへの接続、およびルームへのアクセスとルームの作成
まずはこのチュートリアルの核心である、Photon Cloudサーバーへの接続とルームの作成や参加に取り組みましょう。
- 新しいシーンを作成し、Launcher.unityとして保存します。
- 新しいC#のスクリプト Launcherを作成します。
- HierarchyにLauncherという名前の空のGameObject を作成します。
- GameObject LauncherにC#のスクリプトLauncherを添付します。
- C#のスクリプトLauncherを編集して、コンテンツを以下のようにします。
ここまでのスクリプトの内容を確認しましょう。まずはUnityの視点から確認して、次にPUN固有の呼び出しを見てみましょう。
- Namespace: 
 必須ではありませんが、スクリプトに適切なnamespaceを与えることで他のアセットや開発者との競合を防ぐことができます。
 別の開発者がクラスLauncherを作成したらどうなるでしょう?Unityは警告を出し、あなた、またはその開発者はUnityがプロジェクトを実行できるようにクラス名を変更する必要があります。
 競合がAsset Storeからダウンロードしたアセットに起因する場合、注意が必要です。
 Launcher クラスは、実際はCom.MyCompany.MyGame.launcherで、あなたが所有しているドメインを使用しています。このため、完全に同一のNamespaceを他の誰かが使用する可能性は非常に低いです。逆ドメイン規則をnamespaceとして使用することによって、安全に作業できます。
 Com.MyCompany.MyGameは独自の逆ドメイン名とゲーム名で置き換えられます。これは、従うべき良い慣習 です。
- MonoBehaviour Class クラス: 
 クラスをUnity Componentに変換してGameObjectまたはプレハブにドロップできるようにするため、クラスをMonoBehaviourで派生していることに注目してください。
 MonoBehaviourを拡張するクラスは、多くの非常に重要なメソッドとプロパティにアクセスすることができます。
 このケースでは、2つのコールバックメソッド、Awake()とStart()を使用します。
- PhotonNetwork.autoJoinLobby: 
 Awake()の間は ロビー機能が不要で、既存ルームのリストのみが必要なためPhotonNetwork.autoJoinLobbyをfalseに設定します。
 同じプロジェクトで実際にロビーにautoJoinしたいシーンがあるかも知れないので、この設定は強制的におこなってください。これによって、両方のケースが同一プロジェクト内に存在しても、2つの異なるアプローチ間で切り替える際の潜在的な問題を避けることができます。
- PhotonNetwork.ConnectUsingSettings(): 
 Start()時にPhotonNetwork.ConnectUsingSettings()を使用してPhoton Cloudにパブリック関数の- connect()を
 呼び出します。- _gameVersion変数がgameversionを表しています。既に公
 開済みのプロジェクトに重大な変更を加える時以外は、これを- 「1」にしておいてください。ここで覚えておくべき重要な 情報は、ゲームをネットワーク化してPhoton Cloudに接続 するための起
 点PhotonNetwork.ConnectUsingSettings()であるということです。
PhotonNetwork.automaticallySyncScene
- MasterClientはPhotonNetwork.LoadLevel() を呼び出し、接続したすべてのプレイヤーは自動的に同じレベルを読み込みます。
この時点で、Launchシーンを保存してPhotonSettings (UnityのメニューWindow/Photon Unity Networking/Highlight Photon Server Settingsから選択してください)を開くことができます。デバッグレベルは、以下のとおりFullに設定する必要があります:
 
    その後、「Play」を押すことができます。
Unityのコンソールには数十件のログが表示されるはずです。
「Connected to masterserver.」を探してください。これは確実に接続されていて、ルームに参加する準備などが整っていることを示します。
コーディングを行う際の良い習慣は、潜在的な故障を常にテストすることです。
ここではコンピュータがインターネットに接続されていると仮定しますが、コンピュータがインターネットに接続されていない場合はどうなるのでしょう?
確認してみましょう。お使いのコンピュータのインターネットをオフにしてシーンをプレイします。
Unityコンソールに次のエラーが表示されるはずです:「Connect() to 'ns.exitgames.com' failed: System.Net.Sockets.SocketException: No such host is known」
スクリプトがこの問題を認識してスムーズに反応し、どのような問題や状況にも対応できるのが理想です。
それではこれらの両方のケースを処理し、実際にPUNサーバに接続されたかどうかがLauncherスクリプト内で通知されるようにしましょう。
これはPUNコールバックの導入として最適です。
PUNコールバック
PUNでのコールバックは非常に柔軟性が高く、3つの異なる実装が提供されます。
学習用に3つのアプローチをすべて説明します。状況に応じて最適なものを選んでください。
「魔法のような」メソッド
通常のMonoBehaviourを使用する場合、簡単にプライベートメソッドを作成することができます。
C#
void OnConnectedToMaster()
{
    Debug.Log("DemoAnimator/Launcher: OnConnectedToMaster() was called by PUN");           
}
どの MonoBehaviour も、そのメソッドまたはPUNからの他のメッセージを実装することができます。
これは、Awake()またはStart()などの、UnityがMonoBehavioursに送信しているメインのメソッドと同じ原理に従っています。
ただし、この「魔法のような」メソッドの入力を誤るとエラーの通知がされません。これは非常に速く実用的な実装ですが、取得した各メソッドの名前を正確に知っていて、このような問題を検知するデバッグの技術を熟知していない限りは使用するべきではありません。
IPunCallbacksおよびIPunObservableインターフェースの使用
PUNは、クラスで実装することができる2つのC#のインターフェースである、IPunObservableと IPunCallbacksを提供します。
 
    これは、クラスがすべてのインターフェースにコンパイルしていることを確認しながら、開発者がすべてのインターフェース宣言を実装することを強制する非常に安全な方法です。
上記のMonoDevelopの場合のように、ほとんどのIDEで簡単にこの作業を行うことができます。
ただし、何もおこなわないにも関わらずUnityコンパイラのために実装しなければならないメソッドでスクリプトがいっぱいになる可能性があります。
これはスクリプトがすべて、またはほとんどのPUN機能を頻繁に使用する場合です。
今後のチュートリアルでは、データシリアル化にIPunObservableを使用します。
Photon.PunBehaviourを使用
最後に説明する技術は、私たちが頻繁に使う最も便利なものです。
MonoBehaviourから派生するクラスを作成する代わりに、Photon.PunBehaviourからクラスを派生します。特定のプロパティや仮想メソッドを使用してオーバーライドすることができます。
タイプミスがないことを確認することができ、すべてのメソッドを実装する必要がないので非常に実用的です。
 
    注: オーバーライドする際、ほとんどのスクリプトエディタはデフォルトでベースコールを実装し自動的にそれを埋めますが、今回のケースではその必要がありません。このため、基本的にはPhoton.PunBehaviourにベースメソッドを呼び出さないでください。
注:オーバーライドのもう一つの大きな利点は、メソッド名の上にマウスをホバリングすればコンテキストヘルプを利用できることです。
それでは、これをOnConnectedToMaster()とOnDisconnectedFromPhoton()のPUNコールバックで実際に実行してみましょう。
- C#スクリプト - Launcherを編集します
- ベースクラスをMonoBehaviourからPhoton.PunBehaviourへ変更します。 - C# - public class Launcher : Photon.PunBehaviour {
- 分かりやすくするために、 - Photon.PunBehaviour CallBacksリージョン内でクラスの最後に以下の2つのメソッドを追加します。- C# - #region Photon.PunBehaviour CallBacks public override void OnConnectedToMaster() { Debug.Log("DemoAnimator/Launcher: OnConnectedToMaster() was called by PUN"); } public override void OnDisconnectedFromPhoton() { Debug.LogWarning("DemoAnimator/Launcher: OnDisconnectedFromPhoton() was called by PUN"); } #endregion
- Launcherスクリプトを保存します。
これでインターネット有りまたは無しでこのシーンをプレイする際に、プレイヤーに通知したりロジックを進行するための適切な措置をとることができます。
これは、次のセクションでUIの構築を開始する際に説明します。
ここでは接続の成功について説明します:
OnConnectedToMaster()メソッドに以下の呼び出しを追加します。
C#
// #Critical: The first we try to do is to join a potential existing room. If there is, good, else, we'll be called back with OnPhotonRandomJoinFailed()  
PhotonNetwork.JoinRandomRoom();
コメントに記載されている通り、ルームへのランダムな参加が失敗した場合はその通知を受信する必要があります。その場合は実際にルームを作成しなければならないため、スクリプトでOnPhotonRandomJoinFailed()PUNコールバックを実装し、PhotonNetwork.CreateRoom()を使用してルームを作成する必要があります。また、ルームに参加したことをスクリプトに通知する、関連するOnJoinedRoom() PUNコールバックも必要です。
C#
public override void OnPhotonRandomJoinFailed (object[] codeAndMsg)
{
    Debug.Log("DemoAnimator/Launcher:OnPhotonRandomJoinFailed() was called by PUN. No random room available, so we create one.\nCalling: PhotonNetwork.CreateRoom(null, new RoomOptions() {maxPlayers = 4}, null);");
    // #Critical: we failed to join a random room, maybe none exists or they are all full. No worries, we create a new room.
    PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = 4 }, null);
}
public override void OnJoinedRoom()
{
    Debug.Log("DemoAnimator/Launcher: OnJoinedRoom() called by PUN. Now this client is in a room.");
}       
これでシーンを実行すると、PUNに接続するためのロジックに従うはずです。既存のルームへの参加を試みるか、新しくルームを作成してそれに参加します。
以上で、ルームへの接続および参加に関する重要な側面を説明しました。次に、対処が必要となる不便な点がいくつかあります。
これらはPUNの習得にはあまり関係ありませんが、全体的な観点からは重要です。
Unityインスペクターで変数を公開
MonoBehavioursは自動的にパブリックプロパティをUnityインスペクターに公開します。
これはUnity内の非常に重要な概念です。 今回のケースではLogLevelを定義する方法を変更し、コード自体に触れることなく設定できるよう、パブリック変数を作成します。
C#
/// <summary>
/// The PUN loglevel.
/// </summary>
public PhotonLogLevel Loglevel = PhotonLogLevel.Informational;
Awake()で以下のように変更します:
C#
// #NotImportant
// Force LogLevel
PhotonNetwork.logLevel = Loglevel;
これでスクリプトを特定のタイプのLogLevelになるよう強制的に設定する必要はなくなり、単純にUnityインスペクターで設定して実行することになります。スクリプトを開いて編集や保存をしたり、Unityが再コンパイルして最終実行するのを待つ必要はありません。
これによって、生産性や柔軟性が高まりました。
ルームごとのプレイヤー数の上限にも同じことを行います。
コード内でこれをハードコーディングするのはベストプラクティスではありません。代わりに、後から決めて再コンパイルをせずに数字を試せるよう、パブリック変数にしましょう。
クラス宣言の冒頭で、Public Variablesリージョンに以下を追加します:
C#
/// <summary>
/// The maximum number of players per room. When a room is full, it can't be joined by new players and so new room will be created.
/// </summary>   
[Tooltip("The maximum number of players per room. When a room is full, it can't be joined by new players and so new room will be created")]
public byte MaxPlayersPerRoom = 4;
次にPhotonNetwork.CreateRoom() コールを修正し、以前使用していたハードコーディングの番号の代わりにこの新しいパブリック変数を使用します。
C#
// #Critical: we failed to join a random room, maybe none exists or they are all full. No worries, we create a new room.
PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = MaxPlayersPerRoom }, null);
