# Predict Stop Position of Character ahead in time

Hey there,

I am trying to predict the exact location of where the player would stop once Acceleration is zero, i started looking around the default movement component but i am not sure how to approach this yet. Does anyone know a good way to do it?

i tried doing some simple calculations using ( BrakingDecelerationWalking and GroundFriction ) but nothing comes close to my exact debug line that i draw yet.

You can use the same method CharacterMovementComponent calculating velocity and move updatedcomponent to simulate the move result.
In the code bellow, I used fixed time step, the result is very close (usually less than 5 unreal unit) to the real stop location.

I want to find the extract stop location and pivoting location, but CharacterMovementComponent doesn’t use fixed time to calculate valocity (see UCharacterMovementComponent::GetSimulationTimeStep), it’s update time step is related to current frame’s DeltaTime。

``````bool CalculateStopLocation(
FVector& OutStopLocation,
const FVector& CurrentLocation,
const FVector& Velocity,
const FVector& Acceleration,
float Friction,
float BrakingDeceleration,
const float TimeStep,
const int MaxSimulationIterations /*= 10*/)
{
const float MIN_TICK_TIME = 1e-6;
if (TimeStep < MIN_TICK_TIME)
{
return false;
}
// Apply braking or deceleration
const bool bZeroAcceleration = Acceleration.IsZero();

if ((Acceleration | Velocity) > 0.0f)
{
return false;
}

BrakingDeceleration = FMath::Max(BrakingDeceleration, 0.f);
Friction = FMath::Max(Friction, 0.f);
const bool bZeroFriction = (Friction == 0.f);
const bool bZeroBraking = (BrakingDeceleration == 0.f);

if (bZeroAcceleration && bZeroFriction)
{
return false;
}

FVector LastVelocity = bZeroAcceleration ? Velocity : Velocity.ProjectOnToNormal(Acceleration.GetSafeNormal());
LastVelocity.Z = 0;

FVector LastLocation = CurrentLocation;

int Iterations = 0;
while (Iterations < MaxSimulationIterations)
{
Iterations++;

const FVector OldVel = LastVelocity;

// Only apply braking if there is no acceleration, or we are over our max speed and need to slow down to it.
if (bZeroAcceleration)
{
// subdivide braking to get reasonably consistent results at lower frame rates
// (important for packet loss situations w/ networking)
float RemainingTime = TimeStep;
const float MaxTimeStep = (1.0f / 33.0f);

// Decelerate to brake to a stop
const FVector RevAccel = (bZeroBraking ? FVector::ZeroVector : (-BrakingDeceleration * LastVelocity.GetSafeNormal()));
while (RemainingTime >= MIN_TICK_TIME)
{
// Zero friction uses constant deceleration, so no need for iteration.
const float dt = ((RemainingTime > MaxTimeStep && !bZeroFriction) ? FMath::Min(MaxTimeStep, RemainingTime * 0.5f) : RemainingTime);
RemainingTime -= dt;

// apply friction and braking
LastVelocity = LastVelocity + ((-Friction) * LastVelocity + RevAccel) * dt;

// Don't reverse direction
if ((LastVelocity | OldVel) <= 0.f)
{
LastVelocity = FVector::ZeroVector;
break;
}
}

// Clamp to zero if nearly zero, or if below min threshold and braking.
const float VSizeSq = LastVelocity.SizeSquared();
if (VSizeSq <= 1.f || (!bZeroBraking && VSizeSq <= FMath::Square(10)))
{
LastVelocity = FVector::ZeroVector;
}
}
else
{
FVector TotalAcceleration = Acceleration;
TotalAcceleration.Z = 0;

// Friction affects our ability to change direction. This is only done for input acceleration, not path following.
const FVector AccelDir = TotalAcceleration.GetSafeNormal();
const float VelSize = LastVelocity.Size();
TotalAcceleration += -(LastVelocity - AccelDir * VelSize) * Friction;
// Apply acceleration
LastVelocity += TotalAcceleration * TimeStep;
}

LastLocation += LastVelocity * TimeStep;

// Clamp to zero if nearly zero, or if below min threshold and braking.
const float VSizeSq = LastVelocity.SizeSquared();
if (VSizeSq <= 1.f
|| (LastVelocity | OldVel) <= 0.f)
{
OutStopLocation = LastLocation;
return true;
}
}

return false;
}``````

Has been a while since i messed with this but thank you for the detailed example!

From what i remember, i did something like this too but i was never able to predict the 100% exact position just as you described above.

Your added example looks very interesting and might give me some new ideas on how to approach it.

I am going to experiment with it very soon and see how it goes.

Thanks again.

Hey I tried to predict the stop location, and its very accurate I say, about 0.02 error when stopping

Cool!
Can you share how to do this?

I’m also interested in this as well. I saw your results on YouTube and I must say I’m impressed. The one I built using a simple kinimatic equation is off by around 1 unit. Be really interested in learning how you are getting .02 accuracy

This is the C++ code: and I use:
MaxWalkSpeed = 450.f;
MaxAcceleration = 1600.f;
BrakingDecelerationWalking = 1600.f;
BrakingFrictionFactor = 1.f;
GroundFriction = 0.0f;

and its run on average 60FPS. in editor

// Get and store current world delta seconds for later use
float Local_WorldDeltaSecond = UGameplayStatics::GetWorldDeltaSeconds(this);

``````	// 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;
``````

}

Brilliant! Thanks it works perfectly for me.

If any one interested check this video