[DevLog #005] 「ラグなんて感じさせない」戦闘を作るために、演出とダメージを切り離した話

DevLog

はじめに

アクションゲームをオンラインで遊んでいて、「攻撃したのに手応えがない」「当たったのにエフェクトが遅れる」という体験をしたことはないでしょうか。

これはネットワークのラグ(遅延)が原因です。攻撃の情報がサーバーに届いて、サーバーが「当たった」と判断して、その結果がまた自分の画面に戻ってくるまでの間、画面では何も起きていない。

これを解決するために今回採用したのが、**「Client Authority for Feel(見た目はクライアントが先に動く)」**という設計思想です。


問題:サーバーの返答を待つと遅い

マルチプレイゲームでは、基本的にサーバーが「真実」を管理します。

プレイヤーが攻撃 → サーバーへ送信 → サーバーが判定 → 結果を返す → 画面に反映

正確ではあります。でも、サーバーへ往復する時間分だけ、必ず遅れます。有線LAN環境でも数十ミリ秒、回線が悪ければ100〜200ミリ秒の遅延が生まれます。アクションゲームにとって、これは致命的な手応えの悪さになります。


解決策:「演出」と「数値」を分ける

今回の実装の核心はここです。

ダメージの数値(HP がいくら減るか)はサーバーが決める。でも、演出(エフェクト・音・ヒットストップ)はクライアントが先に出す。

【演出】クライアントが先行(サーバー返答を待たない)
  攻撃が当たった瞬間 → VFX(火花)・ヒット音・ヒットストップを即座に再生

【数値】サーバー確定後に反映
  サーバーが「確かに当たった」と判断 → HP を減らす → 全クライアントへ通知

プレイヤーが感じる「当たった!」という感触は演出で決まります。HP が何点減ったかは0.1秒後でも問題ない。この分離が、ラグを感じさせない戦闘の秘訣です。


実装の詳細①:武器の当たり判定(SphereTrace)

剣を振ったとき、どうやって「当たった」を検知するか。

単純に「剣のモデルが触れた瞬間」で判定すると、振りが速すぎて敵をすり抜けることがあります(コンティニュアスコリジョン問題)。

そこで採用したのが SphereTrace(球体状の判定) です。

前フレームの剣の位置
  ↓
現フレームの剣の位置
  ↓
この2点を球体で繋いでトレース

0.015秒ごとにこれを繰り返すことで、剣が通った軌跡全体をカバーします。どれだけ速く振っても、軌跡の中に敵がいれば確実に検知できます。

当たりを検知したらクライアントが即座に演出を出し、同時にサーバーへ「この座標で当たった」と報告します。サーバーは同じ座標で再度判定し、「確かに当たっている」なら正式なダメージを処理します。これにより不正なダメージも弾けます。


実装の詳細②:自分の攻撃か、他人の攻撃か

少し複雑なのが、「誰が攻撃したか」によって処理を変える部分です。

マルチプレイでは、自分が攻撃することもあれば、他のプレイヤーが攻撃する様子を自分の画面で見ることもあります。

自分が攻撃したとき: すでに攻撃した瞬間にクライアント側でエフェクトを出しています。サーバーからの通知が戻ってきたときに、もう一度エフェクトを出すと二重になってしまいます。だから、自分が攻撃元のときは演出をスキップします。

他人が攻撃したとき: 自分の画面では何も先行処理していません。サーバーから「誰かが攻撃した」という通知が届いたタイミングで、初めて演出とダメージ表示を出します

攻撃した人 == 自分?
  Yes(自分の攻撃):演出は既に出した → HP更新だけ受け取る
  No(他人の攻撃) :初めて演出を出す → HP更新も表示する

実装の詳細③:コンボシステム

「攻撃中に次の攻撃を入力すると、アニメーションが終わるタイミングで繋がる」というコンボも実装しています。

仕組みはシンプルです。

  1. 攻撃中に入力があれば SaveAttack=true で「先行入力あり」と記憶する
  2. アニメーションの特定フレームに仕込んだ AnimNotify が「コンボを続けていいよ」と呼んでくる
  3. そのタイミングで SaveAttack を確認し、true なら次の攻撃へ繋ぐ

攻撃のたびにサーバーとやり取りするのは同じですが、コンボの「つながり感」はクライアント側のアニメーションとフラグ管理で作っているため、ラグの影響を受けにくくなっています。

残っている課題

一点、まだ解決できていない問題があります。

回避(Roll)中にも攻撃が当たってしまう問題です。「よけているつもりなのに食らってしまう」という状態で、回避の気持ちよさを作る上で最優先で解決したい課題です。


今日学んだこと

  • ゲーム自体の仕様事態で何が許容できて何が許容できないのかをしっかり考えることでラグの対策方法が変わってくる。(今回はPvEが主体なので、プレイヤーの体感重視で調整している。)
  • 演出と数値を分離することで、ラグを感じさせない戦闘が作れる。
  • SphereTrace を前フレームと現フレームで繋ぐことで、高速な剣撃でもすり抜けを防げる。
  • 自分の攻撃か他人の攻撃かで処理を出し分けることで、マルチプレイでの二重表示を防げる。

現在の状況

攻撃・コンボ・突進・抜刀納刀・ダメージ属性まで実装が進みました。

次は回避の問題を解決してから、実際に敵1体と戦闘テストを行います。「15〜25秒(ここはプレイしてみて要調整)で1体倒せる」感触が作れているかどうか、確かめるフェーズに入ります。


次回:回避の実装と、はじめての戦闘テストで気づいたこと

タイトルとURLをコピーしました