# How to apply linear drag to a velocity vector?

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);

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);

GetMovementComponent()->MoveUpdatedComponent(DeltaMovement, GetActorRotation(), true, &Hit);

// Apply drag
CurrentVelocity *= FMath::Pow(r, DeltaTime);

}

• You might find this past Q&A on framerate-independent drag useful. – DMGregory Feb 5 at 5:01
• Since this is unrelated to Natalo77's answer, I'll reply to your question about the 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 5 at 14:24
• thank you. I accidentally posted comment in wrong place (I've deleted the old comment now). Appreciate the help here. Still confused, but its a fun kind of confusion :D – Krangogram Feb 5 at 14:26
• well i tried to avoid just straight up asking again. But I simply cannot figure where to start answering with the obvious next question: How can i calculate r lol? (I made small change to my function already so I am going to change in question now for reference) – Krangogram Feb 5 at 14:42
• You don't calculate it, it's a parameter, analogous to your variable WalkDrag — you choose a value that seems to give the runtime behaviour you want. – DMGregory Feb 5 at 14:59

Well I'd say that every time you calculate your velocity, you should add your drag to it.

Framerate independency is hard to achieve in Unreal, given its reliance on ticking components. So long as you use deltaTime every time you're calculating anything, you should be fine.

Force = Mass * Acceleration.

Acceleration = DragForce / ObjectMass

Velocity = InitialVelocity + 1/2(Acceleration * time^2)

FinalVelocity = InitialVelocity + 1/2( (DragForce / ObjectMass) * DT^2 )

• Notice that OP's drag is not a constant force. It depends on the magnitude of velocity: at high velocities it saps more energy, and at low velocities it saps less, always in the same proportion. – DMGregory Feb 5 at 12:33
• should i change all my velocity and drag code to match something like this model? I just want smooth character movement. With that said, my current code seems to work. Also sorry for being stupid, but why add 1/2 (0.5) times the Accel . Also lastly what is the 'time' variable above. I do not understand because if they game had run for 1 minute or 1 hour, the velocity should behave the same. – Krangogram Feb 5 at 12:55
• @Krangogram It appears r is being used as a runge-kutta integration constant. Try giving it a value of 0.5f, like the OP does in their implementation – Natalo77 Feb 5 at 15:37
• @Krangogram I'm actually quite curious as to what you're trying to achieve in the first place when you ask us about this drag. It may be you're going down a complicated route for something very unneeded – Natalo77 Feb 6 at 9:10
• @Krangogram The CMC handles movement fairly well with the tweakable properties it has. I think the question you really need to be asking is how to tweak this movement component to how you want it to feel. – Natalo77 Feb 6 at 13:20