Realtimeイントロ

はじめに

Photon Realtimeは世界中のリージョンで稼動しているPhotonオンプレミスサーバー向けの完全に管理されたサービス(SaaS)です。低レイテンシーで複数のプレイヤーがいつでも世界中からプレイすることが可能です。

ロードバランシングAPIを使用すると、共有のゲームセッション(「ルーム」と呼ばれます)で複数のプレイヤーをマッチングさせたり、別のプラットフォーム上のプレイヤー間でメッセージの転送を同期的にリアルタイムで行うことができます。 すべてのクライアントSDKは互いに通信が可能です。たとえば、 iOS、Android、ウェブ、コンソール、スタンドアロンのいずれを使用していても通信が可能です。

接続

Photon Realtimeアプリケーションは接続にAppIDが必要です。

無料サインアップをして、RealtimeダッシュボードからAppIDを取得してください。

AppIDを設定して、接続先のリージョンを選択してください。 利用可能なリージョンについては、こちらをクリックしてください

Serviceの呼び出し

LoadBalancing APIはゲームロジックと最適に統合するよう構築されています。

受信メッセージの処理のタイミングや、送信頻度を任意で設定できます。 内部的には、ゲームがLoadBalancingClient.Service()を呼ぶまで、送受信ともにバッファされます。

多くの場合、ゲームはアップデートを計算して画面をリフレッシュするゲームループを使用しています。 1秒ごとにService()を10~20回呼んでください。

Service()を呼ばないかぎり、"ネットワークプログレス"はまったく処理されません。

切断

アプリケーションが終了する際や、ユーザーがログアウトする際には、忘れずに切断するようにしてください。

マッチメイキング

ゲームの作成

新しいルームやゲームを作成するには、接続されたロードバランシングクライアントで"ルームの作成"操作をおこなってください

    void MyCreateRoom(string roomName, byte maxPlayers)
    {
        this.OpCreateRoom(roomName, new RoomOptions() { MaxPlayers = maxPlayers }, TypedLobby.Default);
    }
    void createRoom(const ExitGames::Common::JString& roomName, nByte maxPlayers)
    {
        mLoadBalancingClient.opCreateRoom(roomName, ExitGames::LoadBalancing::RoomOptions().setMaxPlayers(maxPlayers));
    }

これによって、ルームの名前とルームで許可されるプレイヤーの人数が設定されます。 クライアントは、自動的に新しいルームに入室します。 "ルームの作成"操作をすると、まだそのルームが存在していない場合には、参加者がいなくてもルームが作成されます。 最後のプレイヤーが退室するまで、ルームは存在します。

ルーム作成時に、"カスタムルームプロパティ"を定義して共通の値を設定することができます。 カスタムルームプロパティを使用すると、マップ名、レベル、ラウンドの時間などを保存できます。 カスタムプロパティのキーは文字列でなければなりません。 もちろん、これらの値はルーム内での設定や変更も可能です。 任意の配列を"ロビー用のカスタムルームプロパティ"として設定し、その配列にそれらのカスタムプロパティの名前をつけて設定することで、カスタムプロパティをロビーに表示するよう選択できます。 ロビーに表示するプロパティは、マッチメイキングやランダムマッチのフィルタとして使用することが可能です。

マッチメイキングの詳細については、こちらを参照してください 。

ゲームの検索

クライアントは名前を指定するか、またはPhotonにマッチングのリクエストをしてゲームに参加します。

ルームの検索方法

  • Random: ランダムにプレイヤーをマッチングします。ルームを満員にするか、またはプレイヤーを均等に配分するかを選択できます。
  • Filters ランダムマッチメイキングで、より最適なマッチングをおこなうために使用します。
  • Listing: 選択可能なルームをロビーに表示し、プレイヤーが手動で選択したり、参加できるようにします。
  • Private: 名前を把握している、非表示のルームに参加します。
  • Parameterized: 期待されるプロパティを定義して、ランダムマッチングをカスタマイズします。

    // join random rooms easily, filtering for specific room properties, if needed
    Hashtable expectedCustomRoomProperties = new Hashtable();

    // custom props can have any name but the key must be string
    expectedCustomRoomProperties["map"] = 1;

    // joining a random room with the map we selected before
    this.OpJoinRandomRoom(expectedCustomRoomProperties, (byte)expectedMaxPlayers);
    // join random rooms easily, filtering for specific room properties, if needed
    ExitGames::Common::Hashtable expectedCustomRoomProperties;

    // custom props can have any name but the key must be string
    expectedCustomRoomProperties.put(L"map", 1);

    // joining a random room with the map we selected before
    mLoadBalancingClient.opJoinRandomRoom(expectedCustomRoomProperties);

ゲームの持続

Photon Realtimeでは、ルームのデータを簡単に保管およびローディングできます。外部のWebサーバーとPhoton Cloudを接続するには、 Webhooks をセットアップする必要があります。

セットアップが完了すると、ルームステートは自動的に保存されるようになります。ルームに再参加するには:

    this.OpReJoinRoom(savedRoomName);
    mLoadBalancingClient.opJoinRoom(savedRoomName, true);

この機能によって、非同期マッチメイキングとゲームプレイが可能になります。

詳細な手順は、ルーム持続性ガイドを参照してください。

ゲームプレイ

イベントの送信

1つのクライアント上で起こることは、すべて同じルームにいる全員を更新するイベントとして送信することができます。

統計、位置または現在のターンでプレイヤーを更新します。 Photonはその更新を、出来る限り速く送信します(信頼性は任意で設定可能です)。

  • Send messages/events: 他のプレイヤーにすべてのタイプのデータを送信
  • Player/Room properties: Photonは、後から参加したプレイヤーも含めて、これらのデータを更新および同期します。

    byte eventCode = 1; // make up event codes at will
    Hashtable evData = new Hashtable();    // put your data into a key-value hashtable
    bool sendReliable = false; // send something reliable if it has to arrive everywhere
    this.OpRaiseEvent(eventCode, evData, sendReliable, RaiseEventOptions.Default);
    nByte eventCode = 1; // use distinct event codes to distinguish between different types of events (for example 'move', 'shoot', etc.)
    ExitGames::Common::Hashtable evData; // organize your payload data in any way you like as long as it is supported by Photons serialization
    bool sendReliable = false; // send something reliable if it has to arrive everywhere
    mLoadBalancingClient.opRaiseEvent(sendReliable, evData, eventCode);

イベントコードは200以下にしてください。また、各コードでイベントの型と内容を定義する必要があります。

上記例のイベントデータはHashtableです。byte[]や、Photonのシリアル化(stringfloat[]など)で対応しているすべてのデータ型を使用できます。 詳細情報はPhotonでシリアル化を参照してください。

イベントの受信

イベントが送信されると、ハンドラーが呼ばれます。以下に例を示します。

    public override void OnEvent(EventData photonEvent)
    {
        // important to call, to keep state up to date
        base.OnEvent(photonEvent);
        // we have defined two event codes, let's determine what to do
        switch (photonEvent.Code)
        {
            case 1:
                // do something
                break;
            case 2:
                // do something else
                break;
        }
    }
    void NetworkLogic::customEventAction(int playerNr, nByte eventCode, const ExitGames::Common::Object& eventContent)
    {
        // logging the string representation of the eventContent can be really useful for debugging, but use with care: for big events this might get expensive
        EGLOG(ExitGames::Common::DebugLevel::ALL, L"an event of type %d from player Nr %d with the following content has just arrived: %ls", eventCode, playerNr, eventContent.toString(true).cstr());

        switch(eventCode)
        {
        case 1:
            {
                // you can access the content as a copy (might be a bit expensive for really big data constructs)
                ExitGames::Common::Hashtable content = ExitGames::Common::ValueObject<ExitGames::Common::Hashtable>(eventContent).getDataCopy();
                // or you access it by address (it will become invalid as soon as this function returns, so (any part of the) data that you need to continue having access to later on needs to be copied)
                ExitGames::Common::Hashtable* pContent = ExitGames::Common::ValueObject<ExitGames::Common::Hashtable>(eventContent).getDataAddress();
            }
            break;
        case 2:
            {
                // of course the payload does not need to be a Hashtable - how about just sending around for example a plain 64bit integer?
                long long content = ExitGames::Common::ValueObject<long long>(eventContent).getDataCopy();
            }
            break;
        case 3:
            {
                // or an array of floats?
                float* pContent = ExitGames::Common::ValueObject<float*>(eventContent).getDataCopy();
                float** ppContent = ExitGames::Common::ValueObject<float*>(eventContent).getDataAddress();
                short contentElementCount = *ExitGames::Common::ValueObject<float*>(eventContent).getSizes();
                // when calling getDataCopy() on Objects that hold an array as payload, then you must deallocate the copy of the array yourself using deallocateArray()!
                ExitGames::Common::MemoryManagement::deallocateArray(pContent);
            }
            break;
        default:
            {
                // have a look at demo_typeSupport inside the C++ client SDKs for example code on how to send and receive more fancy data types
            }
            break;
        }
    }

各イベントは、クライアントが送信したのと同様の方法でコードとデータを送信します。 アプリケーションは、渡されたコードによってどのコンテンツを期待すべきかを把握します(上記参照)。

デフォルトのイベントコードの最新のリストは、SDK内のイベントコード定数を確認してください。たとえば、C#の場合はExitGames.Client.Photon.LoadBalancing.EventCode内にあります。

カスタムサーバーまたはオーソリテーティブサーバーのロジック 

オーソリテーティブロジックを加えなくても、Photon Cloud製品は幅広いタイプのゲームに対応しています。

  • ファーストパーソンシューター 
  • レーシングゲーム
  • マインクラフトタイプのゲーム
  • カジュアルなリアルタイムゲーム 
  • 非同期および同期ゲーム
  • ...

独自のカスタムロジックを実装するには、Photon Serverまたは プラグイン を使用してください。

 ドキュメントのトップへ戻る