8#include "PhysicsPublic.h"
9#include "PhysXPublic.h"
10#include "PhysXVehicleManager.h"
11#include "Components/PrimitiveComponent.h"
12#include "Logging/MessageLog.h"
14UWheeledVehicleMovementComponentNW::UWheeledVehicleMovementComponentNW(
const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
17 PxVehicleEngineData DefEngineData;
18 EngineSetup.MOI = DefEngineData.mMOI;
19 EngineSetup.MaxRPM = OmegaToRPM(DefEngineData.mMaxOmega);
20 EngineSetup.DampingRateFullThrottle = DefEngineData.mDampingRateFullThrottle;
21 EngineSetup.DampingRateZeroThrottleClutchEngaged = DefEngineData.mDampingRateZeroThrottleClutchEngaged;
22 EngineSetup.DampingRateZeroThrottleClutchDisengaged = DefEngineData.mDampingRateZeroThrottleClutchDisengaged;
25 FRichCurve* TorqueCurveData = EngineSetup.TorqueCurve.GetRichCurve();
26 for (PxU32 KeyIdx = 0; KeyIdx < DefEngineData.mTorqueCurve.getNbDataPairs(); ++KeyIdx)
28 float Input = DefEngineData.mTorqueCurve.getX(KeyIdx) * EngineSetup.MaxRPM;
29 float Output = DefEngineData.mTorqueCurve.getY(KeyIdx) * DefEngineData.mPeakTorque;
30 TorqueCurveData->AddKey(Input, Output);
33 PxVehicleClutchData DefClutchData;
34 TransmissionSetup.ClutchStrength = DefClutchData.mStrength;
36 PxVehicleGearsData DefGearSetup;
37 TransmissionSetup.GearSwitchTime = DefGearSetup.mSwitchTime;
38 TransmissionSetup.ReverseGearRatio = DefGearSetup.mRatios[PxVehicleGearsData::eREVERSE];
39 TransmissionSetup.FinalRatio = DefGearSetup.mFinalRatio;
41 PxVehicleAutoBoxData DefAutoBoxSetup;
42 TransmissionSetup.NeutralGearUpRatio = DefAutoBoxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL];
43 TransmissionSetup.GearAutoBoxLatency = DefAutoBoxSetup.getLatency();
44 TransmissionSetup.bUseGearAutoBox =
true;
46 for (uint32 i = PxVehicleGearsData::eFIRST; i < DefGearSetup.mNbRatios; ++i)
49 GearData.
DownRatio = DefAutoBoxSetup.mDownRatios[i];
50 GearData.
UpRatio = DefAutoBoxSetup.mUpRatios[i];
51 GearData.
Ratio = DefGearSetup.mRatios[i];
52 TransmissionSetup.ForwardGears.Add(GearData);
56 FRichCurve* SteeringCurveData = SteeringCurve.GetRichCurve();
57 SteeringCurveData->AddKey(0.0f, 1.0f);
58 SteeringCurveData->AddKey(20.0f, 0.9f);
59 SteeringCurveData->AddKey(60.0f, 0.8f);
60 SteeringCurveData->AddKey(120.0f, 0.7f);
63 const int32 NbrWheels = 4;
64 WheelSetups.SetNum(NbrWheels);
65 DifferentialSetup.SetNum(NbrWheels);
71void UWheeledVehicleMovementComponentNW::PostEditChangeProperty(
struct FPropertyChangedEvent& PropertyChangedEvent)
73 Super::PostEditChangeProperty(PropertyChangedEvent);
74 const FName PropertyName = PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None;
76 if (PropertyName == TEXT(
"DownRatio"))
78 for (int32 GearIdx = 0; GearIdx < TransmissionSetup.ForwardGears.Num(); ++GearIdx)
84 else if (PropertyName == TEXT(
"UpRatio"))
86 for (int32 GearIdx = 0; GearIdx < TransmissionSetup.ForwardGears.Num(); ++GearIdx)
92 else if (PropertyName == TEXT(
"SteeringCurve"))
95 TArray<FRichCurveKey> SteerKeys = SteeringCurve.GetRichCurve()->GetCopyOfKeys();
96 for (int32 KeyIdx = 0; KeyIdx < SteerKeys.Num(); ++KeyIdx)
98 float NewValue = FMath::Clamp(SteerKeys[KeyIdx].Value, 0.0f, 1.0f);
99 SteeringCurve.GetRichCurve()->UpdateOrAddKey(SteerKeys[KeyIdx].Time, NewValue);
107 for (int32 i = 0; i < Setup.Num(); ++i)
109 PxSetup.setDrivenWheel(i, Setup[i].bDriven);
116 float PeakTorque = 0.0f;
117 TArray<FRichCurveKey> TorqueKeys =
TorqueCurve.GetRichCurveConst()->GetCopyOfKeys();
118 for (int32 KeyIdx = 0; KeyIdx < TorqueKeys.Num(); ++KeyIdx)
120 FRichCurveKey& Key = TorqueKeys[KeyIdx];
121 PeakTorque = FMath::Max(PeakTorque, Key.Value);
128 PxSetup.mMOI = M2ToCm2(Setup.
MOI);
129 PxSetup.mMaxOmega = RPMToOmega(Setup.
MaxRPM);
135 PxSetup.mPeakTorque = M2ToCm2(PeakTorque);
138 PxSetup.mTorqueCurve.clear();
139 TArray<FRichCurveKey> TorqueKeys = Setup.
TorqueCurve.GetRichCurveConst()->GetCopyOfKeys();
140 int32 NumTorqueCurveKeys = FMath::Min<int32>(TorqueKeys.Num(), PxVehicleEngineData::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES);
141 for (int32 KeyIdx = 0; KeyIdx < NumTorqueCurveKeys; ++KeyIdx)
143 FRichCurveKey& Key = TorqueKeys[KeyIdx];
144 PxSetup.mTorqueCurve.addPair(FMath::Clamp(Key.Time / Setup.
MaxRPM, 0.0f, 1.0f), Key.Value / PeakTorque);
154 PxSetup.mRatios[i + PxVehicleGearsData::eFIRST] = Setup.
ForwardGears[i].Ratio;
157 PxSetup.mNbRatios = Setup.
ForwardGears.Num() + PxVehicleGearsData::eFIRST;
165 PxSetup.mUpRatios[i + PxVehicleGearsData::eFIRST] = GearData.
UpRatio;
166 PxSetup.mDownRatios[i + PxVehicleGearsData::eFIRST] = GearData.
DownRatio;
173int32 UWheeledVehicleMovementComponentNW::GetCustomGearBoxNumForwardGears()
const
175 return TransmissionSetup.ForwardGears.Num();
178void SetupDriveHelper(
const UWheeledVehicleMovementComponentNW* VehicleData,
const PxVehicleWheelsSimData* PWheelsSimData, PxVehicleDriveSimDataNW& DriveData)
180 PxVehicleDifferentialNWData DifferentialSetup;
183 DriveData.setDiffData(DifferentialSetup);
185 PxVehicleEngineData EngineSetup;
187 DriveData.setEngineData(EngineSetup);
189 PxVehicleClutchData ClutchSetup;
190 ClutchSetup.mStrength = M2ToCm2(VehicleData->TransmissionSetup.ClutchStrength);
191 DriveData.setClutchData(ClutchSetup);
193 PxVehicleGearsData GearSetup;
195 DriveData.setGearsData(GearSetup);
197 PxVehicleAutoBoxData AutoBoxSetup;
199 DriveData.setAutoBoxData(AutoBoxSetup);
202void UWheeledVehicleMovementComponentNW::SetupVehicle()
204 if (!UpdatedPrimitive)
209 if (WheelSetups.Num() < 2)
212 PVehicleDrive =
nullptr;
216 for (int32 WheelIdx = 0; WheelIdx < WheelSetups.Num(); ++WheelIdx)
218 const FWheelSetup& WheelSetup = WheelSetups[WheelIdx];
219 if (WheelSetup.BoneName == NAME_None)
226 SetupVehicleShapes();
232 PxVehicleWheelsSimData* PWheelsSimData = PxVehicleWheelsSimData::allocate(WheelSetups.Num());
233 SetupWheels(PWheelsSimData);
236 PxVehicleDriveSimDataNW DriveData;
240 PxVehicleDriveNW* PVehicleDriveNW = PxVehicleDriveNW::allocate(WheelSetups.Num());
241 check(PVehicleDriveNW);
243 FBodyInstance* TargetInstance = UpdatedPrimitive->GetBodyInstance();
245 FPhysicsCommand::ExecuteWrite(TargetInstance->ActorHandle, [&](
const FPhysicsActorHandle& Actor)
247 PxRigidActor* PActor = FPhysicsInterface::GetPxRigidActor_AssumesLocked(Actor);
253 if (PxRigidDynamic* PVehicleActor = PActor->is<PxRigidDynamic>())
255 PVehicleDriveNW->setup(GPhysXSDK, PVehicleActor, *PWheelsSimData, DriveData, 0);
256 PVehicleDriveNW->setToRestState();
259 PWheelsSimData->free();
263 PWheelsSimData =
nullptr;
266 PVehicle = PVehicleDriveNW;
267 PVehicleDrive = PVehicleDriveNW;
269 SetUseAutoGears(TransmissionSetup.bUseGearAutoBox);
273void UWheeledVehicleMovementComponentNW::UpdateSimulation(
float DeltaTime)
275 if (PVehicleDrive ==
nullptr)
278 FBodyInstance* TargetInstance = UpdatedPrimitive->GetBodyInstance();
280 FPhysicsCommand::ExecuteWrite(TargetInstance->ActorHandle, [&](
const FPhysicsActorHandle& Actor)
282 PxVehicleDriveNWRawInputData RawInputData;
283 RawInputData.setAnalogAccel(ThrottleInput);
284 RawInputData.setAnalogSteer(SteeringInput);
285 RawInputData.setAnalogBrake(BrakeInput);
286 RawInputData.setAnalogHandbrake(HandbrakeInput);
288 if (!PVehicleDrive->mDriveDynData.getUseAutoGears())
290 RawInputData.setGearUp(bRawGearUpInput);
291 RawInputData.setGearDown(bRawGearDownInput);
295 PxFixedSizeLookupTable<8> SpeedSteerLookup;
296 TArray<FRichCurveKey> SteerKeys = SteeringCurve.GetRichCurve()->GetCopyOfKeys();
297 const int32 MaxSteeringSamples = FMath::Min(8, SteerKeys.Num());
298 for (int32 KeyIdx = 0; KeyIdx < MaxSteeringSamples; KeyIdx++)
300 FRichCurveKey& Key = SteerKeys[KeyIdx];
301 SpeedSteerLookup.addPair(KmHToCmS(Key.Time), FMath::Clamp(Key.Value, 0.0f, 1.0f));
304 PxVehiclePadSmoothingData SmoothData = {
305 { ThrottleInputRate.RiseRate, BrakeInputRate.RiseRate, HandbrakeInputRate.RiseRate, SteeringInputRate.RiseRate, SteeringInputRate.RiseRate },
306 { ThrottleInputRate.FallRate, BrakeInputRate.FallRate, HandbrakeInputRate.FallRate, SteeringInputRate.FallRate, SteeringInputRate.FallRate }
309 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
310 PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(SmoothData, SpeedSteerLookup, RawInputData, DeltaTime,
false, *PVehicleDriveNW);
314void UWheeledVehicleMovementComponentNW::UpdateEngineSetup(
const FVehicleNWEngineData& NewEngineSetup)
318 PxVehicleEngineData EngineData;
321 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
322 PVehicleDriveNW->mDriveSimData.setEngineData(EngineData);
326void UWheeledVehicleMovementComponentNW::UpdateDifferentialSetup(
const TArray<FVehicleNWWheelDifferentialData>& NewDifferentialSetup)
330 PxVehicleDifferentialNWData DifferentialData;
333 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
334 PVehicleDriveNW->mDriveSimData.setDiffData(DifferentialData);
342 PxVehicleGearsData GearData;
345 PxVehicleAutoBoxData AutoBoxData;
348 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
349 PVehicleDriveNW->mDriveSimData.setGearsData(GearData);
350 PVehicleDriveNW->mDriveSimData.setAutoBoxData(AutoBoxData);
356 if (val != defaultValue)
362void UWheeledVehicleMovementComponentNW::Serialize(FArchive& Ar)
364 Super::Serialize(Ar);
365 if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_VEHICLES_UNIT_CHANGE)
367 PxVehicleEngineData DefEngineData;
368 const float DefaultRPM = OmegaToRPM(DefEngineData.mMaxOmega);
371 EngineSetup.MaxRPM = EngineSetup.MaxRPM != DefaultRPM ? OmegaToRPM(EngineSetup.MaxRPM) : DefaultRPM;
374 if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_VEHICLES_UNIT_CHANGE2)
376 PxVehicleEngineData DefEngineData;
377 PxVehicleClutchData DefClutchData;
381 BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateZeroThrottleClutchDisengaged, DefEngineData.mDampingRateZeroThrottleClutchDisengaged);
382 BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateZeroThrottleClutchEngaged, DefEngineData.mDampingRateZeroThrottleClutchEngaged);
388void UWheeledVehicleMovementComponentNW::ComputeConstants()
390 Super::ComputeConstants();
391 MaxEngineRPM = EngineSetup.MaxRPM;
394const void* UWheeledVehicleMovementComponentNW::GetTireData(physx::PxVehicleWheels* InWheels, UVehicleWheel* InWheel)
396 const void* realShaderData = &InWheels->mWheelsSimData.getTireData((PxU32)InWheel->WheelIndex);
397 return realShaderData;
400const int32 UWheeledVehicleMovementComponentNW::GetWheelShapeMapping(physx::PxVehicleWheels* InWheels, uint32 InWheel)
402 const physx::PxI32 ShapeIndex = InWheels->mWheelsSimData.getWheelShapeMapping((PxU32)InWheel);
406const physx::PxVehicleWheelData UWheeledVehicleMovementComponentNW::GetWheelData(physx::PxVehicleWheels* InWheels, uint32 InWheel)
408 const physx::PxVehicleWheelData WheelData = InWheels->mWheelsSimData.getWheelData((physx::PxU32)InWheel);
static void GetVehicleEngineSetup(const FVehicleNWEngineData &Setup, PxVehicleEngineData &PxSetup)
static void GetVehicleGearSetup(const FVehicleNWTransmissionData &Setup, PxVehicleGearsData &PxSetup)
void BackwardsConvertCm2ToM2NW(float &val, float defaultValue)
void SetupDriveHelper(const UWheeledVehicleMovementComponentNW *VehicleData, const PxVehicleWheelsSimData *PWheelsSimData, PxVehicleDriveSimDataNW &DriveData)
static void GetVehicleDifferentialNWSetup(const TArray< FVehicleNWWheelDifferentialData > &Setup, PxVehicleDifferentialNWData &PxSetup)
static void GetVehicleAutoBoxSetup(const FVehicleNWTransmissionData &Setup, PxVehicleAutoBoxData &PxSetup)
float MOI
Moment of inertia of the engine around the axis of rotation (Kgm^2).
float MaxRPM
Maximum revolutions per minute of the engine
float DampingRateFullThrottle
Damping rate of engine when full throttle is applied (Kgm^2/s)
float FindPeakTorque() const
Find the peak torque produced by the TorqueCurve
float DampingRateZeroThrottleClutchEngaged
Damping rate of engine in at zero throttle when the clutch is engaged (Kgm^2/s)
FRuntimeFloatCurve TorqueCurve
Torque (Nm) at a given RPM
float DampingRateZeroThrottleClutchDisengaged
Damping rate of engine in at zero throttle when the clutch is disengaged (in neutral gear) (Kgm^2/s)
float Ratio
Determines the amount of torque multiplication
float DownRatio
Value of engineRevs/maxEngineRevs that is low enough to gear down
float UpRatio
Value of engineRevs/maxEngineRevs that is high enough to gear up
float NeutralGearUpRatio
Value of engineRevs/maxEngineRevs that is high enough to increment gear
float GearSwitchTime
Time it takes to switch gears (seconds)
float FinalRatio
The final gear ratio multiplies the transmission gear ratios.
TArray< FVehicleNWGearData > ForwardGears
Forward gear ratios (up to 30)
float ReverseGearRatio
Reverse gear ratio
float GearAutoBoxLatency
Minimum time it takes the automatic transmission to initiate a gear change (seconds)