Hello. I have encountered an issue with the TwoWallAdjust function available through the MovementComponent class.
The issue is that in some cases the function results in the Pawn freezing mid air between two walls. Once stuck there’s no way of getting out with the function always returning a Delta of of near 0.
I made a Gif album which demonstrates the problem:
(The gifs can be slow once you load the album. Let them play once and they will play smoothly thereafter)
Pay attention to the Blue numbers. They are the size of the Delta vector that the TwoWallAdjust function returns. I repeat the function 5 times to account for collisions with more than two walls. Notice how in the normal case (The 90 Degree wall) only the first call to the function returns a change in Delta. The 4 other calls after that all return 0.0 meaning the the collision has been solved and the capsule collision slides down the wall normally. In the cases in which the capsule gets stuck, the function keeps returning new Delta Values for every call, which leads me to believe that the new slide angle it finds keep pushing the capsule into the corner, making it appear stuck and floating mid air.
Also, the Red number is the size of the Velocity vector.
Here’s the code for the TwoWallAdjust function:
void UMovementComponent::TwoWallAdjust(FVector& OutDelta, const FHitResult& Hit, const FVector& OldHitNormal) const
{
FVector Delta = OutDelta;
const FVector HitNormal = Hit.Normal;
if ((OldHitNormal | HitNormal) <= 0.f) //90 or less corner, so use cross product for direction
{
const FVector DesiredDir = Delta;
FVector NewDir = (HitNormal ^ OldHitNormal);
NewDir = NewDir.GetSafeNormal();
Delta = (Delta | NewDir) * (1.f - Hit.Time) * NewDir;
if ((DesiredDir | Delta) < 0.f)
{
Delta = -1.f * Delta;
}
}
else //adjust to new wall
{
const FVector DesiredDir = Delta;
Delta = ComputeSlideVector(Delta, 1.f - Hit.Time, HitNormal, Hit);
if ((Delta | DesiredDir) <= 0.f)
{
Delta = FVector::ZeroVector;
}
else if ( FMath::Abs((HitNormal | OldHitNormal) - 1.f) < KINDA_SMALL_NUMBER )
{
// we hit the same wall again even after adjusting to move along it the first time
// nudge away from it (this can happen due to precision issues)
Delta += HitNormal * 0.01f;
}
}
OutDelta = Delta;
}
How Can I fix this issue? I’ve tried looking elsewhere online, but none seems to give a clear answer on how to fix this issue.
I know it has something to do with this part of the function:
if ((OldHitNormal | HitNormal) <= 0.f) //90 or less corner, so use cross product for direction
{
const FVector DesiredDir = Delta;
FVector NewDir = (HitNormal ^ OldHitNormal);
NewDir = NewDir.GetSafeNormal();
Delta = (Delta | NewDir) * (1.f - Hit.Time) * NewDir;
if ((DesiredDir | Delta) < 0.f)
{
Delta = -1.f * Delta;
}
}
It seems to do it’s job most of the time, but there’s something in it that goes wrong. I don’t know enough about trigonometry and vector math to see the issue myself.
Any suggestions or solutions would be much appreciated!
Best Regards
-Headstub