Godot Version
godot 4
Question
I have a fairly simple rigidbody character controller in godot (I’m using rigidbody rather than characterbody for more flexibility in physics) but right now, when the player jumps, they don’t come back down, but they just keep flying higher, and I’m not sure why.
extends RigidBody3D
var curMaxSpeed = 3
@export var walkSpeed = 3
@export var crouchSpeed = 1
@export var sprintSpeed = 6
@export var jumpForce = 10
@export var SENSITIVITY = 3
@export var jumpTimerMax = 50
var jumpTimer = 50
var crouch = false
@onready var camera = $Head/Camera3D
@onready var head = $Head
@onready var floorCheck = $FloorCheck
# Called when the node enters the scene tree for the first time.
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
var clampVelocity = Vector3(curMaxSpeed * 0.01, 10000, curMaxSpeed * 0.01)
set_linear_velocity(linear_velocity.clamp(Vector3.ZERO, clampVelocity))
_sprint()
_move()
_jump()
func _move():
var move_dir_Y = Input.get_axis("North","South")
var move_dir_X = Input.get_axis("West","East")
apply_central_force(head.basis * (Vector3(move_dir_X, 0, move_dir_Y) * curMaxSpeed * 10))
func _sprint():
if Input.is_action_pressed("Sprint"):
curMaxSpeed = sprintSpeed
else:
curMaxSpeed = walkSpeed
###the issue?
func _jump():
if Input.is_action_just_pressed("Jump"):
print("jump")
linear_velocity.y += jumpForce
jumpTimer = jumpTimerMax
func _unhandled_input(event):
if event is InputEventMouseMotion:
head.rotate_y(-event.relative.x * SENSITIVITY *.001)
camera.rotate_x(-event.relative.y * SENSITIVITY * .001)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-89), deg_to_rad(90))
Fixed it!
I wasn’t doing gravity correctly in the script, but it works pretty well now.
extends RigidBody3D
var curMaxSpeed = 3
@export var walkSpeed = 3
@export var crouchSpeed = 1
@export var sprintSpeed = 6
@export var jumpForce = 10
@export var SENSITIVITY = 3
@export var jumpTimerMax = 50
var jumpTimer = 50
var crouch = false
@onready var camera = $Head/Camera3D
@onready var head = $Head
@onready var floorCheck = $FloorCheck
# Called when the node enters the scene tree for the first time.
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
jumpTimer -= 1
if jumpTimer<= 0 && floorCheck.is_colliding() == false:
linear_velocity.y -= 9.8 * delta
var clampVelocity = Vector3(curMaxSpeed * 0.01, 10000, curMaxSpeed * 0.01)
set_linear_velocity(linear_velocity.clamp(Vector3(0,-10000,0), clampVelocity))
_sprint()
_move()
_jump()
func _move():
var move_dir_Y = Input.get_axis("North","South")
var move_dir_X = Input.get_axis("West","East")
apply_central_force(head.basis * (Vector3(move_dir_X, 0, move_dir_Y) * curMaxSpeed * 10))
func _sprint():
if Input.is_action_pressed("Sprint"):
curMaxSpeed = sprintSpeed
else:
curMaxSpeed = walkSpeed
func _jump():
if Input.is_action_just_pressed("Jump"):
print("jump")
linear_velocity.y = jumpForce
jumpTimer = jumpTimerMax
func _unhandled_input(event):
if event is InputEventMouseMotion:
head.rotate_y(-event.relative.x * SENSITIVITY *.001)
camera.rotate_x(-event.relative.y * SENSITIVITY * .001)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-89), deg_to_rad(90))
works pretty well now, actually. If anyone needs to use this for whatever, feel free. just put it on a rigidbody set up like this:
rigidbody
-collisionshape3d
-Head(node3d)
— -Camera3d
-Raycast3D(floorcheck. place this facing down just below your collider
I wanted to point out the following from the docs, as I think you may run into problems in the future even if it appears to be working OK for now.
Note: Changing the 3D transform or linear_velocity of a RigidBody3D very often may lead to some unpredictable behaviors. If you need to directly affect the body, prefer _integrate_forces as it allows you to directly access the physics state.
The body’s linear velocity in units per second. Can be used sporadically, but don’t set this every frame, because physics may run in another thread and runs at a different granularity. Use _integrate_forces as your process loop for precise control of the body state.
1 Like
I’ve never really had to use that in the past, what would be the best way to implement it in your opinion for this
Edit: I just tried adding a physics box to the scene for the player to push around and… yeah, thats pretty bad
Sorry I don’t know the best approach, but I’d assume you could call most of your code in _integrate_forces instead of _process
.
At the very least I’d switch to using _physics_process
instead of _process
, as that should work better.
Edit: The docs include a basic example of using _integrate_forces
Using RigidBody — Godot Engine (stable) documentation in English
Excelent, thanks
edit: it seems moving everything to physics process works miles better, I always forget thats there. thanks so much
1 Like