Momentum for a First Person Controller in Godot 4

Godot Version

Godot 4

Question

My First Person Controller (CharacterBody3D) currently has no momentum at all. By the way, I measure my movement speed in the debug panel (hotkey ~) with velocity.length() and when I get pushed by one of the platforms (see the video), my speed stays at 0 while I’m being pushed, which isn’t how it supposed to be. What would be the best way to add a momentum/inertia feature and measure my current speed at all times?

Demo:
https://youtu.be/sPl-uA7OZ0Y
https://i.imgur.com/f04DgTZ.gif

Source:
https://github.com/CryptoMares/FPS-Player-Controller

Thanks!

From the Godot docs : “Character bodies detect collisions with other bodies when moving, but are not affected by engine physics properties, like gravity or friction. While this means that you have to write some code to create their behavior, it also means you have more precise control over how they move and react.”

This is true for Godot, but also true in other game/physics engines (a Godot CharacterBody would be called a “kinematic” physic body in other engines).

If you want your player to be pushed by a platform and keep its momentum, you should do one of the followings :

  1. Evaluate the expected movement by yourself in your CharacterBody implementation, by handling the collision(s)
    • Check this doc to get the collision(s) : Using CharacterBody2D/3D — Godot Engine (stable) documentation in English
    • If you want to keep relying on move_and_slide, use get_slide_collision_count() and get_slide_collision()
    • :warning: If you want to use move_and_collide(), you will have to handle everything yourself and it’s not always fun (slopes are painful)
    • Either way, you will probably need to know the velocity of the source moving body, to add this velocity to your own CharacterBody : this is going to get tricky starting from here. You could try to do the following :
      1. Convert your moving StaticBodies into “AnimatableBodies”, with sync_to_physics set to true. This will tell Godot to estimate the velocity of the body, even if it is moving by code or animation : AnimatableBody3D — Godot Engine (stable) documentation in English
      2. Check if the body you are colliding with is a Static or AnimatableBody : if it is, get (and add to yourself) the velocity of this body : StaticBody3D — Godot Engine (stable) documentation in English
  2. Re-make your character controller using a RigidBody instead, so that the body would be impacted by physics
    • But you will have to do your player movement entirely by applying forces : for a classic FPS, I think this is unwanted and developers would prefer to control movement directly.

Don’t hesitate to share your progress as you go : if you’re blocked and I get time later, I might try to do it from your source project

2 Likes

I’m pretty much at the stage right now where I’m just following tutorials – total beginner :slight_smile: I’m learning every day though.

But thanks, this is probably the best answer to this question I’ve got so far – it gives me a good direction to move in.

Making it RigidBody is not what I would like to do, because it will just mean that I have to mitigate certain behaviors that come with it automatically. I’m pretty happy with the current Kinematic Controller, except the lack of Momentum, of course.

Don’t hesitate to share your progress as you go : if you’re blocked and I get time later, I might try to do it from your source project

Thanks, I’ll try my best! But if there’s a chance that you will find the time to do it, that would be just amazing – you’ll be a hero.

The GIF is broken for some reason and I can’t edit the post, so here’s the working GIF here.

Thanks for the GIF :slight_smile:
(it was already clear from your first post)

So, I tried using AnimatableBody3D and it seems like the body’s velocity is not exposed publically in GDScript :face_with_diagonal_mouth:
If an engine developer comes by, I would be curious to know why ?..

It’s public in the engine source code, and it’s very probably accessible through GDExtension, but those are the big guns… (EDIT : nevermind, API is the same between GDScript and GDExtension)…

The workaround would be to add a script to the moving bodies, and evaluate the velocity by comparing the previous and current position in a given delta time, within func _physics_process(delta). Then you could get the velocity and use it on your character controller, when there is collision between the character and this moving body.

1 Like

Thanks for the GIF :slight_smile:
(it was already clear from your first post)

I know, I just have a tendency to overexplain things, sorry :man_shrugging: :slightly_smiling_face:

The workaround would be to add a script to the moving bodies, and evaluate the velocity by comparing the previous and current position in a given delta time, within func _physics_process(delta) . Then you could get the velocity and use it on your character controller, when there is collision between the character and this moving body.

Thanks a lot for your advice! I will keep trying & learning.