Browse Source

Improved behavior of automatic transmission (#300)

* Ramp up clutch friction in 1st gear too
* Don't accelerate engine while switching gears
* Implemented latency after gear switching to prevent jitter
Jorrit Rouwe 2 years ago
parent
commit
c7adb203de

+ 5 - 2
Jolt/Physics/Vehicle/TrackedVehicleController.cpp

@@ -231,8 +231,11 @@ void TrackedVehicleController::PostCollide(float inDeltaTime, PhysicsSystem &inP
 	}
 	else
 	{
-		// Engine not connected to tracks, update RPM based on engine inertia alone
-		mEngine.UpdateRPM(inDeltaTime, abs(mForwardInput));
+		// In auto transmission mode, don't accelerate the engine when switching gears
+		float forward_input = mTransmission.mMode == ETransmissionMode::Manual? abs(mForwardInput) : 0.0f;
+
+		// Engine not connected to wheels, update RPM based on engine inertia alone
+		mEngine.UpdateRPM(inDeltaTime, forward_input);
 	}
 
 	// Update transmission

+ 40 - 28
Jolt/Physics/Vehicle/VehicleTransmission.cpp

@@ -15,6 +15,7 @@ JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(VehicleTransmissionSettings)
 	JPH_ADD_ATTRIBUTE(VehicleTransmissionSettings, mReverseGearRatios)
 	JPH_ADD_ATTRIBUTE(VehicleTransmissionSettings, mSwitchTime)
 	JPH_ADD_ATTRIBUTE(VehicleTransmissionSettings, mClutchReleaseTime)
+	JPH_ADD_ATTRIBUTE(VehicleTransmissionSettings, mSwitchLatency)
 	JPH_ADD_ATTRIBUTE(VehicleTransmissionSettings, mShiftUpRPM)
 	JPH_ADD_ATTRIBUTE(VehicleTransmissionSettings, mShiftDownRPM)
 }
@@ -26,6 +27,7 @@ void VehicleTransmissionSettings::SaveBinaryState(StreamOut &inStream) const
 	inStream.Write(mReverseGearRatios);
 	inStream.Write(mSwitchTime);
 	inStream.Write(mClutchReleaseTime);
+	inStream.Write(mSwitchLatency);
 	inStream.Write(mShiftUpRPM);
 	inStream.Write(mShiftDownRPM);
 }
@@ -37,6 +39,7 @@ void VehicleTransmissionSettings::RestoreBinaryState(StreamIn &inStream)
 	inStream.Read(mReverseGearRatios);
 	inStream.Read(mSwitchTime);
 	inStream.Read(mClutchReleaseTime);
+	inStream.Read(mSwitchLatency);
 	inStream.Read(mShiftUpRPM);
 	inStream.Read(mShiftDownRPM);
 }
@@ -54,44 +57,48 @@ void VehicleTransmission::Update(float inDeltaTime, float inCurrentRPM, float in
 			// Switch to first gear or reverse depending on input
 			mCurrentGear = inForwardInput > 0.0f? 1 : (inForwardInput < 0.0f? -1 : 0);
 		}
-		else if (inEngineCanApplyTorque && inCurrentRPM > mShiftUpRPM)
+		else if (mGearSwitchLatencyTimeLeft == 0.0f) // If not in the timout after switching gears
 		{
-			if (mCurrentGear < 0)
+			if (inEngineCanApplyTorque && inCurrentRPM > mShiftUpRPM)
 			{
-				// Shift up, reverse
-				if (mCurrentGear > -(int)mReverseGearRatios.size())
-					mCurrentGear--;
+				if (mCurrentGear < 0)
+				{
+					// Shift up, reverse
+					if (mCurrentGear > -(int)mReverseGearRatios.size())
+						mCurrentGear--;
+				}
+				else
+				{
+					// Shift up, forward
+					if (mCurrentGear < (int)mGearRatios.size())
+						mCurrentGear++;
+				}
 			}
-			else
+			else if (inCurrentRPM < mShiftDownRPM)
 			{
-				// Shift up, forward
-				if (mCurrentGear < (int)mGearRatios.size())
-					mCurrentGear++;
-			}
-		}
-		else if (inCurrentRPM < mShiftDownRPM)
-		{
-			if (mCurrentGear < 0)
-			{
-				// Shift down, reverse
-				int max_gear = inForwardInput != 0.0f? -1 : 0;
-				if (mCurrentGear < max_gear)
-					mCurrentGear++;
-			}
-			else
-			{
-				// Shift down, forward
-				int min_gear = inForwardInput != 0.0f? 1 : 0;
-				if (mCurrentGear > min_gear)
-					mCurrentGear--;
+				if (mCurrentGear < 0)
+				{
+					// Shift down, reverse
+					int max_gear = inForwardInput != 0.0f? -1 : 0;
+					if (mCurrentGear < max_gear)
+						mCurrentGear++;
+				}
+				else
+				{
+					// Shift down, forward
+					int min_gear = inForwardInput != 0.0f? 1 : 0;
+					if (mCurrentGear > min_gear)
+						mCurrentGear--;
+				}
 			}
 		}
 
-		if (old_gear != mCurrentGear && old_gear != 0)
+		if (old_gear != mCurrentGear)
 		{
 			// We've shifted gear, start switch countdown
-			mGearSwitchTimeLeft = mSwitchTime;
+			mGearSwitchTimeLeft = old_gear != 0? mSwitchTime : 0.0f;
 			mClutchReleaseTimeLeft = mClutchReleaseTime;
+			mGearSwitchLatencyTimeLeft = mSwitchLatency;
 			mClutchFriction = 0.0f;
 		}
 		else if (mGearSwitchTimeLeft > 0.0f)
@@ -110,6 +117,9 @@ void VehicleTransmission::Update(float inDeltaTime, float inCurrentRPM, float in
 		{
 			// Clutch has full friction
 			mClutchFriction = 1.0f;
+
+			// Count down switch latency
+			mGearSwitchLatencyTimeLeft = max(0.0f, mGearSwitchLatencyTimeLeft - inDeltaTime);
 		}
 	}
 }
@@ -130,6 +140,7 @@ void VehicleTransmission::SaveState(StateRecorder &inStream) const
 	inStream.Write(mClutchFriction);
 	inStream.Write(mGearSwitchTimeLeft);
 	inStream.Write(mClutchReleaseTimeLeft);
+	inStream.Write(mGearSwitchLatencyTimeLeft);
 }
 
 void VehicleTransmission::RestoreState(StateRecorder &inStream)
@@ -138,6 +149,7 @@ void VehicleTransmission::RestoreState(StateRecorder &inStream)
 	inStream.Read(mClutchFriction);
 	inStream.Read(mGearSwitchTimeLeft);
 	inStream.Read(mClutchReleaseTimeLeft);
+	inStream.Read(mGearSwitchLatencyTimeLeft);
 }
 
 JPH_NAMESPACE_END

+ 3 - 1
Jolt/Physics/Vehicle/VehicleTransmission.h

@@ -33,7 +33,8 @@ public:
 	Array<float>			mGearRatios { 2.66f, 1.78f, 1.3f, 1.0f, 0.74f }; ///< Ratio in rotation rate between engine and gear box, first element is 1st gear, 2nd element 2nd gear etc.
 	Array<float>			mReverseGearRatios { -2.90f };				///< Ratio in rotation rate between engine and gear box when driving in reverse
 	float					mSwitchTime = 0.5f;							///< How long it takes to switch gears (s), only used in auto mode
-	float					mClutchReleaseTime = 0.3f;					///< How long it takes to release the clutch (go to full friction)
+	float					mClutchReleaseTime = 0.3f;					///< How long it takes to release the clutch (go to full friction), only used in auto mode
+	float					mSwitchLatency = 0.5f;						///< How long to wait after releasing the clutch before another switch is attempted (s), only used in auto mode
 	float					mShiftUpRPM = 4000.0f;						///< If RPM of engine is bigger then this we will shift a gear up, only used in auto mode
 	float					mShiftDownRPM = 2000.0f;					///< If RPM of engine is smaller then this we will shift a gear down, only used in auto mode
 };
@@ -75,6 +76,7 @@ private:
 	float					mClutchFriction = 1.0f;						///< Value between 0 and 1 indicating how much friction the clutch gives (0 = no friction, 1 = full friction)
 	float					mGearSwitchTimeLeft = 0.0f;					///< When switching gears this will be > 0 and will cause the engine to not provide any torque to the wheels for a short time (used for automatic gear switching only)
 	float					mClutchReleaseTimeLeft = 0.0f;				///< After switching gears this will be > 0 and will cause the clutch friction to go from 0 to 1 (used for automatic gear switching only)
+	float					mGearSwitchLatencyTimeLeft = 0.0f;			///< After releasing the clutch this will be > 0 and will prevent another gear switch (used for automatic gear switching only)
 };
 
 JPH_NAMESPACE_END

+ 4 - 1
Jolt/Physics/Vehicle/WheeledVehicleController.cpp

@@ -249,8 +249,11 @@ void WheeledVehicleController::PostCollide(float inDeltaTime, PhysicsSystem &inP
 	}
 	else
 	{
+		// In auto transmission mode, don't accelerate the engine when switching gears
+		float forward_input = mTransmission.mMode == ETransmissionMode::Manual? abs(mForwardInput) : 0.0f;
+
 		// Engine not connected to wheels, update RPM based on engine inertia alone
-		mEngine.UpdateRPM(inDeltaTime, abs(mForwardInput));
+		mEngine.UpdateRPM(inDeltaTime, forward_input);
 	}
 
 	// Update transmission