Expose vehicle relationship between speed and steer to driver

This commit is contained in:
Mr. Capybara
2024-01-02 20:39:24 -04:00
parent 07de7a26dd
commit 42b20b4e76
3 changed files with 126 additions and 25 deletions

View File

@@ -55,6 +55,48 @@ WheeledVehicle::DriveControlSettings WheeledVehicle::GetDriveControl() const
void WheeledVehicle::SetDriveControl(DriveControlSettings &value)
{
// Don't let have an invalid steer vs speed list.
if (&value.SteerVsSpeed == nullptr)
value.SteerVsSpeed = Array<WheeledVehicle::SteerControl>();
if (value.SteerVsSpeed.Count() < 1)
value.SteerVsSpeed.Add(WheeledVehicle::SteerControl());
else // physx backend requires the max of 4 values only
while (value.SteerVsSpeed.Count() > 4)
value.SteerVsSpeed.RemoveLast();
// Maintain all values clamped to have a ordened speed list
int steerVsSpeedCount = value.SteerVsSpeed.Count();
for (int i = 0; i < steerVsSpeedCount; i++)
{
// Apply only on changed value
if (_driveControl.SteerVsSpeed[i].Speed != value.SteerVsSpeed[i].Speed || _driveControl.SteerVsSpeed[i].Steer != value.SteerVsSpeed[i].Steer)
{
WheeledVehicle::SteerControl &steerVsSpeed = value.SteerVsSpeed[i];
steerVsSpeed.Steer = Math::Saturate(steerVsSpeed.Steer);
steerVsSpeed.Speed = Math::Max(steerVsSpeed.Speed, 10.0f);
// Clamp speeds to have an ordened list.
if (i >= 1)
{
WheeledVehicle::SteerControl &lastSteerVsSpeed = value.SteerVsSpeed[i - 1];
WheeledVehicle::SteerControl &nextSteerVsSpeed = value.SteerVsSpeed[Math::Clamp(i + 1, 0, steerVsSpeedCount - 1)];
float minSpeed = lastSteerVsSpeed.Speed;
float maxSpeed = nextSteerVsSpeed.Speed;
if (i + 1 < steerVsSpeedCount - 1)
steerVsSpeed.Speed = Math::Clamp(steerVsSpeed.Speed, minSpeed, maxSpeed);
else
steerVsSpeed.Speed = Math::Max(steerVsSpeed.Speed, minSpeed);
}
else if (steerVsSpeedCount > 1)
{
WheeledVehicle::SteerControl &nextSteerVsSpeed = value.SteerVsSpeed[i + 1];
steerVsSpeed.Speed = Math::Min(steerVsSpeed.Speed, nextSteerVsSpeed.Speed);
}
}
}
_driveControl = value;
}
@@ -392,7 +434,6 @@ void WheeledVehicle::Serialize(SerializeStream &stream, const void *otherObj)
SERIALIZE_MEMBER(Engine, _engine);
SERIALIZE_MEMBER(Differential, _differential);
SERIALIZE_MEMBER(Gearbox, _gearbox);
}
void WheeledVehicle::Deserialize(DeserializeStream &stream, ISerializeModifier *modifier)

View File

@@ -40,6 +40,45 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Wheeled Vehicle\"), ActorTo
Special
};
/// <summary>
/// Storage the relationship between speed and steer.
/// </summary>
API_STRUCT() struct SteerControl : ISerializable
{
DECLARE_SCRIPTING_TYPE_MINIMAL(SteerControl);
API_AUTO_SERIALIZATION();
/// <summary>
/// The vehicle speed.
/// </summary>
API_FIELD(Attributes = "Limit(0)") float Speed;
/// <summary>
/// The target max steer of the speed.
/// </summary>
API_FIELD(Attributes = "Limit(0, 1)") float Steer;
/// <summary>
/// Create a Steer/Speed relationship structure.
/// </summary>
SteerControl()
{
Speed = 1000;
Steer = 1;
}
/// <summary>
/// Create a Steer/Speed relationship structure.
/// <param name="speed">The vehicle speed.</param>
/// <param name="steer">The target max steer of the speed.</param>
/// </summary>
SteerControl(float speed, float steer)
{
Speed = speed;
Steer = steer;
}
};
/// <summary>
/// Vehicle engine settings.
/// </summary>
@@ -94,42 +133,54 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Wheeled Vehicle\"), ActorTo
/// <summary>
/// Acceleration input sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(10)") float RiseRateAcceleration = 6.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(10)") float RiseRateAcceleration = 6.0f;
/// <summary>
/// Deceleration input sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(11)") float FallRateAcceleration = 10.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(11)") float FallRateAcceleration = 10.0f;
/// <summary>
/// Brake input sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(12)") float RiseRateBrake = 6.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(12)") float RiseRateBrake = 6.0f;
/// <summary>
/// Release brake sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(13)") float FallRateBrake = 10.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(13)") float FallRateBrake = 10.0f;
/// <summary>
/// Brake input sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(14)") float RiseRateHandBrake = 12.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(14)") float RiseRateHandBrake = 12.0f;
/// <summary>
/// Release handbrake sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(15)") float FallRateHandBrake = 12.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(15)") float FallRateHandBrake = 12.0f;
/// <summary>
/// Steer input sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(16)") float RiseRateSteer = 2.5f;
API_FIELD(Attributes="Limit(0), EditorOrder(16)") float RiseRateSteer = 2.5f;
/// <summary>
/// Release steer input sensitive.
/// </summary>
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Inputs\"), EditorOrder(17)") float FallRateSteer = 5.0f;
API_FIELD(Attributes="Limit(0), EditorOrder(17)") float FallRateSteer = 5.0f;
/// <summary>
/// Vehicle control relationship between speed and steer. The higher is the speed,
/// decrease steer to make vehicle more maneuverable (limited only 4 relationships).
/// </summary>
API_FIELD() Array<WheeledVehicle::SteerControl> SteerVsSpeed = Array<WheeledVehicle::SteerControl>
{
SteerControl(800, 1.0f),
SteerControl(1500, 0.7f),
SteerControl(2500, 0.5f),
SteerControl(5000, 0.2f),
};
};
/// <summary>

View File

@@ -1554,9 +1554,7 @@ void PhysicsBackend::EndSimulateScene(void* scene)
leftBrake = 1.0f;
}
// @formatter:off
// Reference: PhysX SDK docs
// TODO: expose input control smoothing data
// Smooth input controls
PxVehiclePadSmoothingData padSmoothing =
{
{
@@ -1591,20 +1589,31 @@ void PhysicsBackend::EndSimulateScene(void* scene)
wheelVehicle->_driveControl.FallRateSteer, // fall rate eANALOG_INPUT_STEER_RIGHT
}
};
// Reference: PhysX SDK docs
// TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range)
static constexpr PxF32 steerVsForwardSpeedData[] =
// Reduce steer by speed to make vehicle more easier to maneuver
constexpr int steerVsSpeedN = 8;
PxF32 steerVsForwardSpeedData[steerVsSpeedN];
const int lastSteerVsSpeedIndex = wheelVehicle->_driveControl.SteerVsSpeed.Count() - 1;
int steerVsSpeedIndex = 0;
// Steer vs speed data structure example:
// array:
// speed, steer
// 1000, 1.0,
// 2000, 0.7,
// 5000, 0.5,
// ..
// fill the steerVsForwardSpeedData with the speed and steer
for (int i = 0; i < 8; i += 2)
{
0.0f, 1.0f,
20.0f, 0.9f,
65.0f, 0.8f,
120.0f, 0.7f,
PX_MAX_F32, PX_MAX_F32,
PX_MAX_F32, PX_MAX_F32,
PX_MAX_F32, PX_MAX_F32,
PX_MAX_F32, PX_MAX_F32,
};
const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4);
steerVsForwardSpeedData[i] = wheelVehicle->_driveControl.SteerVsSpeed[steerVsSpeedIndex].Speed;
steerVsForwardSpeedData[i + 1] = wheelVehicle->_driveControl.SteerVsSpeed[steerVsSpeedIndex].Steer;
steerVsSpeedIndex = Math::Min(steerVsSpeedIndex + 1, lastSteerVsSpeedIndex);
}
const PxFixedSizeLookupTable<steerVsSpeedN> steerVsForwardSpeed(steerVsForwardSpeedData, 4);
// @formatter:on
if (wheelVehicle->UseAnalogSteering)
{