目標

ゲームプロジェクト Fluffy Floaty Rubber Tennis は、物理ベースの固定カメラ宇宙テニスゲームです。プレイヤーの唯一の操作はラケットを振ることです。

ラケットを振る際にラケットと他の物体がどのように相互作用するかのロジックは、ラケットがヒットした物体に力を加え、プレイヤーに反作用力を加えることです。

なぜ Physics.SphereCast を使わないのか?

では、なぜ内蔵の Unity 物理関数 Physics.SphereCast を使わないのでしょうか?

もしかしたらその背後にある本当のロジックを理解していないだけかもしれませんが、ヒット距離が 0 の時にバグがあると思います。

下のスクリーンショットに示されているように、プレイヤーが左に向かってスイングすると、スフィアキャストはキャラクターの原点で始まり、ラケットより少し先で終わります。予想される衝突点はスフィアキャストの「最初の球体」とその右側の長い障害物の間に発生します。スフィアキャストが障害物に到達するまでの移動距離が 0 であるため、ヒット距離も 0 であると予想されます。

この時点までは、すべてが私にとって理にかなっています。実際には、スフィアキャストは予想通りヒット距離が 0 でヒットを返しますが、ヒットポイントは Vector3.Zero にあります!

私は複数のテストを行い、結果は一貫しています。ヒット距離が 0 である限り、ヒットポイントは常に Vector3.Zero にあります…

新しいソリューションの構築

組み込みの関数が期待通りに動作しないため、Physics.Raycast を使用して独自のソリューションを構築することにしました。

このメカニズムは、このプロジェクトのニーズに基づいています:ラケットを振ること。

直感性

問題を分解すると、これらはスイングを直感的にするための重要なポイントです:

  • 快適なスイングには、キャラクターの周りに小さな円の空間を含める必要があります。したがって、ボールがプレイヤーと重なっている場合、プレイヤーはそれを打つことができるはずです。
  • スイングは扇形である必要があります。なぜなら、スイングは基本的に腕を回転させてラケットが扇形の領域をカバーするからです。
  • スイングは、プレイヤーが狙っている方向またはマウスの位置に最も近い物体を最初にヒットする必要があります。

したがって、打撃領域は次のようにカバーする必要があります:

メカニズム

上記のように、アイデアは同心円を2つ描き、円の中心を通る2本の線を引いて扇形の角度を決定し、ヒットポイントを接続して平滑な中心角を持つ扇形領域を形成することです。

パラメータは以下の通りです:

  1. 重なり合う円の半径。
  2. 扇形がある円の半径。(スイング時にラケットが届く距離)
  3. 扇形の角度。

レイキャスティング

その後、小さな円から大きな円まで定義されたレイ密度でレイをキャストできます。このプロジェクトでは、

レイのソーティング

直感性セクションで述べたように、レイはプレイヤーがヒットしたい物体をヒットするようにソート/削除する必要があります。

たとえば、プレイヤーが右側を狙っていて、ヒットエリアと重なる緑の円がボールである場合、ソートなしのデフォルトの動作は非常にランダムです。たとえば、表示された画像では、レイは下から上、上から下、さらには中央からエッジに向かってキャストされることがあります。

この場合、次の3つのソーティング方法を追加することにしました:

  1. 距離ソート:セクターの中心からの距離に基づいてレイをソートします。

  2. 角度ソート:レイと照準方向との角度に基づいてレイをソートします。

  3. 最初/最後のヒットソート:レイがキャストされる順序に基づいてレイをソートします。

実装

いくつかのデバッグを経て、結果はかなり良好です。少なくともゲームプレイの観点からはそうです。

これは、さまざまなソート方法の完全な比較です:

first hit
最初のヒット
last hit
最後のヒット
distance min
最小距離
distance max
最大距離
angle min
最小角度
angle max
最大角度

ゲーム内でこの成果を見たいですか?

自分でゲームを試してみてください!