From the moment I transitioned into Godot, I always wanted to create a responsive physics driven first person controller. All of the instances that I've seen use a kinematic body and because the game that I'm making relies on a lot of physics based interactions, using a kinematic body results in a lot of awkward and game breaking interactions with rigidbodies. I was hoping such thing would already exist but I haven't seen any. That's why I want to take it upon myself to create a physics driven rigidbody first person controller.
I have already made a proof of concept project with a simple FPS controller. It could be found here:
https://github.com/Leakbang/Rigidbody-FPS-Controller
I already have encountered my first issue and it is with rotating the player body. I am currently rotating the player body (The rigidbody) using player.rotate_y()
and this interferes with the physics simulation. You can download the project from Github and try it. My question is how can I rotate the player around without messing up with the physics calculations. I don't know how it would be possible to rotate the player around while via physics. There is also the problem with responsiveness as the rotation lag would be definitely noticeable when moving the mouse around.
While I plan to use this FPS controller in my own game, I also want to release it freely as a building block for others to use.
Creating a physics based rigidbody FPS controller
You would have to do everything through the physics engine, no manual position or rotation alterations. You can do this by adding an angular force to the object, such as with apply_torque_impulse() or add_torque(). This will work perfectly with physics, but does make it harder to control, since it is not a 1:1 map to the controller. However, with the right values it can be close.
Also, there is stuff you can fake. For example, making the player physics object a capsule (that never rotates) will allow you to change the camera rotation freely with the mouse without messing up the physics. This is probably what most games do.
@cybereality said: You would have to do everything through the physics engine, no manual position or rotation alterations. You can do this by adding an angular force to the object, such as with apply_torque_impulse() or add_torque(). This will work perfectly with physics, but does make it harder to control, since it is not a 1:1 map to the controller. However, with the right values it can be close.
The problem is I have the rigidbody type set to Character and that locks the Rigidbody rotation so add_torque and apply_torque_impulse do not work. If I have it as a normal rigidbody and only lock the X & Z axis, then the player movement gets totally disrupted when its in contact with anything, including the ground.
@cybereality said: Also, there is stuff you can fake. For example, making the player physics object a capsule (that never rotates) will allow you to change the camera rotation freely with the mouse without messing up the physics. This is probably what most games do.
Yeah, I think that is the way to go! However, I'm not sure how to make the movement direction relative to the camera. Here is the movement code:
var fmove : float = 0.0
var smove : float = 0.0
var wishdir : Vector3
func _input(event):
fmove = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
smove = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
func _integrate_forces(state):
state.add_central_force(wishdir.normalized() * 60)
func _process(delta):
wishdir = (global_transform.basis.x * smove + -global_transform.basis.z * fmove).normalized()
I'm using wishdir
to get the direction the player is supposed to move towards. How can I account for the direction of the Camera so that holding forward, always pushes the player in the direction where the camera is looking.
The answer is in this thread: https://godotforums.org/discussion/comment/56795/#Comment_56795
@cybereality said: The answer is in this thread: https://godotforums.org/discussion/comment/56795/#Comment_56795
I tried the solutions posted in that thread but I couldn't make it work on my own. I added this snippet in the camera look script:
func _physics_process(delta):
var forward_vec = Vector3.FORWARD
var basis = get_transform().basis
forward = basis.xform(forward_vec)
And in the movement script I get the forward
variable:
func _process(delta):
forward = $Camera.forward
func _integrate_forces(state):
state.add_central_force(forward * wishdir.normalized() * 60)
Normalizing forward
doesn't help.
I'm a bit puzzled understanding how this works. So wishdir is a normalized Vector3 that shows which input keys the player is holding down. So the output will be like (1,0,0) (holding W) or (0,0,1) (Holding D) but the problem is that multiplying the forward vector with the method you mentioned, would just reduce the speed of the player in one or more directions rather than changing the angle the force is supposed to be applied. And also the X axis of the forward vector could be 0 which means that the player won't be able to move forwards/backwards. Maybe I'm just totally getting it wrong but I would appreciate it if you could elaborate on this.
- Edited
No, forward is already the vector you want to use. So just multiply it by a scale to move forward.
state.add_central_force(forward * 60)
The problem you are having is that you can't multiply by (1,0,0) (for example) because the actual forward can be any combination of x,y,z values, not just x. What you probably need is 2 integers (one for forward back and one for left right) and then do the camera calculation for forward and left. Then in the movement you'd have to do this:
state.add_central_force((forward * forward_input + left * left_input) * 60)
Where left_input would be 1 for left -1 for right or 0 if no button was pressed (same for forward).
@cybereality said: Also, there is stuff you can fake. For example, making the player physics object a capsule (that never rotates) will allow you to change the camera rotation freely with the mouse without messing up the physics. This is probably what most games do.
Seems like often in games, what you see is not what is happening, lol. Developing can feel like doing hacks a lot.
@cybereality said: No, forward is already the vector you want to use. So just multiply it by a scale to move forward.
Yep that did it thank you! It fully works now however, the vector directions are not working as intended :DD
var forward_vec = Vector3.RIGHT
var left_vec = Vector3.BACK
I don't know why the vector directions are like this but it doesn't bother me too much. It's just odd that the directions don't match.
Might be the default rotation on your camera/player.
@cybereality said: Might be the default rotation on your camera/player.
Yeah that's the cause. Well that's pretty weird. Is there anyway to deal with this? We should probably report this as bug.
- Edited
Yeah that's the cause. Well that's pretty weird. Is there anyway to deal with this? We should probably report this as bug.
This is not a bug – it's most likely because you rotated one of the parent nodes somehow, or that your player isn't designed to face Z- (which is the forward direction in Godot).
Yeah, not really a bug. Forward has to be some fixed vector, and negative z seems to be a natural choice. I believe this is the direction objects face by default, but if you imported models from Blender or wherever then you would need to follow the same convention.
@Calinou said:
Yeah that's the cause. Well that's pretty weird. Is there anyway to deal with this? We should probably report this as bug.
This is not a bug – it's most likely because you rotated one of the parent nodes somehow, or that your player isn't designed to face Z- (which is the forward direction in Godot).
I assumed that the directional vectors would be relative to the player, not Global. I am not importing any 3D meshes for now, but this is problematic as the rotation of player object always has to be (0,0,0). I can't have the starting player rotation looking in any other direction.
Also in the meantime, I downloaded nightly builds of Godot 4 (Thank you Calinou for your nightly builds) to try the physics of Godot 4 and see how it works there. I'm honestly surprised how difficult it is to port from Godot 3x to Godot 4. Especially with the coding department as many things have changed and I couldn't find the G4 counterparts of the G3x code.
- Edited
I'm honestly surprised how difficult it is to port from Godot 3x to Godot 4. Especially with the coding department as many things have changed and I couldn't find the G4 counterparts of the G3x code.
Documentating on porting projects from Godot 3 to Godot 4 hasn't been written yet. The documentation is also outdated in many parts, but this is slowly being worked on. (Nonetheless, we don't guarantee that everything will be up-to-date by the time the first 4.0 alpha is released.)
A Godot 3 -> Godot 4 project converter is also being worked on to handle more things than just renamed nodes. Nonetheless, it won't handle the entirely different physics APIs automatically (this is pretty much impossible).