Godot Version
4.3.stable
Question
I have the below GDScript in the Characterbody2D
extends CharacterBody2D
const SPEED = 150.0
const JUMP_VELOCITY = -300.0
const COYOTE_TIME = 0.1 # Coyote time allows jump slightly after leaving a platform
var coyote_time_left = 0.0 # Timer to track how much coyote time remains
var collision_shapes_freed = false # Flag to track if collision shapes are freed
var is_crouching = false # Tracks if the player is crouching
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D
@onready var collision_shape_standing: CollisionShape2D = $CollisionShapeStanding
@onready var collision_shape_crouching: CollisionShape2D = $CollisionShapeCrouching
@onready var raycast_up: RayCast2D = $RayCastUp # Add a RayCast2D pointing upwards
func _ready() â void:
raycast_up.enabled = true # Ensure the raycast is enabled
func _physics_process(delta: float) â void:
# Only interact with collision shapes if they havenât been freed
if not collision_shapes_freed:
# Check if âmove_downâ action is pressed
if Input.is_action_pressed(âmove_downâ):
enter_crouch_state()
# Check if the "move_down" action is released and there's no obstacle above
elif is_crouching and not raycast_up.is_colliding():
exit_crouch_state()
# Add gravity if not on the floor
if not is_on_floor():
velocity += get_gravity() * delta
coyote_time_left -= delta # Countdown coyote time when not on the floor
else:
coyote_time_left = COYOTE_TIME # Reset coyote time when on the ground
# Handle movement and animations
var direction := Input.get_axis("move_left", "move_right")
if direction > 0:
animated_sprite.flip_h = false
elif direction < 0:
animated_sprite.flip_h = true
# Handle jump with coyote time
if Input.is_action_just_pressed("jump") and (is_on_floor() or coyote_time_left > 0):
velocity.y = JUMP_VELOCITY
coyote_time_left = 0.0 # Reset coyote time after jumping
# Play animations based on movement state
if is_on_floor():
if is_crouching:
animated_sprite.play("down")
velocity.x = 0 # Stop horizontal movement while in crouch state
elif direction == 0:
animated_sprite.play("idle")
else:
animated_sprite.play("run")
else:
animated_sprite.play("jump")
# Apply movement
if not is_crouching: # Prevent moving while crouched
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
# Move the player
move_and_slide()
Function to enter the crouch state
func enter_crouch_state() â void:
collision_shape_standing.disabled = true
collision_shape_crouching.disabled = false
set_collision_mask_value(3, false) # Disable collision layer 3
is_crouching = true
Function to exit the crouch state (stand up)
func exit_crouch_state() â void:
collision_shape_standing.disabled = false
collision_shape_crouching.disabled = true
set_collision_mask_value(3, true) # Re-enable collision layer 3
is_crouching = false
A function to be called from the other node to free collision shapes
func free_collision_shapes():
if not collision_shapes_freed:
collision_shape_standing.queue_free()
collision_shape_crouching.queue_free()
collision_shapes_freed = true # Set the flag to true to stop further interaction with freed nodes
It does as I intend, except when exiting the âcrouchâ due to raycasting no longer detecting collision as it causes the player to fall through the platform. This only happens with raycasting, not when âmove_downâ is released successfully by the player.
I tried this:
extends CharacterBody2D
const SPEED = 150.0
const JUMP_VELOCITY = -300.0
const COYOTE_TIME = 0.1 # Coyote time allows jump slightly after leaving a platform
var coyote_time_left = 0.0 # Timer to track how much coyote time remains
var collision_shapes_freed = false # Flag to track if collision shapes are freed
var is_crouching = false # Tracks if the player is crouching
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D
@onready var collision_shape_standing: CollisionShape2D = $CollisionShapeStanding
@onready var collision_shape_crouching: CollisionShape2D = $CollisionShapeCrouching
@onready var raycast_up: RayCast2D = $RayCastUp # Add a RayCast2D pointing upwards
var is_exiting_via_raycast = false # Tracks if weâre exiting crouch via raycast
func _ready() â void:
raycast_up.enabled = true # Ensure the raycast is enabled
func _physics_process(delta: float) â void:
# Only interact with collision shapes if they havenât been freed
if not collision_shapes_freed:
# Check if âmove_downâ action is pressed
if Input.is_action_pressed(âmove_downâ):
enter_crouch_state()
# Check if the "move_down" action is released and there's no obstacle above
elif is_crouching and not raycast_up.is_colliding() and not is_exiting_via_raycast:
exit_crouch_with_delay()
# Add gravity if not on the floor
if not is_on_floor():
velocity += get_gravity() * delta
coyote_time_left -= delta # Countdown coyote time when not on the floor
else:
coyote_time_left = COYOTE_TIME # Reset coyote time when on the ground
# Handle movement and animations
var direction := Input.get_axis("move_left", "move_right")
if direction > 0:
animated_sprite.flip_h = false
elif direction < 0:
animated_sprite.flip_h = true
# Handle jump with coyote time
if Input.is_action_just_pressed("jump") and (is_on_floor() or coyote_time_left > 0):
velocity.y = JUMP_VELOCITY
coyote_time_left = 0.0 # Reset coyote time after jumping
# Play animations based on movement state
if is_on_floor():
if is_crouching:
animated_sprite.play("down")
velocity.x = 0 # Stop horizontal movement while in crouch state
elif direction == 0:
animated_sprite.play("idle")
else:
animated_sprite.play("run")
else:
animated_sprite.play("jump")
# Apply movement
if not is_crouching: # Prevent moving while crouched
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
# Move the player
move_and_slide()
Function to enter the crouch state
func enter_crouch_state() â void:
collision_shape_standing.disabled = true
collision_shape_crouching.disabled = false
set_collision_mask_value(3, false) # Disable collision layer 3
is_crouching = true
Function to exit the crouch state (stand up)
func exit_crouch_state() â void:
collision_shape_standing.disabled = false
collision_shape_crouching.disabled = true
set_collision_mask_value(3, true) # Re-enable collision layer 3
is_crouching = false
is_exiting_via_raycast = false # Reset the raycast exit flag
Function to exit the crouch state after a delay via raycast
func exit_crouch_with_delay() â void:
is_exiting_via_raycast = true # Set flag to prevent multiple calls
await get_tree().create_timer(0.2).timeout # Add a 0.2 second delay (adjust as needed)
exit_crouch_state()
Optional: A function to be called from the other node to free collision shapes
func free_collision_shapes():
if not collision_shapes_freed:
collision_shape_standing.queue_free()
collision_shape_crouching.queue_free()
collision_shapes_freed = true # Set the flag to true to stop further interaction with freed nodes
Which adds a delay to the exit crouch and fixes the issue⌠only now thereâs a delay after every time âmove_downâ is exited, regardless of the reason. Iâve tried everything at my skill level, I really have, to make this work. Either I separate or add flags and the delay doesnât even work or it continues to delay the exit all the time.
Some insight would be greatly appreciated