記事一覧へ
08/06/20

当たり判定について

皆さん、こんにちは。VALORANTのゲームシステム開発チームでソフトウェアエンジニアをしているKevin Leeです。ゲームシステム開発チームは移動や戦闘、入力など、VALORANTのゲームプレイの核となる多くのシステムの開発を担当しています。この投稿では、FPSのゲームプレイにおける中心的システムのひとつである、当たり判定について説明します。

VALORANTのように1発のヘッドショットが勝負の明暗を決めるようなゲームでは、当たり判定はとても重要なシステムとなります。私たちの開発者としての目標は、プレイヤーが銃を撃った際にその結果が明白で、違和感がなく、何よりも正確であるようにすることです。

しかし現実には、当たり判定がおかしいと思われる動画を添えたメッセージを受け取ったり、投稿を見かけることもあります。私たちはこれらの報告をすべて深刻に受け止め、各動画を1フレームずつ確認して、システムが想定通りに機能しているかどうかを検証しています。

とはいえ、現在のVALORANTの当たり判定はとても良い状態にあると考えています。もちろんバグが発生するエッジケースもまだ存在しますし、これらを軽視しているわけではありません。私たちは常にシステム全体の品質と明瞭性の向上に努めており、そしてこれからも続けていきます。

正確性 vs 明瞭性

ベータパッチ0.50で、当たり判定に関する問題の報告が急増しました。皆さんからの報告や動画を確認し、開発チーム内部で検証を重ねた結果、エッジケースのバグをいくつか特定することはできました、しかし、それでも報告がこれほどまでに急増したことの理由は説明にはなりませんでした。そこでさらに詳しく調査を行った結果、ほとんどのケースで問題になっていたのは正確性ではなく、明瞭性であったことが分かりました。弾の当たり判定自体は正しく処理されているものの、ヒット時のビジュアルフィードバックがプレイヤーにとって誤解を招くものとなっていたのです。これによって私たちは、正確性と明瞭性を区別して考えることが重要であることを学びました。

「射撃が正しく処理された」という“感覚”を実現するためにはどちらも重要ですが…

  • 正確性の問題は射撃の結果が「間違っている」ことを意味します(例:弾が頭に当たったのに胴に当たったことになっていたり、クライアントとサーバーで敵プレイヤーの表示が異なっている)。
  • 明瞭性の問題は射撃の結果が「確認しづらい」ことを意味します(例:弾は肩に当たっているものの、ビジュアルフィードバックでは頭に当たっているように見える)。
  • 正確性のバグは明瞭性のバグよりも深刻です。

この記事でシステムに対する理解が深まり、プレイヤーの皆さんが自分のゲームプレイを振り返った際に、画面上でなにが起こっているのかを理解できるようになることを願っています。ここでは、まず高次のシステムの仕組みを説明し、その次に射撃ボタンを押してからヘッドショットが表示されるまでに何が起こるのかを説明します。

技術的な内容の詳細についてはVALORANTのネットコードについて説明したRiot Tech Blogの記事(英語)をご覧ください。

また、「おかしな当たり判定」として寄せられる報告によく見られる事例をケーススタディとして取り上げ、実際にはなにが起こっているのか、そしてそれをどのように改善していくのかをお話しします。

クリックからヘッドショットまで

射撃が行われたときに何が起こるのかについて話す前に、ゲーム上でどのように射撃がシミュレートされるかを理解しておくことが重要です。VALORANTのゲームプレイでは2回シミュレートされます。1回はサーバー上(シミュレーションの結果に絶対的な権限を持ちます)で行われ、1回はプレイヤーのクライアント上(ゲームの反応性を高めるために、サーバーの結果を予測します)で行われます。

シミュレーションにはマップを形成しているあらゆるもの(各プレイヤーの位置や空中を行き交うアビリティ、戦場に展開されたスモークなど)が含まれます。ゲームクライアントはフレームごとにシミュレーションのスナップショットを撮影し、それを使ってプレイヤーの画面上にフレームをレンダリングします。サーバーもフレームごとにこれを行います(サーバーは誰も見ていないので、レンダリングの手順は省かれます)。

では、敵がコーナーからピークしてきて、あなたが素晴らしいエイムで敵の頭に照準を合わせてマウスを左クリックしたとき──いったい何が起こるのでしょうか?

hit_reg_flow.jpg

キーを押した瞬間に、その入力がゲームの入力システムに送られ、フレームごとに入力が処理されます(これはハードウェア/オペレーティングシステムのわずかな遅延の影響を受けます)。入力が処理されると、処理が行われたフレームを示すタイムスタンプとともに、「射撃した」という情報がサーバーに送られます。

なお、このタイムスタンプに記される時刻は、入力が行われた時点であなたの画面にレンダリングされていたものを基準に決定されます。この後はクライアント上とサーバー上、2つの異なるシミュレーションで射撃がどう処理されるのかを見ていきましょう。

まずはクライアント、つまりあなたのローカルPCから説明します。クライアントは「射撃した」という情報データをサーバーに送信するとすぐに、その射撃のマズルフラッシュと弾道を表示する処理を開始します。これらを表示するには新たなフレームを画面上にレンダリングする必要があるので、表示されるのは最短でも射撃の入力から1フレーム後になります。ここで重要なことは、弾道が表示されるフレームは射撃が処理されるフレームと同じではなく、少なくとも1フレームは遅れているという点です。

これが射撃の明瞭性の問題につながる可能性があります(この同期ズレを解消するためによく用いられる方法のひとつは弾を遅延させることですが、私たちはそれは行っていません。弾を遅延させると、VALORANTで最小化したいと考えている“入力の遅延”が増加してしまうからです)。マズルフラッシュと弾道を表示した後、クライアントはサーバーから結果が返ってくるのを待ってから、弾が命中したがどうかを描画します。全ユーザーの間で一貫性を保ち、クライアントをハッキングして偽の射撃結果を送信するチート行為を排除するために、射撃結果はすべてサーバー側が優先で管理されています。

一方のサーバー側ではまず、射撃が行われたというメッセージをクライアントから受け取ります。この時、インターネットのレイテンシによって、射撃が入力されてから受け取るまでにはいくらか時間が経過してしまいます。メッセージを受け取ると、プレイヤーの画面に表示されたシミュレーション結果が正しいことを確認するために、サーバーはメッセージに添えられたタイムスタンプの時刻までシミュレーションを巻き戻してから、当たり判定を計算します(この際、プレイヤーの位置やアニメーションのポーズも巻き戻されます)。これを完了すると、結果をクライアントに送り返します。以降は、ヘッドショットを成功させたと仮定して説明していきましょう。

クライアントはサーバーから射撃結果のメッセージを受け取ると、その後、適切なビジュアルエフェクトとオーディオを再生します。ヘッドショットの場合は、ヘッドショットのビジュアルエフェクトとオーディオが再生されるというわけです。クライアントはサーバーからの返事を待ってから射撃結果を描写するため、弾道が表示されるタイミングとヒットエフェクト(命中したことを示すエフェクト)が再生されるタイミングの間にはタイムラグが発生します。クライアントとサーバー間のラウンドトリップタイム(例:サーバーまで40msなら、弾道とヒットエフェクトの間に発生するのは80ms)にごく短い処理時間を足した時間がここのタイムラグになります。レイテンシが大きい場合は、この遅延が知覚できるくらい大きくなります。

これは明瞭性における問題で、私たちが積極的に改善を試みている部分です。

ケーススタディ 1:動いているターゲットを射撃した場合

Case_Study_1.gif


当たり判定について寄せられる報告を見てみると、「ターゲットが走っている」場合のものが多いです。走っているターゲットに射撃が当たった場合にビジュアル上で何が起こるのかを詳しく見てみましょう。走っているターゲットにプレイヤーがヘッドショットを当てたと判定されています。この例における問題を分かりやすく説明するために、クライアントは60 FPSで動作しているとしましょう。弾道が表示される直前のフレームを見ると、照準がターゲットの頭に重なっていることが分かります。

case-study-1_frame-1.jpgcase-study-1_frame-2.jpg

しかし、弾道が表示されるフレームでは、すでにターゲットの頭は照準からズレています。

case_study_1_part_2.gif

次も同じような状況ですが、今度はわずかにターゲットを外したと判定されます。フレームごとに見てみると、先ほどとは逆になっていることがわかります。つまり、弾道が表示される直前のフレームでは照準が頭からズレていますが、弾道が表示されるフレームでは照準は頭に重なっているのです。弾道の表示されているフレームだけを見ると、「これは明らかにヘッドショットだ!」と思うかもしれません。しかし、射撃が行われたタイミングを正確に把握するためには、弾道が表示される前のフレームを見る必要があるのです。

case-study-1_part2_frame-1.jpgcase-study-1_part2_frame-2.jpg
case-study-1_part2_no-hit-vfx.jpg

ここで、1つ目の動画でヒットエフェクトがレンダリングされるフレームに注目してみましょう。インターネットのレイテンシによって発生する遅延が原因で、ターゲットの位置とヒットエフェクトの位置には、明確に気付くくらいのズレが発生しています。こういったケースでは、エフェクトが表示された時点での敵の位置に注目してしまいがちで、射撃が行われた時点での敵の位置には注目しにくいのですが、これがいくつかの混乱の原因となります。これにしゃがみやストレイフ移動時が加わることでさらなる混乱が生じることもあるのですが、それは後のケーススターディ2で見ていきましょう。

case-study-1_part2_frame-where-hit-vfx-rendered.jpg

このケーススタディは、現在の当たり判定システムにおける明瞭性の欠如を示しています。内部処理に関する知識がないと状況を明確に理解できない、というのは理想的な状況ではありません。開発者としてこれは問題であると認識しており、現在こういったケースで明瞭性を改善する方法を模索している最中です。

ケーススタディ 2:敵がヒットエフェクトに重なるようにしゃがんだ場合

遠距離から銃撃戦を始めたとしましょう。あとから後悔することになるものの、あなたは左クリックを長押ししてヴァンダルを乱射しました。少なくとも1発はヘッドショットになるはずだ…と。しかし、現実はそう甘くはありません。実際はボディショットを3発当てて117ダメージを与えただけで、お返しにヘッドショットを食らってしまいました。

怒りに震えながら試合後に映像を確認したあなたは、あの時の当たり判定が間違っていたことを確信します。敵のプレイヤーはあなたの射撃を避けようとしてしゃがみを連打していたのですが、しゃがんだ敵の頭にはヒットエフェクトが表示されているのです!しかし、なぜかバトルレポートにはボディショットと表示されています。これはどういうことでしょうか?

この問題に関して、実際にredditに“ターゲットがしゃがむとヘッドショット判定が出ない(英語)”というタイトルで投稿がありました。

このような報告に対して開発チームが調査を行ったところ、多くの場合は当たり判定が「間違っているように見えている」ことが真の問題であることがわかりました。つまり、実は当たり判定は正しく機能しているのです。弾はあなたが射撃ボタンを押したときにエイムしていた方向に飛んでおり(拡散や移動によるブレは無視したとして)、サーバー側で正しく処理されています。

しかし、以下に挙げるような要素によってビジュアル上の誤解が生まれてしまうのです。

  1. インターネットのレイテンシによってヒットエフェクトの表示が遅延する
  2. ヒットエフェクトは射撃ボタンを押した瞬間のエイム先の座標に表示される
  3. ターゲットが動いている(ほとんどの場合はしゃがんでいる)
Case_Study_2.gif

別の例として、プレイヤーのPingが100である場合を考えてみましょう。プレイヤーがターゲットの肩を撃ったとします。当たり判定はサーバーからの返事を待つ必要があるので、ヒットエフェクトが表示されるのは100ms後になります。しかし、この100msの間に敵がしゃがみを始めたため、ヒットエフェクトが表示される位置に頭が重なってしまいました。遠距離で激しい銃撃戦を行っているときは、ボディショットのビジュアルエフェクトをヘッドショットのビジュアルエフェクトと勘違いしてしまう可能性もあります。

case-study-2_cursor-on-body.jpg case-study-2_hit-VFX-on-body-correctly.jpg case-study-2_player-crouches-into-vfx.jpg

ベータパッチ0.50の期間中、これは特に問題となっていました。パッチ0.50では出血表現の非表示化が誤ってすべてのプレイヤーに適用されてしまった上に、当時のビジュアルエフェクトはヘッドショットとボディショットの区別をつけづらいものだったからです。同じビジュアルエフェクトではないものの、戦闘中は両者の違いがわかりにくくなる場合もあることを認識していなかったのです。

このしゃがみに関する問題も当たり判定の明瞭性に関するもので、現在改善に向けて取り組んでいます。この解決方法のひとつとして、ヒットエフェクトを(マップ上の座標ではなく)当たり判定が発生した体の部位に紐づけて表示させることを検討しています。そうすれば、レイテンシが高い状態でも当たり判定とビジュアルエフェクトの関連性が明確になるはずです。

出血表現を無効に設定した場合のヘッドショットとボディショットのビジュアルエフェクトの比較(現行パッチ):

headshot-VFX.jpgbody-shot-VFX.jpg

明瞭性改善の計画

2つのケーススタディはヒットエフェクトの改善すべき部分を浮き彫りにしています。私たちが計画している変更のひとつは、先ほどお伝えしたように当たり判定が発生した体の部位に出血と火花のエフェクトを発生させるようにすることです。こうすれば、キャラクターの動きを追従して、エフェクト発生時のキャラクター位置に違和感なく表示できるようになります。ビジュアルエフェクトの発生位置が敵の体の動きにあわせて一緒に動くことになるので、ケーススタディ2の敵がしゃがんだ状況での明瞭性が大幅に改善できるというわけです。

ただし、欠点もあります。ターゲットが遮蔽物に隠れると、ビジュアルエフェクトもターゲットと一緒に遮蔽物の後ろへ隠れてしまうのです。Pingが100msのプレイヤーが、コーナーからピークしてきた敵を撃った場合を考えてみましょう。弾が命中した直後に敵が遮蔽物の背後に隠れて、隠れた後に命中の確認がサーバーから送られてきた場合、撃ったプレイヤーはヒットエフェクトを見ることができない可能性があります。

パーティクルを追加して、「サーバーのシミュレーションに基づく、ターゲットの体の部位と一緒に動くパーティクル」と「クライアントのシミュレーションに基づく、当たり判定が発生した座標に直ちに表示されるパーティクル」の両方を描画することで、この問題を軽減する方法も考えています。しかし、この方法では、クライアントとサーバーのシミュレーションで射撃の結果が一致しなかった場合に混乱を生じさせる可能性があります。射撃が当たったのかどうかをわかりやすくするためには、発生したエフェクトが何を表しているのかをわかりやすくする必要があるのです。

今後もこれらの明瞭性の問題の改善を続けていきますので、将来のパッチで明瞭性のアップデート内容についてお話しできればと思います。

動画は引き続き大歓迎

今回の記事がVALORANTの当たり判定や射撃処理の仕組みをより良く理解する助けとなれば幸いです。今後も当たり判定に問題があると感じることがあれば、遠慮なく動画をお送りください。可能な限り力を尽くして調査を行います。

たとえ何も問題がなかったとしても、正確性のバグが発生した際に原因の特定に活用できるので、動画はいつでも大歓迎です。それでは、今日もredditを巡回してきます(“当たり判定”という文字を含んだ投稿がredditの人気投稿欄に上がるたびに脈拍が跳ね上がりますが…)。

redditに投稿された当たり判定の正確性に関するバグ(一例)