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;
}
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;
I tried Translating this into BP I failed massively lol maybe you could make a tutorial showing how you did it in c++ 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…
Hey thanks for sharing your code. Unfortunately, I cannot use c++ in my project, so i would like to convert it to blueprint logic. However, I am having a hard time trying to translate your vector bitwise operators in some conditions. In Unreal Blueprints I can only apply bitwise operators on floats… Any Idea how to repace the conditions with a more common approach that would be easy to reconstruct in blueprints?