1

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

}
Krangogram
  • 117
  • 1
  • 11
  • 1
  • 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 05 '20 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 05 '20 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 05 '20 at 14:42
  • 1
    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 05 '20 at 14:59

1 Answers1

1

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 )
Natalo77
  • 679
  • 8
  • 27
  • 1
    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 05 '20 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 05 '20 at 12:55
  • To be fair I do say 'Linear' drag in the question title. Perhaps this is the wrong terminology? What I really want is realistic drag of linear movement (as opposed to rotation/torque (I think in Unity they called it Linear and Angular , which is where i got the linear thing from.). – Krangogram Feb 05 '20 at 13:08
  • i should say believable not realistic – Krangogram Feb 05 '20 at 13:59
  • @DMGregory sorry to keep messaging. But I have been reading your answer in the link. I understand most of the equation but at the risk of sounding mega-stupid, what is 'r' in the code? https://gamedev.stackexchange.com/questions/169558/how-can-i-fix-my-velocity-damping-to-work-with-any-delta-frame-time – Krangogram Feb 05 '20 at 14:14
  • 1
    @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 05 '20 at 15:37
  • thank i will do. seems to work at the moment. Although Im now concerned about how i calculate my velocity vectors too. When i get home Im gonna try to start from scratch to see if I can understand it better with just moving a cube or something – Krangogram Feb 05 '20 at 15:46
  • 1
    @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 06 '20 at 09:10
  • I think so yes. All I really wanted was to be able to keep track of velocity (in order to smoothly slow down etc). In Unity I was able to set the velocity of Rigidbody directly, but it seems in Unreal if I enable 'Physics' on the player , the PlayerMovmentController seems to stop being used – Krangogram Feb 06 '20 at 13:00
  • 1
    @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 06 '20 at 13:20
  • Yesh I agree @Natalo77. I had that thought last night... The whole time I thought there must be more to the Character Controller than I realise, surely it handles velocity etc... I will try to learn more about it. The docs and examples from Unreal are ok but they could be better organised IMHO – Krangogram Feb 06 '20 at 13:57