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;