I have built my own movement code for my character as I want to make smooth movement. (This project is just a character and a floor/wall for testing).
The code seems to work fine, but I of course need to apply my own drag somehow. I've tried many ideas for this, and tried to read around a lot. But I can't work out if this code I made is frame dependant or not.
I am getting 120fps in Unreal editor for example (and my monitor is 144hz if that affects it), but what if someone played my game and was on 60fps, or another number.
After many hours I came up with the code below, and I did even go on the calculator and try to test with various numbers, but sadly I'm no expert mathematician, I wasn't sure if the figures I got meant it was good or bad.
Anyway, here is the move method, pretty self-documenting. With the drag part at bottom. Does this drag formula apply consistent drag for the character over any frame rate?
void APostie::Move()
{
float DeltaTime = GetWorld()->GetDeltaSeconds();
FHitResult Hit;
CurrentVelocity.X = FMath::Clamp<float>(CurrentVelocity.X + (InputAxisVector.X * WalkForce), -MaxWalkSpeed, MaxWalkSpeed);
CurrentVelocity.Y = FMath::Clamp<float>(CurrentVelocity.Y + (InputAxisVector.Y * WalkForce), -MaxWalkSpeed, MaxWalkSpeed);
FVector ForwardMovement = GetActorForwardVector() * CurrentVelocity.X;
FVector SidewaysMovement = GetActorRightVector() * CurrentVelocity.Y;
FVector Velocity_Localised = ForwardMovement + SidewaysMovement;
float r = 1;
FVector DeltaMovement = Velocity_Localised * (FMath::Pow(r, DeltaTime) - 1.0f) / FMath::Log2(r);
AddControllerYawInput(LookAxisVector.X * LookSpeed);
GetMovementComponent()->MoveUpdatedComponent(Velocity_Localised, GetActorRotation(), true, &Hit);
// Apply drag
CurrentVelocity *= (1 - WalkDrag) * (1 - DeltaTime);
if (CurrentVelocity.IsNearlyZero())
{
CurrentVelocity = FVector::ZeroVector;
}
}
NOTE: WalkDrag is a uproperty set to 0.01f.
Also, I do of course realise I need to clamp the velocity and to handle hits so velocity is set to zero if I hit walls etc. I'm doing that now, but meanwhile still unsure about this drag formula.
UPDATE: I've tried to take on board DMGregory's help. Here is what I came up with:
void APostie::Move()
{
float DeltaTime = GetWorld()->GetDeltaSeconds();
FHitResult Hit;
CurrentVelocity.X = FMath::Clamp<float>(CurrentVelocity.X + (InputAxisVector.X * WalkForce), -MaxWalkSpeed, MaxWalkSpeed);
CurrentVelocity.Y = FMath::Clamp<float>(CurrentVelocity.Y + (InputAxisVector.Y * WalkForce), -MaxWalkSpeed, MaxWalkSpeed);
FVector ForwardMovement = GetActorForwardVector() * CurrentVelocity.X;
FVector SidewaysMovement = GetActorRightVector() * CurrentVelocity.Y;
FVector Velocity_Localised = ForwardMovement + SidewaysMovement;
float r = WalkDrag;
FVector DeltaMovement = Velocity_Localised * (FMath::Pow(r, DeltaTime) - 1.0f) / FMath::Log2(r);
AddControllerYawInput(LookAxisVector.X * LookSpeed);
GetMovementComponent()->MoveUpdatedComponent(DeltaMovement, GetActorRotation(), true, &Hit);
// Apply drag
CurrentVelocity *= FMath::Pow(r, DeltaTime);
}
r
parameter here:r
is the ratio of speed one second later to speed now. Values close to zero make a very aggressive drag to bring the object to a near-stop quickly. Values close to one are a milder/more slippery drag. – DMGregory Feb 05 '20 at 14:24WalkDrag
— you choose a value that seems to give the runtime behaviour you want. – DMGregory Feb 05 '20 at 14:59