Make a hitbox with Area2D hit multiple enemies

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

Hi,
I have a Area2D hitbox set up to emit signals on body enter/exit and use it to hit enemies. The hitbox is always there and I check if there is an enemy inside when performing my hit/attack. It works ok, but it cannot hit multiple enemies, due to keeping track of only one enemy with the body enter/exit.
How do people solve this issue? Should I…

  • make an array that keeps track of all bodys entering/exiting?
  • disable/enable the Area2D, somehow, I tried this unsuccessfully…
  • something else?
  • create a brand new hitbox from code and hit all that enters, destroy box shortly after?

I know that I could animate a box to appear/dissapear to get that effect but I see myself not wanting to fidget around with animation player for each new hitbox as the project grows, I want all the manipulations to be in code.
Thanks.

:bust_in_silhouette: Reply From: timothybrentwood

Assuming hitbox is your Area2D, at the time of the attack do:

 for body in hitbox.get_overlapping_bodies():
     body.apply_damage(amount)

or connect the body_entered signal and damage the bodies as they come in

func _on_Area2D2_body_entered(body: Node) -> void:
    body.apply_damage(amount)

I’m not sure which works best for your game.
obligatory: make sure your collision layers are set up properly

Thanks,
I tried the .get_overlapping_bodies() thing earlier but it did not work satisfactory, seems like that function is not “instant”?
What I ended up doing was having the collision shape in the area2D disabled by default and enabling it when performing the attack. It works perfectly.

func _attack():
attack = true
weaponhitbox.disabled = false
attack_timer = Timer.new()

func _attack_timer(): #runs when timer trigger
attack = false
weaponhitbox.disabled = true

func _on_WeaponHitbox_body_entered(body):
enemy = body
enemy._take_damage(weapon_damage)
enemy = null

jonkbonker | 2021-04-27 17:48

Indeed the get_overlapping_bodies() is not instant, it updates once a physics frame. If you are processing your inputs during _process() you can consider changing them to be processed during _physics_process() instead. The only thing I would change about your code is:

func _on_WeaponHitbox_body_entered(body):
    if body.has_method("_take_damage"):
        body._take_damage(weapon_damage)

This will prevent crashes down the line if you decide to have your weapon interact with say pots or something down the line.

timothybrentwood | 2021-04-28 20:49