Hello folks,
I’m trying to utilize the new Custom Gravity Direction feature of the Character Movement Component for Pawns moving around on moving and rotating platforms. I have a platform in my test environment that rolls about X at a constant rate, and the Pawn stands on the center of it. I set the gravity direction for the pawn every frame by the platform. I then orient the pawn such that its up vector matches the -gravity vector, and maintain the pawn’s forward vector (as best as possible). I use the following code:
void AIPBaseCharacter::OrientToGravity()
{
// Compute the desired rotation
FVector DesiredUp = -GetGravityDirection().GetSafeNormal();
FVector CurrentForward = GetActorForwardVector();
FVector AdjustedForward = CurrentForward - FVector::DotProduct(CurrentForward, DesiredUp) * DesiredUp;
AdjustedForward = AdjustedForward.GetSafeNormal();
// Handle edge cases
if (AdjustedForward.IsNearlyZero())
{
AdjustedForward = FVector::CrossProduct(DesiredUp, FVector::RightVector).GetSafeNormal();
if (AdjustedForward.IsNearlyZero())
{
AdjustedForward = FVector::CrossProduct(DesiredUp, FVector::UpVector).GetSafeNormal();
}
}
FQuat DesiredRotation = FRotationMatrix::MakeFromZX(DesiredUp, AdjustedForward).ToQuat();
SetActorRotation(DesiredRotation);
}
The gravity vector is set in the tick of the platform quite simply as:
Pawn->SetGravityDirection(-GetActorUpVector());
This, however, results in an odd drift from side to side as the platform rotates.
A video can be seen here:
[https://www.dropbox.com/s/hvx9eix26bayk12/RotateNoTranslate.mp4?raw=1](Rotating Platform, Rotating Pawn, no translation)
I’ve determined that the problem is due to the pawn’s pivot being in the center of its capsule. This means that if you rotate the pawn, its feet will not remain in the same spot that they were standing on. In an effort to address this problem, I updated the code to compute the feet location, computed a new capsule center position after rotating to keep the feet at the same position, and translated the character there. The new code follows:
void AIPBaseCharacter::OrientToGravity()
{
// 1. Calculate the feet's world position
FVector CurrentActorLocation = GetActorLocation();
DrawDebugSphere(GWorld, CurrentActorLocation, 10.f, 12, FColor::Yellow, false, 0.05f);
float CapsuleHalfHeight = GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
FVector FeetWorldPosition = CurrentActorLocation - GetActorUpVector() * CapsuleHalfHeight;
DrawDebugSphere(GWorld, FeetWorldPosition, 10.f, 12, FColor::Green, false, 0.05f);
// 2. Compute the desired rotation
FVector DesiredUp = -GetGravityDirection().GetSafeNormal();
FVector CurrentForward = GetActorForwardVector();
FVector AdjustedForward = CurrentForward - FVector::DotProduct(CurrentForward, DesiredUp) * DesiredUp;
AdjustedForward = AdjustedForward.GetSafeNormal();
// Handle edge cases
if (AdjustedForward.IsNearlyZero())
{
AdjustedForward = FVector::CrossProduct(DesiredUp, FVector::RightVector).GetSafeNormal();
if (AdjustedForward.IsNearlyZero())
{
AdjustedForward = FVector::CrossProduct(DesiredUp, FVector::UpVector).GetSafeNormal();
}
}
FQuat DesiredRotation = FRotationMatrix::MakeFromZX(DesiredUp, AdjustedForward).ToQuat();
// 3. Determine the new actor location
FVector NewActorLocation = FeetWorldPosition + DesiredUp * CapsuleHalfHeight;
DrawDebugSphere(GWorld, NewActorLocation, 10.f, 12, FColor::Blue, false, 0.05f);
SetActorRotation(DesiredRotation);
SetActorLocation(NewActorLocation, true, &HitResult, ETeleportType::TeleportPhysics);
}
This code, however, still exhibits a drift as shown in the following video:
[https://www.dropbox.com/scl/fi/z8azf1ihoi0ctxutlcpkc/RotateAndTranslate.mp4?rlkey=kxeow7nmgqoxpltbfeigrj0si&raw=1](Rotating platform, rotated and translated pawn)
I tried using a line check to the floor to see if perhaps the foot position calculation wasn’t precise enough, but the result was the same. I also tried ensuring the tick order where the pawn ticked after the platform, so that it would get the updated gravity vector so it wouldn’t be pushed by physics or something, but that didn’t seem to help either. I’m at a bit of a loss on how I would accomplish this, I’m unsure where the interaction is happening that is causing this drift. Interestingly, if I let it run, it keeps moving in that fixed direction to the side, and if I rotate the platform the other way, it will slide the other direction. It doesn’t seem to matter the orientation of the platform.
Any help would be much appreciated!