From a logical point of view, I decided to move the corrective force calculations into the Tank Movement Component instead of the tracks.
This actually makes more sense to me. Use the tank overall right speed, and by that do the same calculation for the complete tank instead. This avoids the “double” code execution on each track, each one just doing half of the corrective force and makes the correction in one single step.
The Code itself is basically the same:
void UTankMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction * ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // so that it ticks in BP as well, not needed in our case, but...
if (sidewaysCorrectionActive) {
// Apply corrective force to whole tank to compensate sideways movement
auto TankRoot = Cast<UStaticMeshComponent>(GetOwner()->GetRootComponent());
auto RightSpeed = FVector::DotProduct(TankRoot->GetRightVector(), TankRoot->GetComponentVelocity());
auto Acceleration = -RightSpeed / DeltaTime * TankRoot->GetRightVector();
// Force = m * a
auto Force = TankRoot->GetMass() * Acceleration;
GEngine->AddOnScreenDebugMessage(4, 2.0f, FColor::Blue, FString::Printf(TEXT("RightSpeed: %f, Correction: %s"), RightSpeed, *Force.ToString()));
TankRoot->AddForce(Force); // Adding force at the tank location itself
}
}
BTW: I made the correction switchable in game using F12 key, that’s where the sidewaysCorrectionActive
parameter comes from.