problem implementing crouching by changing collision shape size

Using Godot 4.3 stable (steam)

I am writing a fps character controller and I want to implement crouching by changing the size of the CollisionShape3D. When standing, I have the Camera3D and a Raycast3D on top of the collision shape. However, when crouching, the collision shape changes size but the camera and collision shape don’t move to match the change in size. I’ve included screenshots to illustrate - I moved the camera outside of the collider so I could see what was happening, because the character was clipping through walls it shouldn’t have.

My questions are 1) why is this happening and 2) how can I fix this? I’ve tried adding the camera and raycast as children of the collider but the effect is still the same.


If it helps here is the relevant code - it literally just lerps the shape size:

if Input.is_action_just_pressed("crouch"):
		is_crouching =! is_crouching
	
	if is_crouching:
		current_speed = crouch_speed
		player_collider.shape.height=lerp(player_collider.shape.height,crouching_height,lerp_speed*delta)
	else:
		player_collider.shape.height=lerp(player_collider.shape.height,standing_height,lerp_speed*delta)
		
		if Input.is_action_pressed("sprint"):
			current_speed = sprint_speed
		else:
			current_speed = walk_speed

The position of the camera and the size of the collider are not intrinsically linked:
The camera will move if you move the collider, but if you change the size of the collider it technically does not move.

You can solve your issue by moving the camera in the same way:

if Input.is_action_just_pressed("crouch"):
		is_crouching =! is_crouching
	
	if is_crouching:
		current_speed = crouch_speed
		CAMERA.position.y=lerp(CAMERA.position.y,crouching_height,lerp_speed*delta)
		player_collider.shape.height=lerp(player_collider.shape.height,crouching_height,lerp_speed*delta)
	else:
		CAMERA.position.y=lerp(CAMERA.position.y,standing_height,lerp_speed*delta)
		player_collider.shape.height=lerp(player_collider.shape.height,standing_height,lerp_speed*delta)
		
		if Input.is_action_pressed("sprint"):
			current_speed = sprint_speed
		else:
			current_speed = walk_speed

Depending on where in the tree your camera is, you might have to change the values a little bit: the position.y here will be relative to the camera’s parent.
For example, if the camera is the child of the collider, you want half the height, since the camera will be in the center of the collider at Vector3(0,0,0)


As you can see the transform of the camera says “0,0,0”, even tho the collider is not centered in the scene

1 Like