how to use area2d as Attack Range in act 2d game like hollow knight

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

I want to make a game like hollow knight. When i used area2d to check other collisions, i found that i couldn’t get result immediately when i use the method get_overlapping_bodies().

the Document recommend me to use signal like Enter() or Exit(). But sometime when i want to hit the enemies, they are already in the area2d, signal Enter can’t give me the right answer too.

I want just want to make sure if other bodies are closed enough with my player. and hit them in custom frame(I call my method in AnimationPlayer to make sure it can get right result with animation)

so how to use area2d or another node in godot to be the attack area in 2d act game?
is there have any example projects to learn?

Thank you very much

Are you using a Rigidbody, a KinematicBody2D or just a plain Area2D node? In RigidBodies you can enable a etting called Continuous cd which gives you more precise collisions. A KinematicBody2D has another option called Sync to Physics under the Motion tab. But it says that it is not wise to use it with move_and_slide().

You could also check this if everything else fails. Is this helpful at all?

johnygames | 2020-02-26 10:05

I had what I think is a similar problem to you. My attack Area2D wouldn’t update it’s actual collision detection until the next frame, so there was a single frame delay any time I changed its rotation. What I did instead of using an Area2D was construct an outline of the attack shape using Raycasts instead, because you can call the function force_raycast_update() to make sure that they have the same frame collision data. That might be something to explore.

denxi | 2020-02-26 14:58

:bust_in_silhouette: Reply From: Mark C

The RayCast2D answer is probably the nicest one so far (including my own).

The problem you’re having using Area2D is trying to check at the time of the attack you’re producing.

The best way if you want to stick with an Area2D is to use signals, but not for a realtime check, rather to add them to an array of “hit-able” targets when they enter, and remove them when they exit.

When you attack, your attack function automatically hits all of the targets within the array (all of them the game have told you have come within the area you can hit, and haven;t left it yet).

You’d use something like the following to get the targets your attack would affect into the array. How you implement the damage is totally separate, so I’ll leave that out.

# your array
var targetsInHitbox

func _on_Area2D_body_entered(body):
   # add the newly entered body to the array
   targetsInHitbox.append(body)

func _on_Area2D_body_exited(body):
   # remove works on the number of element you give it
   # so you need to use the find function inside it to get 
   # the right number to remove
   targetsInHitbox.remove(targetsInHitbox.find(body))
   

Note if you’ve renamed your Area2D, then the “Area2D” part of the func will change to match your naming. If you connect in the editor (which you should), then the func creation and naming will be taken care of for you.

When your player attacks, you’ll then want to use a for loop to iterate through the array, and perform your attack on each.

Apologies if the GDScript isn’t perfect, I use NativeScript/C++ for my Godot scripting… The approach is sound though.

thank you for your answer!
I have tried Raycast2D before.But It just could give me the first collision.
I also ask my friend the same question.
they told me that i could use shape.disabled.
I set shape.disabled equals false when it ready. Before My attack frame, I set that with true. The area2d can trigger then enter event again.

DCaptain | 2020-02-28 02:14

Nice - interesting approach.

With RayCast2D, it does only show the first collision, but you can add exclusions to what it will report colliding against.

So you’d run the RayCast2D multiple times in the single physics process run while there is still a collision. When you get a collision, return the object, do what you want to it, then add that object to the exceptions list and run the same raycast again.

This is the same technique you’d use for piercing projectiles (you could even set it to have a max number of runs so you can choose how many targets your “shot”/ray would go through before stopping)

Remember to only run RayCast2D in physics process, that’s where RayCast2D is reliable according to the docs.

Relevant functions:

is_colliding() - a boolean that returns true while there is still an object being hit by the ray
get_collider() - gives the relevant object to you to do what you want with it
add_exception(object) - add the collided object to this exception list so the ray ignores it on the next “cast”

Iterate using the above.

Mark C | 2020-02-28 11:38