Having trouble with crouching and sliding on ground!

Godot Version

4.3

Question

I have been having trouble while creating a general character controller. As I tried to implement ground sliding, it didn’t work, and no matter what I tried, the crouch seemed to always be dominant, so I would really apreciate it if you would help me with this one.

here is the player code:

extends CharacterBody3D
#Export Vars
@export var Curent_Speed := 0.0
@export var Jump_Velocity := 4.5
@export var Walking_Speed := 5.0
@export var Crouching_Speed := 2.0
@export var Sprinting_Speed := 8.0
@export var Look_Sens := 0.006
@export var gravity = 12
@export var Lerp_Speed := 10.0
@export var air_lerp_speed = 0.01

#onready vars
@onready var standing_collision: CollisionShape3D = %"Standing Collision"
@onready var crouching_collision: CollisionShape3D = %"Crouching Collision"
@onready var head: Node3D = $head
@onready var eyes: Node3D = $head/eyes
@onready var crouching_collision_check: RayCast3D = $"Crouching Collision/Crouching collision check"

#Non-export vars
var Motion_Dir := Vector3(0,0,0)
var Crouching_Head_Position := Vector3(0, -0.1, 0)
var Standing_Head_Position := Vector3(0, 0.75, 0)

var is_walking = false
var is_sprinting = false
var is_crouching = false
var is_sliding = false

var Sliding_Timer := 0
var Sliding_Timer_Max := 1
var Sliding_Dir := Vector2.ZERO
var Sliding_Speed := 10

func _unhandled_input(event):
	if event is InputEventMouseButton:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	elif Input.is_action_just_pressed("ui_cancel"):
		Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
		
	if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		if event is InputEventMouseMotion:
			self.rotate_y(-event.relative.x * Look_Sens)
			head.rotate_x(-event.relative.y * Look_Sens)
			head.rotation.x = clamp(head.rotation.x, deg_to_rad(-90), deg_to_rad(90))

func handle_ground_physics(delta):
	var Input_Dir = Input.get_vector("Left", "Right", "Forward", "Backward").normalized()
	
	if Input.is_action_pressed("Crouch") or is_sliding == true:
		if is_on_floor():
			Curent_Speed = Crouching_Speed
			head.position.y = lerp(head.position.y, Crouching_Head_Position.y, Lerp_Speed * delta)
			
			standing_collision.disabled = true
			crouching_collision.disabled = false
			
			if is_sprinting  == true and Input_Dir != Vector2.ZERO:
				is_sliding = true
				Sliding_Timer = Sliding_Timer_Max
				Sliding_Dir = Input_Dir
			
			is_crouching = true
			is_walking = false
			is_sprinting = false
		
	elif !crouching_collision_check.is_colliding():
		standing_collision.disabled = false
		crouching_collision.disabled = true
		
		head.position.y = lerp(head.position.y, Standing_Head_Position.y, Lerp_Speed * delta)
	
		if Input.is_action_pressed("Sprint"):
			Curent_Speed = Sprinting_Speed
			
			is_sprinting = true
			is_crouching = false
			is_walking = false
		else:
			Curent_Speed = Walking_Speed
			
			is_sprinting = false
			is_crouching = false
			is_walking = true
		
	if is_sliding == true:
		Sliding_Timer -= delta
		if Sliding_Timer <= 0:
			is_sliding = false
			print("sliding_finished")

	Motion_Dir = lerp(Motion_Dir, (transform.basis * Vector3(Input_Dir.x, 0, Input_Dir.y)).normalized(), Lerp_Speed * delta)
	if not is_on_floor():
		if Input_Dir != Vector2.ZERO:
			Motion_Dir = lerp(Motion_Dir, (transform.basis * Vector3(Input_Dir.x, 0, Input_Dir.y)).normalized(), delta * air_lerp_speed)
	if Motion_Dir:
		velocity.x = Motion_Dir.x * Curent_Speed
		velocity.z = Motion_Dir.z * Curent_Speed

	else:
		velocity.x = move_toward(velocity.x, 0, Curent_Speed)
		velocity.z = move_toward(velocity.z, 0, Curent_Speed)
		
	if is_sliding == true:
		Motion_Dir = (transform.basis * Vector3(Sliding_Dir.x, 0, Sliding_Dir.y)).normalized()
		is_crouching = false
	
	if is_sliding == true:
		velocity.x = Motion_Dir.x * (Sliding_Timer) * Sliding_Speed
		velocity.z = Motion_Dir.z * (Sliding_Timer) * Sliding_Speed
	if is_sliding == true:
		head.rotation.z = lerp(head.rotation.z, -deg_to_rad(7.0), delta * Lerp_Speed)
	else:
		head.rotation.z = lerp(head.rotation.z, -deg_to_rad(0), delta * Lerp_Speed)
	
	if Input.is_action_just_pressed("Jump") and is_on_floor():
		velocity.y = Jump_Velocity
		
	pass

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


func _physics_process(delta):
	
	handle_air_physics(delta)
	
	handle_ground_physics(delta)
	
	move_and_slide()

This code runs while is_sliding is true, even if you’re not pressing Crouch anymore. And you’re setting is_crouching to true in there. (So while you’re sliding, crouching will also be set to true every frame)

	if Input.is_action_pressed("Crouch") or is_sliding == true:
		if is_on_floor():
			Curent_Speed = Crouching_Speed
			head.position.y = lerp(head.position.y, Crouching_Head_Position.y, Lerp_Speed * delta)
			
			standing_collision.disabled = true
			crouching_collision.disabled = false
			
			if is_sprinting  == true and Input_Dir != Vector2.ZERO:
				is_sliding = true
				Sliding_Timer = Sliding_Timer_Max
				Sliding_Dir = Input_Dir
			
			is_crouching = true
			is_walking = false
			is_sprinting = false

Then you set is_sliding to false here when the timer runs out:

if is_sliding == true:
	Sliding_Timer -= delta
	if Sliding_Timer <= 0:
		is_sliding = false
		print("sliding_finished")

Then you want to set is_crouching to false here:

	if is_sliding == true:
		Motion_Dir = (transform.basis * Vector3(Sliding_Dir.x, 0, Sliding_Dir.y)).normalized()
		is_crouching = false

But this code only runs if is_sliding is true, which was already set to false above. So it looks like after you’re done sliding, is_crouching will remain set to true forever.

Not sure if that’s the issue, it’s just something I noticed…