The Re-Inventing the Wheel Thread

Hi, first of all I would like to thank the work you did on the script and everyone contributions.

I have looked over the code in the script and I have found a few errors, the first error I found was in the rotation of the visual wheels, where the rotation keeps being accumulated and it will eventually reach a float limit, when that happens the wheel will ofc stop visually rotating, although that should take quite a while to happen depending on the application and so on.


WheelArray**->SetRelativeRotation(FRotator(CurrentWheelPitch**, CurrentAngle**, 0.0f));

I haven’t fixed this yet but it’s just a question of not doing the rotation in an accumulated fashion.

The second error I found was


FVector DragForce = -Vel * SpeedKPH * AirResistance;

Where there is a multiplication of a cm/s value with a km/h value, now this does not result in any error that affects gameplay, since in the end it’s all being multiplied by another value, but it’s technically incorrect, it should be multiplied by cm/s, or ofc Vel changed to km/h too.

The next error I found was here:


if (!bOnGround[Index]) {PreviousPosition[Index] = SpringPosition;}

This is incorrect because if it was not on the ground it means that previous position was the TraceLength not the current position, in my case I just eliminated the entire if and passed the assignment of previous position to the else



			else {
				bOnGround[Index] = false;
				SpringLengthArray[Index] = TraceLength;
				/*Much Like SpringPosition, PreviousPosition is not the position but the length*/
				PreviousPosition[Index] = TraceLength;
			}


Although I would change the if to be !Hit.bBlockingHit to change the order of things so the code is clearer to read, but that’s a matter of taste. The results of this fix will barely be noticeable since it only happens during the tick where the wheel touches the ground, it is still incorrect.

The next piece of incorrect code I found was this:


FVector TotalForce = Hit.ImpactNormal * FVector::DotProduct(Hit.ImpactNormal, SpringForce * BodyUpVector);

This creates a problem in extreme angles between the car the ground, where the total force that ends up being applied is far lower than it should have been, and for this to be correct it would also mean that the very way in which the traces are made would be incorrect, since the angle in which they are made should at least in a simple model like this represent the way in which the forces are applied.
The correction I believe is this


FVector TotalForce = BodyUpVector * SpringForce;

The next mistake I found is the cause of the car just launching into the air and for it to get a speed boost after flipping over:


float GripMultiplier = FMath::Max(TraceLength/SpringLengthArray[Index], MaxGrip);

That line is incorrect, MaxGrip in this case would actually be MinGrip, since the FMath::Max as it’s name implies chooses the maximum value of the two, so MaxGrip is actually selected only when it’s the bigger value of the two, not when it’s the smallest, to actual get a max limit the function to use is FMath::Min since this one will select the smallest of two values and that means you can always be sure that you will never get a value larger than MaxGrip.
So in short the correct line would be


float GripMultiplier = FMath::Min(TraceLength / SpringLengthArray[Index], MaxGrip);

This change eliminates the car flying and the boosts the car got after rolling over.
There is the same error inside AddDrive, although given the configuration of the default car and the fact the value of AddDrive is clamped this problem doesn’t really show itself there (still needs to be fixed ofc).

Found some minor errors in AddDrive and AddLatGrip where FVector Dir was not being used and BodyLocation being created but not used aswell.

Finally I believe the AntiRoll model is not correctly done, I haven’t done proper testing on it since it was the last part I checked so take it with a grain of salt, but I believe the assignment of AntiRollForceF should take zeroed FVector(0.0f , 0.0f , 0.0f) instead of FVector() since from the quick test I did it would seem FVector() does not assign a 0 value vector, but instead the current position of the object or something (once again didn’t test it properly).
The entire model also seems to be incorrect if the model that I believe inspired it http://forum.unity3d.com/threads/how-to-make-a-physically-real-stable-car-with-wheelcolliders.50643/ is to be believed, the original model doesn’t use forces and does things all around differently.



		float AntiRollForceF = ((SpringLengthArray[0] / TraceLength) - (SpringLengthArray[1] / TraceLength)) * AntiRollFront;
		float AntiRollForceB = ((SpringLengthArray[2] / TraceLength) - (SpringLengthArray[3] / TraceLength)) * AntiRollBack;

		if (bOnGround[0]) {
			SpringForceArray[0] += BodyUpVector * -AntiRollForceF;
			BodyInstance->AddForceAtPosition(SpringForceArray[0], SuspForceLocation[0], false);
		}
		if (bOnGround[1]) {
			SpringForceArray[1] += BodyUpVector * AntiRollForceF;
			BodyInstance->AddForceAtPosition(SpringForceArray[1], SuspForceLocation[1], false);
		}
		//back
		if (bOnGround[2]) {
			SpringForceArray[2] += BodyUpVector * -AntiRollForceB;
			BodyInstance->AddForceAtPosition(SpringForceArray[2], SuspForceLocation[2], false);
		}
		if (bOnGround[3]) {
			SpringForceArray[3] += BodyUpVector * AntiRollForceB;
			BodyInstance->AddForceAtPosition(SpringForceArray[3], SuspForceLocation[3], false);
		}


I believe the code above would be the correct implementation of the other model in UE4, but once again haven’t really tested it properly so could be wrong, and if I am please do correct me on it, also for this to work it requires the “PreviousPosition[Index] = TraceLength;” on else change to have been made.

Thank you.