I've been trying to add crouching

Godot Version

GD 4.2.1


I’ve been trying to add Crouch to my FPS controller and this has been driving me insane for almost a month now I really want a simple way to add Crouch I’m not trying to use the animation player or using two different collision shape I just want the option to make the Crouch hold or toggle

Here’s the code

@onready var Head = $Head
@onready var CollisionShape = $CollisionShape3D

#the MAX amount for the player Head/Camera to look either Up or Down most games have this to not let the Head/Camera to loop around the character
@export var _LookUp := deg_to_rad(89)
@export var _LookDown := deg_to_rad(-89)

@export var _MouseSens : float = deg_to_rad(2.85)

@export var CrouchHeight = -0.25
@export var CrouchTransition = 4

# Speed 
var _Speed

# this is the Movement Speed for the player
@export var _SprintMovementSpeed = 6.5
@export var _DefaultMovementSpeed = 4.5
@export var _CrouchMovementSpeed = 2.5

# the is the Lerp Speed you can remove this if you'd like
@export var _LerpSpeed = 8

const _JumpVelocity = 2.5
var _Gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

# allows the player to move in 3D space
var _Direction = Vector3.ZERO

func _ready():
	_Speed = _DefaultMovementSpeed

func _input(event):
	if event.is_action_pressed("Exit"):

func _unhandled_input(event):
		if event is InputEventMouseMotion:
			rotate_y (deg_to_rad(-event.relative.x * _MouseSens))
			Head.rotate_x (deg_to_rad(-event.relative.y * _MouseSens))
			Head.rotation.x = clamp(Head.rotation.x,_LookDown,_LookUp)

func _process(delta):
	if Input.is_action_pressed("Crouch"):
		_Speed = _CrouchMovementSpeed
		if Input.is_action_pressed("Sprint"):
			_Speed = _SprintMovementSpeed
			_Speed = _DefaultMovementSpeed

func _physics_process(delta):
	if not is_on_floor():
		velocity.y -= _Gravity * delta

	# Handle jump.
	if Input.is_action_just_pressed("Jump"):
		velocity.y = _JumpVelocity

	# Handles Movement
	var input_dir = Input.get_vector("MoveLeft", "MoveRight", "MoveForward", "MoveBackward")
	_Direction = lerp(_Direction,(transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized(), delta * _LerpSpeed)
	if _Direction:
		velocity.x = _Direction.x * _Speed
		velocity.z = _Direction.z * _Speed
		velocity.x = move_toward(velocity.x, 0, _Speed)
		velocity.z = move_toward(velocity.z, 0, _Speed)


On the _unhandled_input.

You should check if event.is_action("crouch"):

Then if event.is_pressed(): then move camera down or camera parent down some y amount. Else, assume released, move camera or parent back to zero.

A better solution is the object that is “crouching” handle that input event and do it in a separate script. Although more convenient here.

1 Like

Sorry I don’t really understand what you mean I tried to do what you suggested but it didn’t work