Need help with 2D sprite flickering when input is held

Godot Version

4.2.1

Question

I’m making a simple 2D platformer and I’m using an AnimatedSprite2D for my character. The animation played (walk, run, jump, idle, attack, crouch) depends on the input key(s) and whether or not the player is on the floor and are called in the _physics_process(delta) function.

For some reason, when I hold down crouch (s key) for more than a few seconds, the idle animation plays for about 1 frame, then goes back to crouch. It feels like it should be an easy fix, but I can’t figure out why it’s doing this. I do not have similar issues with run/jump/attack.

Does anyone have any ideas on what the issue might be?? Thanks in advance for your help!

func _physics_process(delta):
	if Input.is_action_pressed("left") and (velocity.x <= 0):
		direction = -1
		animated_sprite_2d.flip_h = true
		$AttackArea/HurtBox.position.x = -46
	if Input.is_action_pressed("right") and (velocity.x >= 0):
		direction = 1
		$AttackArea/HurtBox.position.x = 46
		animated_sprite_2d.flip_h = false
		
	if !attacking:
		if (velocity.x > 1 || velocity.x < -1):
			animated_sprite_2d.animation = "run"
		elif (Input.is_action_pressed("down") and is_on_floor()):
			animated_sprite_2d.animation = "crouch"
		else:
			animated_sprite_2d.animation = "idle"
		
	if Input.is_action_just_pressed("shift") and !attacking:
		print("attacking")
		attack()
	

	
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity * delta
		if not Input.is_action_pressed("down"):
			if !attacking:
				animated_sprite_2d.animation = "jump"
		else: 
			if !attacking:
				animated_sprite_2d.animation = "crouch"
	

	# Handle jump.
	if Input.is_action_just_pressed("jump") and (is_on_floor() or is_on_wall()) and player_jump_count <= 2:
		velocity.y = JUMP_VELOCITY
		player_jump_count += 1
		if player_jump_count >= 2:
			$JumpCountTimer.start()
			
	if is_on_floor_only():
		player_jump_count = 0
	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("left", "right")
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, 50)

	move_and_slide()

I found fixes for the bugs - not perfect, but good enough for my purposes! I’ll share the results in case anyone runs into a similar issue, or has ideas on how to fix this more efficiently.
For the crouch flicker, I updated the !attacking input block to remove the floor requirement for crouch (which ended up being a hilarious movement feature that works really well with the tone of the game).
For the item pickup flicker, I moved the direction input check to the top of the physics process and moved the item container interaction into the physics process. Here is the new physics process:

func _physics_process(delta):
	
	#Input direction and movement/deceleration
	var direction_input = Input.get_axis("left", "right")
	if direction_input:
		velocity.x = direction_input * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, 50)
	
	#Item and container interactions
	for index in get_slide_collision_count():
		#define the body being interacted with
		var collision := get_slide_collision(index)
		var body := collision.get_collider()
		
		if body != null and body.has_method("add_item"):
			body.add_item()
	
	#Sprite and HurtBox direction updates
	if Input.is_action_pressed("left") and (velocity.x <= 0):
		character_flip(-1)
	if Input.is_action_pressed("right") and (velocity.x >= 0):
		character_flip(1)

	#Input handling when not executing an attack
	if !attacking:
		if Input.is_action_just_pressed("shift"):
			attack()
		elif (velocity.x > 1 || velocity.x < -1):
			animated_sprite_2d.animation = "run"
		elif Input.is_action_pressed("down"):
			animated_sprite_2d.animation = "crouch"
		else:
			animated_sprite_2d.animation = "idle"
	
	#Gravity and fall animation
	if not is_on_floor():
		velocity.y += gravity * delta
		if not Input.is_action_pressed("down") and !attacking:
			animated_sprite_2d.animation = "jump"
	
	#Jump input and mechanics
	if Input.is_action_just_pressed("jump"):
		if (is_on_floor() or is_on_wall()) and player_jump_count <= 2:
			velocity.y = JUMP_VELOCITY
			player_jump_count += 1
		elif player_jump_count < 1:
			velocity.y = JUMP_VELOCITY
			player_jump_count += 1
		if player_jump_count >= 2:
			$JumpCountTimer.start()
	if is_on_floor_only():
		player_jump_count = 0
	
	move_and_slide()

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.