Timer for damage taken

I want to make the code wait like 2 seconds or smth before damaging the player again.

This is the code I have, but it doesn’t work idk why:

extends CharacterBody2D

signal health_depleted

var health = 100.0
const damage_rate = 10.0
var attacking: bool = false
var damage_cactus := 20.0

func _ready():
	%AnimationPlayer.animation_finished.connect(_on_animation_finished)

func _physics_process(delta):
	var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	if attacking:
		velocity = Vector2.ZERO
	else:
		velocity = direction * 400
	move_and_slide()
	
	if not attacking:
		if velocity.length() > 0.0:
			%Bluwee.play_run()
		else:
			%Bluwee.play_idle()
	
	if Input.is_action_just_pressed("attack") and not attacking:
		attacking = true
		handle_attack_animation()
	
	var overlapping_mobs = %Hurtbox.get_overlapping_bodies()
	if overlapping_mobs.size() > 1:
		health -= damage_cactus * overlapping_mobs.size() * delta
		%ProgressBar.value = health
		%Timer.start(2)
		if health <= 0.0:
			health_depleted.emit()

func handle_attack_animation():
	var mouse_position = get_global_mouse_position()
	var vector_to_mouse = (mouse_position - global_position).normalized()
	var angle_to_mouse = vector_to_mouse.angle()  # Angle in radians
	# Convert angle to degrees for easier comparisons
	var angle_in_degrees = rad_to_deg(angle_to_mouse)
	
	# Adjust for top-down orientation (0 degrees = up)
	if angle_in_degrees < 0:
		angle_in_degrees += 360
	
	# Determine animation based on the angle
	if angle_in_degrees >= 315 or angle_in_degrees < 45:
		%Bluwee.play_attack()  # Mouse is above the player
	elif angle_in_degrees >= 45 and angle_in_degrees < 135:
		%Bluwee.play_down_attack()  # Mouse is to the right of the player
	elif angle_in_degrees >= 225 and angle_in_degrees < 315:
		%Bluwee.play_up_attack()  # Mouse is below the player
	elif angle_in_degrees >= 135 and angle_in_degrees < 225:
		%Bluwee.play_left_attack()  # Placeholder for left attacks if needed

func _on_animation_finished(animation: String):
	# Reset attacking flag when the attack animation is done
	if animation in ["right_attack", "back_attack", "front_attack", "left_attack"]:
		attacking = false
		%WarriorBlue.scale.x = 1
		%Bluwee.play_idle()

In this part of your code, you start the timer and … what? Do you wait for it? No. Do you do anything on timer completed - no. You just start a timer.

Instead you need something like this (pseudo code):

# This will be your flag for taking damage
var can_take_damage: bool = true


# inside your function:
	if overlapping_mobs.size() > 1:
		# can we take damage
		if can_take_damage:
			take_damage()
			can_take_damage = false

func take_damage():
		health -= damage_cactus * overlapping_mobs.size() * delta
		%ProgressBar.value = health
		%Timer.start(2)
		if health <= 0.0:
			health_depleted.emit()

# Use the timers timeout signal to allow taking damage again
func _on_timer_timeout():
	can_take_damage = true

Something like that anyway, I hope this helps in some way.

PS the two IF statements I did separately just for clarity to show you how it works, but you can combine them with an AND into a single IF. You could even drop the variable and just see if the timer is running if you chose instead as well.

1 Like

In short, you have to connect something to the timer’s timeout signal or event.

if you want to wait for a timer, you could write:
await get_tree().create_timer(2.0).timeout
But i think it would not help for the player to get damaged no more than every 2 seconds.

I think I would take a slightly different approach here:

var can_take_damage: bool = true

func _process(delta: float) -> void:
    # some code
    if not can_take_damage:
        return
	if overlapping_mobs.size() > 1:
        can_take_damage = false
		health -= damage_cactus * overlapping_mobs.size() * delta
		%ProgressBar.value = health
		if health <= 0.0:
			health_depleted.emit()
		await get_tree().create_timer(2.0).timeout
        can_take_damage = true
    # some code

With the above approach you won’t check for damage if player received damage within last 2 seconds. After that time, damage can be taken.

The code above may have syntax errors but I tried my best without Godot editor.

I hope this helps you with your problem.

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