I’d think you’d want the clamp right before the move_and_slide(); you’re potentially adding a bunch of stuff to velocityafter you clamp it.
Also, velocity.normalized() will override your clamp, and probably not do what you want here; if you normalize a vector it makes it be of length 1.0 (unless it’s a zero vector, in which case it’s a math error and what you get really depends on who implemented the normalize).
If you wanted movement to always be 5 unless the player is stationary, you might want something like:
var frame_speed: float = SPEED * delta * 10
if Input.is_action_pressed("S"): velocity += basis.z * frame_speed
if Input.is_action_pressed("W"): velocity -= basis.z * frame_speed
if Input.is_action_pressed("A"): velocity -= basis.x * frame_speed
if Input.is_action_pressed("D"): velocity += basis.x * frame_speed
if is_zero_approx(velocity.length_squared()):
velocity = Vector3.ZERO
else:
velocity = velocity.normalized() * 5.0
The other thing is, you’re using basis.x and basis.z, which is the rotation relative to the node’s parent. Depending on the relationship there, you could get all sorts of weird behavior. You might want to consider calculating the angle based on something explicit, like the world-relative angle of the XZ vector between the camera and the player.
update, it works but im running into some issues, the player cant jump anymore also if you know how I could stop the player when there not pressing anything that would be much appreciated.
Doing these movement calculations once/twice per axis means you will be slightly axis-aligned. There’s a pull request for better acceleration based movement templates.
Here’s what that looks like for a 3D character
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Isolate vertical and horizontal planar movement
var vertical_velocity := velocity.project(up_direction)
var horizontal_velocity := velocity - vertical_velocity
# Handle jump.
if Input.is_action_just_pressed("Jump") and is_on_floor():
vertical_velocity = up_direction * JUMP_FORCE
# Using get_vector for a limited input (no clamp or .normalize() needed)
var input_dir := Input.get_vector("Left", "Right", "Forward", "Backward")
var direction: Vector3 = basis * Vector3(input_dir.x, 0, input_dir.y)
# move_toward is being applied on both axis simultaneously, no accidental axis-alignment
horizontal_velocity = horizontal_velocity.move_toward(direction * SPEED, ACCELERATION * delta)
# Re-combine the movement vectors into velocity
velocity = horizontal_velocity + vertical_velocity
move_and_slide()
You would want to limit the entire vector’s length to 5, but instead you are clamping each axis to ±5, which means the player would move faster at 10u/s if they are diagonal to the world axis.
Using the dedicated .limit_length function avoids this because it takes both axis’ length into account and limits them combined according to pythagoras’ theorem.
velocity = velocity.limit_length(5)
Seems like you tried to fix this by using velocity.normalized() but you must get a warning along the lines of “this statement has no effect” because .normalized() does not apply the normalization instead making a copy. Eitherway best to remove that line as normalization isn’t what you need and would cause much more issues if this line was correct.
Then you are applying acceleration per-axis with each if Input..., again the player will accelerate faster if they are moving diagonally. Better to use Input.get_vector, transform it to a Vector3 matching your player’s direction and using move_toward over the entire vector at once. That’s what this section does: