こんにちは。サーバーサイドエンジニアの佐藤です。
今回は対戦や協力などで用いられるマッチングにおける工夫を共有します。
プレイヤー同士が対戦や協力などを目的に一緒にプレイするゲームでは、同一のゲームにプレイヤー同士を引き合わせるマッチングが行われます。
マッチング時には、力量が近いなどといった何らかの基準を満たすようにプレイヤーを引き合わせることがあります。この際、マッチング候補であるプレイヤーが多ければ多いほど基準を満たすプレイヤーがいる可能性が高く、より良いマッチングができます。
そのため、コンテンツの種類を絞りプレイヤーを集められるようにするのが一般的です。特にこれは対戦や協力などのマルチプレイを主体とするゲームタイトルにおいては重要です。
一方で、プレイヤーが複数のコンテンツに分散してしまう特徴を持つタイトルにおいては、マッチングの候補となるプレイヤーが少なく、適切にマッチングさせることが困難になります。
シングルモードが主体でマルチプレイ要素も持ち合わせるゲームはこの特徴を持ちがちであり、悩みの種となります。
本記事では、プレイヤーが分散するタイトルにおいて、マッチングの質を高めることに成功したため、その工夫と問題の解決について紹介いたします。
なお、対象となるタイトルではOpenMatchなどのマッチメイキングフレームワークを利用しておらず、データベースを利用しマッチングを行っています。
背景
対象のタイトルではホストとゲストが存在するロビー制のシステムを採用しています。
ホストとは、一緒にゲームをプレイするプレイヤーが集まる場所であるロビーを作成し、ゲームの開始などを管理するプレイヤーです。また、ゲストとは既存のロビーへの参加を行うプレイヤーです。
ゲストがロビーに参加する方法はゲームによって様々です。対象タイトルでは既存のロビーへ無作為に参加するランダムマッチングを主体としています。
無作為と言いましたが、必ずしも完全ランダムにマッチングさせるわけではありません。快適にプレイするため、より通信が安定する物理的距離が近いプレイヤー同士*1や実力が近いプレイヤー同士がマッチングしやすくする仕組みを導入することもあります。*2
この仕組みはプレイヤーが多いほど、より相応しいプレイヤーがいる確率が高いため有効に機能します。
プレイヤーを多く集めることができるゲームでは、一定の相応しさの基準を満たしたプレイヤー同士だけでマッチングさせ、基準を満たさないプレイヤーをマッチングさせないようにすることが可能です。
これは母数が多く、どのプレイヤーに対しても基準を満たすプレイヤーが常に存在するからこそできる戦略です。母数が少ない場合には誰ともマッチングしないプレイヤーが発生してしまいます。
対象タイトルはコンテンツが多く、プレイヤーが分散し集めにくい特性を持っています。
完全にマッチングしないプレイヤーの発生を防ぐため、基準の近いプレイヤーとマッチングしやすいが、遠いプレイヤーともマッチングする可能性のある重み付きランダムを用いてマッチングしています。
下の図は最大4人まで同時に遊ぶことができるロビーが3つ、ホストが3人いる状態*3における1人のゲストの流入と重み付きランダムによるマッチングを表したものになります。
重み付きランダムでは、ゲストのロビー(もしくはホスト)へのマッチングの相応しさを算出し、その値を重みとする乱数でロビーへの割り当てを行います。これにより、相応しくないロビーに対しても少ない確率で割り当てが行われ、マッチングしないプレイヤーの発生を防ぎます。
各種改善手法
このロビー制を持つタイトルにおいて行った改善を紹介します。
一連の改善のベースとなるゲストのホスト化、その発展であるロビープール機能、ロビープール機能の設定値の自動化の順で説明していきます。
ゲストのホスト化
対象タイトルではランダムマッチを行うゲストに比べ、ホストはロビーを作成するなど少々手間がかかるようになっておりました。
プレイヤーの多くが手間を避けるためゲストとなることで、ホストに対してゲストが多すぎるという不均衡が発生していました。
不均衡が発生すると、ランダムマッチング時にロビーが存在しないためいつまで経っても入室できず、ゲームを開始できない状態に陥ってしまいます。
また、リリースから長時間経過したコンテンツや深夜帯では、そもそも遊ぶプレイヤーが少なく、ロビーが存在しない状態が発生しやすくなります。
本来一緒に遊びたいプレイヤーが複数いてもロビーが無いために遊ぶことができないのはもったいない状況です。
この状況を改善するため、ランダムマッチング時にロビーが存在しない場合には、すぐにゲームを開始できる状態まで予め設定されたロビーを作成し、ホストとして入室するようにしました。
この仕組みを導入することで、ゲストが手間を大幅に省いた状態でホストになることができ、他のゲストも作成されたロビーに入室することができます。
これで、ロビーが無いためマッチングできず、遊ぶ機会が失われる問題が改善されました。
ロビープール機能
ゲストのホスト化を発展させ、2つの問題の解消に取り組みました。
1つ目はコンテンツのリリースなどの極端にプレイヤーが増えるタイミングで、同一のロビーに沢山のゲストが入室しようとして人数制限によりエラーになる問題です。
これは入室可能ロビー群を参照用データベース、実際に入室するロビーを更新用データベースと別々に取得することに由来します。
2つ目はマッチング候補となるロビーの数が少なすぎて適切なマッチングが行われなくなる問題です。
これらの問題の解消のために、マッチング時に最低限のロビーが存在することを保証することを考えました。
具体的には、ゲストがホスト化する際の条件を「ロビーが存在しないとき」から「ロビー数が閾値未満のとき」に変更しています。
上の図は閾値が3、ロビー数2のときにゲストが新たに生成されたロビーにホストとして入室する様子を示したものです。
これにより、ランダムマッチングでゲストが既存のロビーに割り当てられる際には常に閾値の数以上のロビーが存在することになります。
ゲストの割り振りが常に複数のロビーに分散されることで直前で満員になったロビーに入室しようとする機会が減ります。
また、候補数を担保することによりマッチングの質を上げることができます。
ロビーを人工的に滞留させることからこの機能をロビープール、そして閾値をプール数と呼んでいます。
プール数設定自動化
前述のプール数は時間帯やモードリリースからの経過時間によるプレイヤー数の増減を考慮し、決め打ちで設定しておりました。
定期的に設定の見直しを行っていましたが、とても手間ですし、値の妥当性に乏しい状況です。
どうにか現在のプレイヤーの流入状況に合わせて自動的に設定できないものかと考えた際に、「プレイヤー数が同じ条件下においては、マッチングにかかる時間と質がトレードオフになる」ということに気が付きました。
よくよく考えてみると非常に当たり前なことでしたが、この気付きから、ロビーが満員になるまでにかかる時間を指定することで対応するプール数を計算可能なのではないかという疑問を抱きました。
とは言うものの、いきなり現状のマッチングに対応するプール数を算出する方法を考案することは困難だったため、マッチングを簡易的なモデルに置き換えた上でのプール数を考え、より現状に近づけていくアプローチを取ることにしました。
1. マッチングの簡易モデル化
ここでは、プール数を算出するためにマッチングにセレクタという概念を持ち込み、簡易化したモデルで考えます。この簡易化されたモデルにおいてはロビー数は固定で増えないものとします。
①ゲストはランダムマッチを経てロビーに参加する際にはセレクタへ到達します。
②セレクタはロビーに対してゲストを順番に振り分けます。
③ゲストはロビーに入室します。
次にやってくるゲストに対しても同様に処理します。
これを次々とやってくるゲストに対して続けていくと、最終的には全てのロビーが満員になります。
この場合、ゲストがロビーに1人もいない状態から全てのロビーが満員になるまでの時間は以下の式で表すことができます。
満員になるまでの時間=ロビー数 × 1ロビーあたりのゲストキャパシティ ÷ セレクタへの流入量
上の図においては1つのロビーに3人のゲストが参加可能になりますので、1ロビーあたりのゲストキャパシティは3になります。
2. モデルの厳密化
現状のモデルは最初からロビーが存在する体になっており、ランダムマッチにおける重み付きランダムなどの様々な機能を無視しています。
より厳密にするため、ここではホストがロビーを新たに立てるケースをモデルに組み込んでいきます。
ランダムマッチでゲストとして参加した5人のプレイヤーがセレクタに移っている状況について考えます。この状況で1人のホストがロビーを作成するとします。
この際にセレクタへ流入する前にゲストがロビーに奪われると考えます。
この図においては3人のゲストがセレクタへの流入以前に新規ロビーに奪われてしまいました。
このように考えるとセレクタへのゲスト流入量は以下の式で表せます。
セレクタへのゲスト流入量 = ゲスト流入量 - 1ロビーあたりのゲストキャパ × ホスト流入量
「1ロビーあたりのゲストキャパ×ホスト流入量」が新規ロビーによるゲストの損失です。
この式と1における式の2つ式についてロビー数について解くと以下の式が導出できます。
ロビー数 = 満員になる時間 × (ゲスト流入量 - 1ロビーあたりのゲストキャパ × ホスト流入量) ÷ 1ロビーあたりのゲストキャパ
1ロビーあたりのゲストキャパは図においては3となっていますが、本タイトルではコンテンツごとの設定となっています。
この式における「ロビー数」を「プール数」、「満員になる時間」を「1つのロビーが満員になる時間」と当てはめ、実際のゲームに適用していきます。*4
モデルの導入
前述の式の「ゲスト流入量」と「ホスト流入量」は実際のマッチング環境からできるだけ現状を反映したデータとして取得する必要があります。
ですので、ホストとしてロビーを作成するタイミングとゲストとしてランダムマッチを行おうとするタイミング*5でデータベースに保存しています。
これでプール数の計算に必要な値は全て取得できるようになりました。
1分ごとに直近1分の流入量を取得し、プール数の計算を行います。
ここでちょっとした工夫ですが、実際にゲストのホスト化を行う際には先程の式で計算したプール数をそのまま用いるのではなく、以下の式のように前回計算したプール数と合成した値を利用します。
今回のプール数 = α * 計算したプール数 + (1 - α) * 前回のプール数 (0 < α ≦ 1)
この合成により、たまたま1分間だけ大幅にズレた値を取ったとしてもプール数の急激な変化を抑えることができます。
しかし、αを小さすぎる値にすると、コンテンツリリースなどの急激なプール数の変化に対する追従が遅れるため注意が必要です。
結果
実際のあるコンテンツのリリースからの1時間の合成前後のプール数の変化は以下のようになっています(α=0.5としてます)。
コンテンツリリース後からプール数が増え、おおよそ9付近で維持されているのがわかります。
また、合成によりプール数が特定時刻だけ谷や山となるような状況が緩和されています。
これで今まで手探りだったプール数がプレイヤーの流入状況に応じて自動的に設定されるようになりました。
また、実際にロビーが満員になるまでの時間を比較しました。以下が2つのコンテンツにおけるリリース日のロビーが満員になるまでの時間の設定値と実測値の平均です。設定値は一方のコンテンツでは4秒、もう一方では8秒に設定しています。
設定値(秒) | 平均値(秒) |
---|---|
4.0 | 4.6372 |
8.0 | 7.1846 |
モデルに取り込めていないマッチングの要素があるにもかかわらず、満員になるまでの時間が指定値に近くなっています。
マッチング時間を指定することでプール数を自動で調整できるようになりました。マッチングの質を求める場合には時間を長く、質よりも早くプレイできることを優先したい場合には時間を短く指定することでコントロールが可能です。
まとめ
「遊びたいプレイヤーがいるにもかかわらずロビーが存在せず遊べない」、「ロビー数が少ない場合にプレイヤーが集中してしまいロビーに入れない」、「ロビー数が少ない場合にマッチングの質が悪化する」という問題を解決することができました。
また、マッチングまでの時間を指定することでプール数を動的に変化させ、マッチングまでの時間をコントロールすることに成功しました。実際にマッチングが重要なコンテンツでは長めの時間を設定しマッチングの質を向上させています。
今回計算式を導出する上で使ったモデルは実際のマッチングを簡易化したものです。マッチング時間をより正確にコントロールするには、モデルをより実際のマッチングに近づけることが必要です。
プール数の小数点部はゲストのホスト化の可否を決める上で有効には機能していません。特にプール数が低くなっている場合は小数点部の影響が大きくマッチング時間がコントロールしにくくなる課題があります。
このように、コロプラのサーバーサイドエンジニアはより快適にプレイできるような改善に取り組んでおります。
以上が今回のブログの内容となります。最後までご確認いただきありがとうございました。