クイックスタート

本記事では、アプリケーションにマルチプレイヤー機能を実装する際の典型的な事例を示しています。

このデモは当社のPhoton Unity SDKにのみ含まれていますが、(1) 接続 、 (2) ルーム作成 and (3) イベントの送信など大枠のワークフローはC#アプリケーションや他言語でも共通しています。

Unityエンジンで開発する場合は、ゲームステートとシミュレーションの同期を助けるFusionや、Unityとの統合がより深いQuantumを使うことを検討してください

マスターサーバーへの接続

まずはじめに、クライアントをPhoton Cloudに接続します。つまり、クライアントをマスターサーバーに接続します。
この接続以降、マスターサーバーはすべてのクライアントのゲームサーバーへの移動、Cloud内や利用可能なルームでのロードバランシングを実施します。

デモのコードで詳細をみていきましょう:

C#

// from "Assets\Photon\DemoCode\GameLogic.cs"
public GameLogic(string appId, string gameVersion)
{
    // this.MasterServerAddress = "your server"; // no need to set any address when using the Photon Cloud.
    this.AppId = appId;
    this.AppVersion = gameVersion;

    this.LocalPlayer.NickName = "usr" + SupportClass.ThreadSafeRandom.Next() % 99;

    this.StateChanged += this.OnStateChanged;
    this.UseInterestGroups = true;
    this.JoinRandomGame = true;

    this.DispatchInterval = new TimeKeeper(10);
    this.SendInterval = new TimeKeeper(100);
    this.MoveInterval = new TimeKeeper(500);
    this.UpdateOthersInterval = new TimeKeeper(this.MoveInterval.Interval);
}                

GameLogicクラスはLoadBalancingClientを継承してステートを保持し、マスターサーバーとゲームサーバー間の移行を自動的に実行します。
GameLogicコンストラクターで使用される引数の詳細をみてみましょう。

  1. string appId: Photon Cloudシステム内のアプリケーションを特定します。
    AppIDがまだない場合には、Photon Cloudダッシュボードで確認してください。
    デモを正常に作動させるには、有効なAppIDを入力する必要があります。
  2. string gameVersion: ゲームの個別のビルドを明確に区別したい場合に選択する文字列です。
    同じバージョン番号のクライアントのみがマッチングされ、相互に通信することができます。
    この文字列によって、古いクライアントを中断せずに、非常に簡単に機能追加をおこなえます。
Particle Demo Screenshot (Unity3D SDK)
Particle Demo Screenshot (Unity3D SDK)

接続すると、Photon Cloudはあなたからの命令をいつでも実行できるよう待機します。
今後は、細部を管理する必要はありません。すべて、自動的に処理されます!

リスト化が可能なマスターサーバーに接続されているので、ルームを作成し、入室してください。
この時点では、プレイヤー同士は通信ややりとりができません。
ここで、ルームの概念が機能し始めます。
プレイヤー同士を接続する方法については、以下を参照してください。

ロビー、ルーム作成とルーム入室

デフォルトでは、接続するとLoadBalancing APIによってゲームの「ロビー」に入ります。
ロビーにいる間、マスターサーバーはクライアントにルームのリストを提供します。
トラフィックを低く維持するため、ロビー内ではクライアントは互いにインタラクトできません。

ルームは、プレイヤーがインタラクトする(ゲームをプレイする)別個のエリアと考えることができます。
同じルームにいる間、プレイヤーは他のプレイヤーからイベントを送受信したり、 ルームプロパティの変更/更新などをすることができます。

以下のサンプルでは、**"OpCreateRoom"**操作を使用してルームを作成し、開きます。ルームを作成すると、同時にそのルームに入ります。

C#

    RoomOptions options = new RoomOptions();
    options.MaxPlayers = 4;
    peer.OpCreateRoom("Room 42", options, TypedLobby.Default);

特徴的な引数とRoomOptionsは以下のとおりです:

  • string roomName
    ルーム名で、ルームの識別とルームへの入室に使用されます。
  • bool RoomOptions.IsVisible
    この変数は、ロビーから見えるルームのリストにそのルームが属するかを決定します(すなわち、マスターサーバーに接続しているが、ルームには属していないプレイヤーなど)。
    重要なのは、クライアントが正確なルーム名を把握している場合にはこれらのルームに参加できるという点です。
  • bool RoomOptions.IsOpen
    そのルームにクライアントが入室できるかを決定します。
    クライアントがすでにルームにいる場合は、この変数が変わってもクライアントには影響はありません。しかしisOpenがfalseである限り、退室後ルームに再入室することはできません。
  • byte RoomOptions.MaxPlayers
    ルーム内の最大プレイヤー数を決定します。
    ゼロに設定すると無制限となります。
    1つのルームに多数のプレイヤーを参加させたい場合には、Photon Server MMOアプリケーションを参照してください!
  • Hashtable RoomOptions.CustomRoomProperties
    任意で使用できる、ルームの詳細を定義するキー/値のセットです。
    例:キーの「レベル」は「de_dust」またはその他の値に設定できます。
    プロパティは、ルーム内のすべてのクライアントで同期され、マッチメイキングに使用されます。
    詳細は以下を参照してください。
  • string[] RoomOptions.CustomRoomPropertiesForLobby
    ロビーで表示されるプロパティです。

Photonでは実行時にプレイヤーまたはルームのプロパティを変更することができるので、 RoomOptions.CustomRoomPropertiesで設定されたプロパティに制限されることはありません。
ルームでは、room.SetCustomProperties(props)を使用して新たな値を設定したり、既存の値を上書きします。
変更はマージされるので、変更したいキーのみを渡します。

ルームは多くのプロパティを保持できますが、マッチメイキングに通常必要なプロパティはその一部です。このため、ロビーで利用可能とすべきプロパティキーのリストを定義しなければなりません。

RoomOptions.CustomRoomPropertiesで定義されていないキーでもstring[] CustomRoomPropertiesForLobbyで利用でき、この場合には後で値を設定します。

LoadBalancing Room Properties Example
LoadBalancing Room Properties Example

ルームのプロパティと同様に、プレイヤーごとにCustom Propertiesを設定できます。
ルームに参加する前でも、各クライアントはLoadBalancingClient.LocalPlayer.SetCustomProperties()としてプレイヤープロパティを設定可能です。
これらのプロパティはクライアントに属し、クライアントが参加または作成するすべてのルームと同期されます。

LoadBalancing Player Properties Example
LoadBalancing Player Properties Example

さあ、これで正常にルームが作成できたので、他のクライアントに参加してもらいましょう!ルームへの参加は簡単で、迅速にできるため
これ以上説明は必要ありません。非常に容易な操作で実行できます:

C#

// From LoadBalancingClient.cs                        
public void OnOperationResponse(OperationResponse operationResponse)
{
    ...
    this.OpJoinRoom(name);
}

プレイヤーがお互いにどのようにインタラクトできるようになったか、みてみましょう。

イベントの送信

クライアントが互いにインタラクトするには、単純なイベントシステムを使用しています。
任意のルーム内のプレイヤー間で、信頼性の高い情報を迅速に送受信するにはイベントを使用できます。
ゲームロジックに必要なすべてのデータは、クライアント間でこの方法で送信されます。

必要に応じ、単純なパラメータをともなうプロトコル(TCP対UDP、または信頼性の低いUDP対信頼性の高いUDP)を指定すれば、情報交換の方法をカスタマイズすることができます。

LoadBalancing RaiseEvent Operation Diagram
LoadBalancing RaiseEvent Operation Diagram

イベントはルーム内の参加者で分配されます。

イベントの送信先は特定のプレイヤーリスト、グループまたは全員から選択できます。

Particleデモで使用するイベントのを参考にしてみましょう。たとえば、色の変更です:

C#

public void ChangeLocalPlayercolor()
{
    if (this.LocalPlayer != null)
    {
        this.LocalPlayer.RandomizeColor();
        this.loadBalancingPeer.OpRaiseEvent(DemoConstants.EvColor, this.LocalPlayer.WriteEvColor(), this.SendReliable, new RaiseEventOptions() { CachingOption = EventCaching.AddToRoomCache });
    }
}            

OpRaiseEvent引数には、以下が含まれます:

  • byte eventCode
    このイベントコードは、発生させたい実際のイベントを指定します。
    Photonにはあらかじめ定義された、255から開始して下がっていくイベントがあります。
    1から199までは、ゲームロジックで使用する独自のイベントを定義することができます。
  • Object evData
    この引数には、移動する必要のあるすべてのデータを設定することができます。
    使用する型はPhotonでサポートされている必要があります。
    これは、クライアント間で情報を交換するのに使用する、中央データ構造です。
    ゲームロジックで繰り返し発生し、標準化された手順(たとえばターンの終了など)は、イベントとして送信される必要があります。
  • bool sendReliable
    このフラグをtrueに設定するとUDPから信頼性の高いUDPに切り替えます。
    送信中に失われたパッケージはすべて再送信され、クライアントは送信された順にパッケージが処理されることを確認します。
    この手順によってメッセージが追加され、通信全体にデータ負荷がかかるため、パフォーマンスにネガティブな影響を及ぼす点に留意してください。
  • int[] RaiseEventOptions.TargetActors
    イベントを送信するルーム内のActorNumbersのリスト。
  • EventCaching RaiseEventOptions.CachingOption
    サーバーがキャッシュでイベントを処理する方法に影響します。後から参加するプレイヤーのイベントをキャッシュするか、以前にキャッシュされたイベントを削除することができます。
  • byte RaiseEventOptions.SequenceChannel
    異なるチャネルを使用し、送信するイベントをグループ分けして優先順位を付けることができます。
    以下の簡単な例で、この機能について説明します:
    たとえば、チャネル1を使用してプレイヤーの位置についての関連情報を送信しているとしましょう。
    特に高い信頼性を必要とするゲームであるため、信頼性の高いUDPを有効化しています。
    一部のプレイヤーに遅延が発生し、接続状況が悪化するために膨大なパケットロスが生じたため、ある時点からチャネル1が多数のメッセージで混雑しました。結果的に、多くのメッセージを再送信する必要があります。
    別の重要なイベントをキューに追加したい場合(ラウンドの終わりなど)には、クライアントがまだチャネル1からすべての位置更新を受信中のため、認識に時間がかかる可能性があります。

channelId 0でイベントをディスパッチした場合、そのイベントはキューされた他のメッセージよりも優先されます。
この機能を活用することで、接続状況が悪い場合でも反応を高め、ゲームロジックの正しいフローを確保できます。

Particle Demo (Unity3d SDK): Room View Screenshot
Particle Demo (Unity3d SDK): Room View Screenshot

最後になりましたが、レシーバーグループの指定には、追加の負荷を使用できます。

最後までお読みいただき、ありがとうございました!
この記事についてのご意見やご質問は、フォーラムからご連絡ください。皆様からのフィードバックをお待ちしています!

Back to top