Need Help Fixing Sprinting and Jumping at the same time.

Godot Version

4.4

Question

How do I fix my code so I can sprint and jump at the same time?

Here is my current code:
extends CharacterBody3D

Player Nodes

@onready var nek = $nek
@onready var head = $nek/head
@onready var eyes = $nek/head/eyes

@onready var standing_collision_shape = $standing_collision_shape
@onready var crouching_collision_shape = $crouching_collision_shape
@onready var ray_cast_3d = $RayCast3D
@onready var camera_3d = $nek/head/eyes/Camera3D

Speed Vars

var current_speed = 5.0

const walking_speed = 5.0
const sprinting_speed = 8.0
const crouching_speed = 3.0

States

var walking = false
var sprinting = false
var crouching = false
var free_looking = false
var sliding = false

Slide Vars

var slide_timer = 0.0
var slide_timer_max = 1.0
var slide_vector = Vector2.ZERO
var slide_speed = 10.0

Head bobbing vars

const head_bobbing_sprinting_speed = 22.0
const head_bobbing_walking_speed = 14.0
const head_bobbing_crouching_speed = 10.0

const head_bobbing_sprinting_intensity = 0.2
const head_bobbing_walking_intensity = 0.1
const head_bobbing_crouching_intensity = 0.05

var head_bobbing_vector = Vector2.ZERO
var head_bobbing_index = 0.0
var head_bobbing_current_intensity = 0.0

Movement Vars

var crouching_depth = -0.2

const jump_velocity = 4.5

var lerp_speed = 10.0
var air_lerp_speed = 3.0

var free_look_tilt_amount = 3

Input Vars

var direction = Vector3.ZERO
const mouse_sens = 0.125

Get the gravity from the project settings to be synced with RigidBody nodes

var gravity = ProjectSettings.get_setting(“physics/3d/default_gravity”)

func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _input(event):

Mouse Movement

if event is InputEventMouseMotion:
	if free_looking:
		nek.rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
		nek.rotation.y = clamp(nek.rotation.y, deg_to_rad(-120), deg_to_rad(120))
	else:
		rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
	head.rotate_x(deg_to_rad(-event.relative.y * mouse_sens))
	head.rotation.x = clamp(head.rotation.x, deg_to_rad(-89), deg_to_rad(89))

func _physics_process(delta):

Getting Movement Input

var input_dir = Input.get_vector("left", "right", "forward", "backward")

Handle Movement State

Crouching

if Input.is_action_pressed("crouch") || sliding:

	current_speed = lerp(current_speed,crouching_speed,delta*lerp_speed)
	head.position.y = lerp(head.position.y, crouching_depth, delta * lerp_speed)

	standing_collision_shape.disabled = true
	crouching_collision_shape.disabled = false

Slide Begin Logic

	if sprinting and input_dir != Vector2.ZERO and is_on_floor() and not sliding:
		sliding = true
		slide_timer = slide_timer_max
		slide_vector = input_dir
		#free_looking = true 
		free_looking = true

	walking = false
	sprinting = false
	crouching = true

elif !ray_cast_3d.is_colliding() and not Input.is_action_pressed("crouch") and not sliding:

# Standing

	standing_collision_shape.disabled = false
	crouching_collision_shape.disabled = true

	head.position.y = lerp(head.position.y, 0.0, delta * lerp_speed)

	if Input.is_action_pressed("sprint"):
		# Sprinting
		current_speed = lerp(current_speed,sprinting_speed,delta*lerp_speed)

		walking = false
		sprinting = true
		crouching = false
	else:
		# Walking
		current_speed = lerp(current_speed,walking_speed,delta*lerp_speed)

		walking = true
		sprinting = false
		crouching = false


# Handle Free Look
if Input.is_action_pressed("free_look") || sliding:
	free_looking = true

	if sliding:
		camera_3d.rotation.z = lerp(camera_3d.rotation.z, -deg_to_rad(7.0),delta*lerp_speed)
	else:
		camera_3d.rotation.z = -deg_to_rad(nek.rotation.y*free_look_tilt_amount)
else:
	free_looking = false
	nek.rotation.y = lerp(nek.rotation.y, 0.0, delta * lerp_speed)
	camera_3d.rotation.z = lerp(camera_3d.rotation.z, 0.0, delta * lerp_speed)

Handle sliding

if sliding:
	slide_timer -= delta
	if slide_timer <= 0:
		sliding = false
		free_looking = false

Handle Headbob

if sprinting:
	head_bobbing_current_intensity = head_bobbing_sprinting_intensity
	head_bobbing_index += head_bobbing_sprinting_speed * delta
elif walking:
	head_bobbing_current_intensity = head_bobbing_walking_intensity
	head_bobbing_index += head_bobbing_walking_speed * delta
elif crouching:
	head_bobbing_current_intensity = head_bobbing_crouching_intensity
	head_bobbing_index += head_bobbing_crouching_speed * delta

if is_on_floor() and not sliding and input_dir != Vector2.ZERO:
	head_bobbing_vector.y = sin(head_bobbing_index)
	head_bobbing_vector.x = sin(head_bobbing_index / 2) * 0.5

	eyes.position.y = lerp(eyes.position.y, head_bobbing_vector.y * (head_bobbing_current_intensity / 2.0), delta * lerp_speed)
	eyes.position.x = lerp(eyes.position.x, head_bobbing_vector.x * head_bobbing_current_intensity, delta * lerp_speed)
else:
	eyes.position.y = lerp(eyes.position.y, 0.0, delta * lerp_speed)
	eyes.position.x = lerp(eyes.position.x, 0.0, delta * lerp_speed)

Add the gravity

if not is_on_floor():
	velocity.y -= gravity * delta

Handle Jump

if Input.is_action_just_pressed("ui_accept") and is_on_floor():
	velocity.y = jump_velocity
	sliding = false

Get the input direction and handle the movement/deceleration

if is_on_floor():
	direction = lerp(direction, (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(), delta * lerp_speed)
else:
	if input_dir != Vector2.ZERO:
		direction = lerp(direction, (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(), delta * air_lerp_speed)

if sliding:
	direction = (transform.basis * Vector3(slide_vector.x, 0, slide_vector.y)).normalized()
	current_speed = (slide_timer + 0.1) * slide_speed

if direction:
	velocity.x = direction.x * current_speed
	velocity.z = direction.z * current_speed	

else:	
	velocity.x = move_toward(velocity.x, 0, current_speed)
	velocity.z = move_toward(velocity.z, 0, current_speed)

move_and_slide()
1 Like

Hey realmooster,

I ran into a similar issue recently — trying to do two similar actions at the same time just didn’t work right. I’m still new to Godot myself, so apologies if I’m missing something, but I think I figured out what’s going on.

The problem seems to be that sprinting only activates while you’re grounded, specifically here:
If is_on_floor()
if Input.is_action_pressed(“sprint”):
current_speed = lerp(current_speed,
sprinting_speed, delta * lerp_speed)
sprinting = true

But as soon as you jump, is_on_floor() becomes false, then that block stops running, and it resets sprinting = false. So mid-jump, your sprint just dies out.

How I would try to fix it I think?

I would try to move the sprinting = true/false logic to only run when I’m on the floor. Then, during the rest of the movement code, I just use the current sprinting value — I don’t reset it in the air.

So like:

Only update sprinting state if grounded

if is_on_floor():
if Input.is_action_pressed(“sprint”):
sprinting = true
else:
sprinting = false

Use the sprinting state for current speed regardless of grounded or not

if sprinting:
current_speed = lerp(current_speed, sprinting_speed, delta * lerp_speed)
elif input_dir != Vector2.ZERO:
current_speed = lerp(current_speed, walking_speed, delta * lerp_speed)
else:

# Maybe decelerate or set to 0, up to you

That way, if you were sprinting when you jump, you keep that speed in the air, and everything feels way smoother?

Again, I’m still learning too, so if anyone sees a better way to handle this, I’d love to learn more!

Hope that helps!