Determine where a Character stops

In order to replicate Paragon’s locomotion system I’m required to know where my character will end its movement, I’ve watched all the documentation about this subject (Twitch streams, Laurent Delayent presentation and the Unreal Engine API) but I can’t figure out a way to calculate exactly where the actor stops moving.

My attempt was, knowing that only friction slows down the movement, the following:

float Friction = Character->GetCharacterMovement()->GroundFriction * Character->GetCharacterMovement()->BrakingFrictionFactor;
float WalkingDecelerationSpeed = Character->GetCharacterMovement()->BrakingDecelerationWalking;
FVector StartingLocation = Character->GetActorLocation();
FVector Velocity = Character->GetVelocity();
const FVector RevAccel = -WalkingDecelerationSpeed * Velocity.GetSafeNormal();

FVector StopLocation = StartingLocation + (-(Velocity*Velocity) / (2 * ((-Friction) * Velocity + RevAccel)));

if ((2 * (-Friction) * Velocity.Z + RevAccel.Z) == 0)
{
	StopLocation.Z = StartingLocation.Z;
}

if ((2 * (-Friction) * Velocity.Y + RevAccel.Y) == 0)
{
	StopLocation.Y = StartingLocation.Y;
}

if ((2 * (-Friction) * Velocity.X + RevAccel.X) == 0)
{
	StopLocation.X = StartingLocation.X;
}

return StopLocation;

Not only it has a low precision with default values of the CharaterMovementComponent, but it brakes comepletely if I try to change the value of BrakingDecelerationWalking, probably because I haven’t understood correctly what BrakingDecelerationWalking and GroundFriction purpose are.

So, if anyone knows more about Kinematics in Unreal than I do, I’ll be glad to know more about this two variables usage and how to predict the character stop location

Interesting problem. First, I’m pretty sure all the locomotion stuff from Paragon is going to be included in the next engine version. I think they said that in the stream. We’re supposed to do what we can for now but if you want to try it yourself in the meantime, I can respect that.

You’re probably going to have a hard time getting the prediction to be accurate all the time. You’re calculating it once over the entire deceleration but the engine is handling it in frame-sized time periods. It might be worth trying to update the prediction each tick and then adjust the animation speed accordingly. If the predictions aren’t too far off then the changes in animation speed won’t be noticeable.

As far as the math itself. I obviously don’t have experience with this so if you think the problem is in there then you should post a link to the formula you’re using.

Here’s the code I used in my version it works really great, although you have to set friction to zero

// Small number break loop when velocity is less than this value
float SmallVelocity = 10.f * FMath::Square(Local_WorldDeltaSecond);

 // Current velocity at current frame in unit/frame
 FVector CurrentVelocityInFrame = Velocity * Local_WorldDeltaSecond;

 // Store velocity direction for later use
 FVector CurrentVelocityDirection = Velocity.GetSafeNormal2D();

 // Current deacceleration at current frame in unit/fame^2
 FVector CurrentDeaccelerationInFrame = (CurrentVelocityDirection * BrakingDecelerationWalking) * FMath::Square(Local_WorldDeltaSecond);

 // Calculate number of frames needed to reach zero velocity and gets its int value
 int StopFrameCount = CurrentVelocityInFrame.Size() / CurrentDeaccelerationInFrame.Size();

 // float variable use to store distance to targeted stop location
 float StoppingDistance = 0.0f;

 // Do Stop calculation go through all frames and calculate stop distance in each frame and stack them
 for (int i = 0; i <= StopFrameCount; i++)
 {
     //Update velocity
     CurrentVelocityInFrame -= CurrentDeaccelerationInFrame;

     // if velocity in XY plane is small break loop for safety
     if (CurrentVelocityInFrame.Size2D() <= SmallVelocity)
     {
         break;
     }

     // Calculate distance travel in current frame and add to previous distance
     StoppingDistance += CurrentVelocityInFrame.Size2D();
 }
 
 // return stopping distance from player position in previous frame
 return CharacterLocation + CurrentVelocityDirection * StoppingDistance;