WebGLのバックグラウンドタブ

ユーザーが複数のブラウザタブを開くと、アクティブな(可視)タブのみが定期的に高頻度で更新されます。 非アクティブ(不可視)のタブは、ほとんどのブラウザで1秒間に1回しか更新されません。 この場合の可視性は、ウィンドウが必ずしもフォアグラウンドにあることを意味するのではなく、別のウィンドウの裏で非フォーカス状態の場合もあります。

これはUnityのWebGLエクスポートにも該当し、送受信メッセージが1秒間に1回しか処理されないため、問題が発生する可能性があります。 つまり、すでに更新頻度が低い状況下でメッセージキューが増え、さらに多くの更新処理が必要となります。 多くのアプリは、タブがバックグラウンドにある間に同期を失って切断されます。

WebGLアプリケーションはJavaScriptを使用しているので、ブラウザからゲームロジックにメッセージを直接送信するために、これらのビルドを拡張することができます。 この場合、ゲームから切断するか、アプリケーションタブがバックグラウンドにある際に低い更新レートの間で追加の更新を強制することが可能です。 これをおこなうには、次のいずれかの方法を実行します。

WebGLビルドを修正

それぞれのアプローチについて説明する前に、アプリケーションタブがバックグラウンドにあるかを判断する方法について説明します。 このためvisibilitychangeイベントにフックして変更をリッスンします。 2つの状態は区別されます:hidden(隠れた)状態と「その他の状態」です。 状態の変化を検出するたびに、ゲームロジックからゲームオブジェクトにメッセージを送信し、機能を実行することができます。 これは、次のJavaScriptコードスニペットを使用しておこなうことができます。

<script>

document.addEventListener('visibilitychange', function () {
    if (document.visibilityState == "hidden") {
        SendMessage("Receiver", "DoSomething");
    } else {
        SendMessage("Receiver", "DoSomethingElse");
    }
});

</script>

上記の場合'Receiver'というゲームオブジェクトにメッセージを送信しています。 このオブジェクトでは、DoSomething(Else)という関数を実行しています。 この関数は、ゲームオブジェクトに添付された任意のスクリプト内に設定することが可能です。

このコードをWebGLアプリケーションに添付するには、ビルドに移動して作成したindex.htmlファイルを開きます。 上記のスニペットをコピーアンドペーストして、そのHTMLファイルの タグの34行目に挿入します。 'SendMessage'関数のパラメータを調整してください。

Back To Top

第1のアプローチ - 接続を閉じる

WebGLアプリケーションタブがバックグラウンドになると、最初のアプローチではクライアントをPhotonから切断します。 アプリケーションがフォアグラウンドに戻ると、Photonに(再)接続しようとします。 これは、上記のシナリオの処理に推奨される方法です。

これをおこなうために、index.htmlファイルの上のコードスニペットを使用し、ゲームロジックから'Disconnect'および'Reconnect'機能にメッセージを送信しています。 これらの関数は、以下の例のようになります。

public void Disconnect()
{
    PhotonNetwork.Disconnect();
}

public void Reconnect()
{
    if (!PhotonNetwork.IsConnected && wasConnected)
    {
        PhotonNetwork.ReconnectAndRejoin();
    }
    else
    {
        PhotonNetwork.ConnectUsingSettings();
    }
}

備考:ブール変数wasConnected は、クライアントが以前ルームに参加した場合にはtrueに設定されます。 この情報があれば、ロビーに最初に参加せずに、ルームに直接再接続して再入室を試みることができます。

ReconnectAndRejoinを正しく使用するにはルームとそのオプションを正しく設定する必要があります。 これは `PlayerTtl`(サーバーから切断されるまでにプレイヤーが非アクティブになるまでの時間をミリ秒で表します)を0以上の値に設定する必要があることを意味します。 空のルームを維持したい場合は、`EmptyRoomTtl`(空のルームが切断されるまで、サーバーのメモリに保持される時間(ミリ秒単位))を0以上の値に設定します。 このアプローチを使用して`ReconnectAndRejoin`をテストする場合、両方の値を30,000(30秒)または60,000(60秒)に設定するよう推奨します。

Back To Top

第2のアプローチ - インタレストグループを使用して接続を維持

第2のアプローチでは、ゲームロジック、特にネットワーキングロジックへの追加作業が必要です。 このアプローチを使用して、ゲームに関連するメッセージを送受信せずに接続を維持するよう試みます。 これは、インタレストグループを使用して特定のグループに迅速に登録または登録解除することで達成できます。

PUNで使用されるデフォルトのグループは0です。このグループからは登録解除できないため、問題解決に使用することはできません。

上記のように、このアプローチを使用する場合には別のインタレストグループを使用する必要があります。 以下の例では、グループ1に自由に登録/登録解除できるためグループ1を使用しています。

Photonに接続する際には、希望するグループへの送受信を有効にしてください。 以下を呼び出して設定できます。

PhotonNetwork.SetInterestGroups(1, true);
PhotonNetwork.SetSendingEnabled(1, true);

また、インスタンス化されたゲームオブジェクト(PhotonViewコンポーネントが添付されているもの)が、グループ変数を対象のグループに設定していることを確認してください。 たとえば、以下を使用できます。

public void Awake()
{
    GetComponent<PhotonView>().Group = 1;
}

ほとんどのネットワークトラフィックを特定のグループに'移動'させたら、ブラウザのJavaScriptから呼び出されるこれら2つの機能を引き続き追加できます。 この例では、'Subscribe'および'Unsubscribe'と名づけます。たとえば、以下のようになります。

public void Subscribe()
{
    GetComponent<PhotonView>().Group = 1;

    PhotonNetwork.SetInterestGroups(1, true);
    PhotonNetwork.SetSendingEnabled(1, true);
}

public void Unsubscribe()
{
    GetComponent<PhotonView>().Group = 2;
    PhotonNetwork.SetInterestGroups(1, false);
    PhotonNetwork.SetSendingEnabled(1, false);
}

最後に、上記2つの関数を呼び出せるように「index.html」ファイルに追加するJavaScriptスニペットを調整します。

この方法は多くの作業を必要とし、多くの問題を引き起こす可能性があるため問題解決の方法として推奨されません。

Back To Top

第3のアプローチ - 強制的に更新をおこなって接続を維持

このアプローチは、すべての着信および発信メッセージを強制的に処理するため、さきに述べた2つのアプローチとは異なります。 したがって、まず基本的なJavaScriptスニペットを以下のように調整する必要があります。

<script>

var isActive;

document.addEventListener('visibilitychange', function () {
if (document.visibilityState == "hidden") {
    isActive = setInterval(function() { SendMessage("Receiver", "DoSomething"); }, 250);
} else {
    clearInterval(isActive);
    isActive = false;
}
});

</script>

これは、現在の可視状態にもとづいてタイマーを作成および破棄します。 このタイマーがアクティブになると250ミリ秒ごと、または1秒間に4回該当する関数を呼び出します。 この間隔は、SendMessage関数のパラメータと同様に必要に応じて調整することができます。

これを更新すればWebGLプロジェクトの調整も続行できます。 このため、さきほど設定したタイマーから呼び出される関数DoSomethingを作成します。 この関数は、たとえば次のようになります。

public void DoSomething()
{
    if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom)
    {
        return;
    }

    PhotonNetwork.NetworkingClient.LoadBalancingPeer.DispatchIncomingCommands();
    PhotonNetwork.NetworkingClient.LoadBalancingPeer.SendOutgoingCommands();
}

これにより、ブラウザのタブがバックグラウンドにあってもネットワークのメッセージフローが増加します。 このアプローチは良い方法のように思われますが、大きな欠点もあります。 ゲームが実際に表示されていないときにキャラクターをコントロールすることができないので、キャラクターのトランスフォームに関連する変更ができません。 したがって、常に同じ情報を他のクライアントに送信することになり、重要なコンテンツがないメッセージ数が増えます。 このため、このアプローチは推奨されません。

Back To Top

第4のアプローチ - 第3のアプローチを調整して接続を維持

第3のアプローチは推奨されていませんが、最後のアプローチとして使用できます。 'DoSomething'関数を以下のように変更します。

public void DoSomething()
{
    PhotonNetwork.NetworkingClient.LoadBalancingPeer.SendAcksOnly();
}

これは、接続を維持するためにサーバーに確認応答を送信するだけです。 追加作成されたこの間隔では、ゲームロジックに関連するメッセージは処理されません。

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