Vehicular Combat
概要
KEO Vehicular Combat サンプルは、Quantumで作られた車両コンバットゲームです。このサンプルには2種類の車両(軽量バギーと重量のある8輪戦車)が含まれており、これらを使って進行中のフリーフォーオールデスマッチで戦います。
このサンプルはRedcatpigによって開発されました。Redcatpigが近日中にリリース予定のKEOをベースとしています。
テクニカルハイライト
- 運転物理搭載の車両コントローラー
- 多軸構成に対応
- 動的サスペンションビューフォーミュラ
- ダメージシステム
- Hitscan武器システム
スクリーンショット
ダウンロード
多軸構成に対応
デフォルトでは、このサンプルは4つの車軸と8つの車輪(車軸あたり2つの車輪)をサポートしています。VehicleState
コンポーネントの固定配列サイズを大きくすることで、より多くの車軸と車輪を持つ車両を作成することができます; 単純に最大車両が持つ可能性がある車軸の最大数に設定します。
C#
component VehicleState {
asset_ref<VehicleConfig> Config;
DriveTrain DriveTrain;
Byte AxleCount;
array<AxleState>[4] Axles; // modify this value for support more axles
[HideInInspector] FP TimeFlipped;
[HideInInspector] FP TimeFalling;
[HideInInspector] FP Fuel;
}
車軸のセットアップ
各車両について、その特定の車両のAxle Count
を設定します。各アクセルが機能するにはAxleConfig
、WheelConfig
、SuspensionConfig
、TireConfig
が必要です。
車軸の設定
AxleConfig
で車軸のオフセット(車両の中心/ピボットに対する相対的な位置)を設定できます。
各車軸はトラクションおよび/またはステアリングを適用できます。車軸が車両の後方にあり車輪もステアリングを適用する場合には(タンク車の場合など)、車輪に適切なステアリングを適用するためにInvertSteeringオプションを確認する必要があります。
C#
struct AxleState {
asset_ref<AxleConfig> AxleConfig;
asset_ref<WheelConfig> WheelConfig;
asset_ref<SuspensionConfig> SuspensionConfig;
asset_ref<TireConfig> TireConfig;
[HideInInspector] FP SteerAngle;
[HideInInspector] WheelState WheelL;
[HideInInspector] WheelState WheelR;
}
運転アシスト
運転アシストセクションでは、各ステアリング車軸に対するステアリングの最大および最小角度を設定します。これによって、高速で運転する際のオーバーステアリングやコントロールを失うことを防ぎます。
サスペンション
Quantumシミュレーション内の車両物理の値を読むことで、サスペンションがUnity側で視覚化されます。これを担うクラスはAxleView.cs
です。
これは純粋なビジュアル表示のため、サスペンションのビジュアルはシミュレーションに反応しますが、サスペンション自体はシミュレーションの一部ではありません。このため、以下のセクションは完全にUnity側の表示とコードに関するものです。
動的サスペンションビュー
このサンプルに含まれるカスタムサスペンションビュー用の方式は、KEOの車両で作成されるサスペンションのタイプ特有のものです。ただし、ロジックは他のサスペンションタイプに適用できます。
サスペンションは以下から成ります:
- 左/右車輪: 車両の動きに応じて、X軸上で回転する視覚車輪。
- 左/右ピボット: このオブジェクトはサスペンション圧縮(Quantumシミュレーションから取得)に応じて設定されたY位置を取得し、ステアリングをシミュレーションするためにY軸上で回転します(車輪オブジェクトはピボットの子でなければなりません)。
- 左/右の修正済みピボット: 車輪のY位置と同期されるオブジェクトで、サスペンションバーのすべての「内部」パーツを含みます (以下で説明します)。
サスペンション方式
サスペンションバーは内側トップバー(A)、外側トップバー(B)、内側ボトム(C)、外側ボトム(D)で構成されています。
ビジュアルを作動させる方式は以下のとおりです:
この方式は車輪のY位置を取得し、それに応じて内側と外側のサスペンション部品を回転させて油圧バーの開閉をシミュレートするという考えにもとづいています。
そのためには、所定のサスペンションアームの開始角度(Alpha)が必要です。開始角度はトップバー(ケース #1)では常に0であり、ボトムバーでは測定する必要があります(下図のケース #2のAlphaを参照)。オフセット、すなわちバーが回転する位置からの最初のY距離も必要です(下図のケース #2のオフセット参照)。最後にワールドのX軸に完全に平行なときのサスペンションアームの長さ(Beta)を考慮する必要があります(ケース1のBetaを参照してください)。これらの値を測定するには、車両の作成に使用した3Dソフトを使用するのが最適です。
C#
LeftPivot.localRotation = Quaternion.Euler(0, axleState.WheelL.SteerAngle.AsFloat, 0);
RightPivot.localRotation = Quaternion.Euler(0, axleState.WheelR.SteerAngle.AsFloat, 0);
if (vehicleViewUpdateData.VehiclePhysicsBody->IsSleeping)
{
return;
}
// update wheels suspension travel
var suspensionMaxTravel = _suspensionConfig.MaxTravel.AsFloat;
var leftSuspensionCompression = axleState.WheelL.Suspension.CompressionPrevious.AsFloat - suspensionMaxTravel;
var rightSuspensionCompression = axleState.WheelR.Suspension.CompressionPrevious.AsFloat - suspensionMaxTravel;
LeftPivot.localPosition = _leftPivotPosition + new Vector3(0, leftSuspensionCompression + _anchorOffset, 0) / Scale;
RightPivot.localPosition = _rightPivotPosition + new Vector3(0, rightSuspensionCompression + _anchorOffset, 0) / Scale;
LeftFixedPivot.localPosition = _leftFixedPivotPosition + new Vector3(0, leftSuspensionCompression + _anchorOffset, 0) / Scale;
RightFixedPivot.localPosition = _rightFixedPivotPosition + new Vector3(0, rightSuspensionCompression + _anchorOffset, 0) / Scale;
C#
float angleTop;
float angleBottom;
if (wheelLocalPos.y < 0)
{
angleBottom = (Mathf.Atan((Mathf.Abs(wheelLocalPos.y) + _vehicleView.BottomOffset) / _vehicleView.BottomBeta) * 180 / Mathf.PI - _vehicleView.Alpha) * -1;
angleTop = (Mathf.Atan((Mathf.Abs(wheelLocalPos.y) + _vehicleView.TopOffset) / _vehicleView.TopBeta) * 180 / Mathf.PI) * -1;
}
else
{
angleBottom = Mathf.Atan((Mathf.Abs(wheelLocalPos.y) + _vehicleView.BottomOffset) / _vehicleView.BottomBeta) * 180 / Mathf.PI - _vehicleView.Alpha;
angleTop = Mathf.Atan((Mathf.Abs(wheelLocalPos.y) + _vehicleView.TopOffset) / _vehicleView.TopBeta) * 180 / Mathf.PI;
}
if (leftSide)
{
angleTop = angleTop < 0 ? Mathf.Abs(angleTop) : angleTop * -1;
angleBottom = angleBottom < 0 ? Mathf.Abs(angleBottom) : angleBottom * -1;
}
suspensionInnerBottom.localRotation = Quaternion.Euler(new Vector3(0, 0, angleBottom));
suspensionInnerTop.localRotation = Quaternion.Euler(new Vector3(0, 0, angleTop));
suspensionOuterBottom.localRotation = Quaternion.Euler(new Vector3(0, 0, angleBottom));
suspensionOuterTop.localRotation = Quaternion.Euler(new Vector3(0, 0, angleTop));
Back to top