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
on my chanel:link text

I tried to create the paragon animation system…

I tried Translating this into BP I failed massively lol maybe you could make a tutorial showing how you did it in c++ :slight_smile: on line 32 I get hugeeeee numbers but that’s using bp I haven’t done it in c++ cause idk but I can read c++ and understand it just a bit.

I think you can do that in BP because i made a prototype of this prediction system in BP. I love to share that but un fortunately Many of my previous projects got deleted or corupted…

And also paragon animation sytem project is not completed yet. There are many bugs thats killing me…
1.Triggers that I used to predict start stop location jump locations works 90% of the time I don’t know why.
2. There is also a bug with jump and spin transaction that crashes the whole editor to crash… :frowning: