Movement script help[

4.4

for reference I am only pressing W, for some reason the player moves strangely like they can only move in 4 angles

also wanted to include this but no its not just because im moving my camera fast

sorry for the short video file size limit, also its not much better when pressing left and right it does basically the same thing


movement code, this only happens when clamp is there (clamp is to limit player speed

What’s going on here and how can i fix it?

What’s local_velocity for? You aren’t using it…

I’d think you’d want the clamp right before the move_and_slide(); you’re potentially adding a bunch of stuff to velocity after 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.

I’m not using local velocity that’s just left over

Fair enough.

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

can you explain in more detail why my character does that?

These lines are a good example of forcing axis-alignment

velocity.x = clampf(velocity.x, -5, 5)
velocity.z = clampf(velocity.z, -5, 5)

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:


Make sure to paste code instead of screenshots

1 Like