how to simulate a DoT effect on entering an Area2D?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By mrblitzpunk

i’m a complete beginner, just started doing this last week so my code is still very rudimentary. currently im doing this in the enemy node:

func _on_hurtbox_body_entered(body): #function to deal damage to player
if body.is_in_group(“player”)

i wanted this code that deals damage to the player to run every frame that they’re in collision and then deal with the damage interval/invincibility frame on the player side. but it doesn’t work since apparently the game only calls this function once,

i even tried:

func _on_hurtbox_body_entered(body): #function to deal damage to player
if body.is_in_group(“player”) and can_deal_damage:
can_deal_damage = false

with this code on the _process function:

if not can_deal_damage:
	await get_tree().create_timer(damage_timer).timeout
	can_deal_damage = true

still doesn’t work. can anyone give me a better (and hopefully still easy to understand) solution?

:bust_in_silhouette: Reply From: malaska

You are correct, the _on_body_entered function will only happen when your player enters. There is also the on body exited signal, and together you can easily use those to track if the player is inside the area or not.

You can have a seperate function that then gets called in the _process and does the damage/timer.

Your code might look something like this:

var player # to store reference to the player
var damage_interval: float = 1.0 # damage interval for DOT effect
var timer: float = 1.0 # to count down damage interval
var damage: float = 2

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
    # Call our DOT function, with delta (time elapsed since last process)


# Perform our DOT effect/timing
func dot( delta ):
    # If we are not tracking the player, do nothing
    if player == null:

    # Decrement timer by delta - this will keep track of time for us
    timer -= delta

    # When timer runs out, damage player and reset timer
    if timer <= 0:
        player.take_damage( damage )
        timer = damage_interval

# Detect player entering damage area
func on_hurt_box_body_entered(body):
    if body.isingroup("player"):
        player = body

# Detect player exiting damage area
func on_hurt_box_body_exited(body):
    # Check if body was the same node as our player
    if body == player:
        # Set player to null - no longer track it
        player = null

thanks for the reply!

for now my current solution was to just enable and disable the enemy hitbox on a set interval with this code

var can_hit = true
func deal_damage():
	if not can_hit:
		Hitbox.set_deferred("disabled", true)
		Hitbox.set_deferred("disabled", false)

func _on_hurtbox_body_entered(body): #function to deal damage to player
	if body.is_in_group("player"):
		can_hit = false
		await get_tree().create_timer(0.5).timeout
		can_hit = true

honestly not sure if this is a good/standard practice, but at the level im at it’s good enough i guess. not sure if i should handle this better by turning the monitoring on or off in the player script instead

mrblitzpunk | 2023-04-27 16:44

Nice! Some may disagree with me, but I say if it works how you expect, than it’s all good :slight_smile: Good job coming up with a solution!

malaska | 2023-04-27 18:32