How to create an area spell

Godot Version

4.2.1

Question

I’m new to Godot. I’m trying to build a basic ARPG. I have character movement, a basic enemy that is a character2D, and the ability to create a circle at a point chosen by mouse click.

The spell is an Area2D. I’ve managed to get the spell’s stats to grab the player’s stats and modify them. The point of confusion has to do with how the enemy takes damage from the spell. I was working under the assumption that I’d use signals to accomplish this. I was getting confused about which object is emitting the signal and which is catching it to do something with and then the specifics of how to do that. I don’t seem to be able to directly use the signal UI in the editor to connect the objects since it seems to only work for children/parents. An explanation of how this should work would be appreciated. Also, it doesn’t seem like the signal carries any other data? So I’m confused about how to pass the spell’s damage to the enemy since neither the enemy nor the spell by default exists in the scene hierarchy until created. Plus there might be multiple spells and multiple enemies to pass and receive info at any given time.

However, when I was looking again at Area2D, I saw functions that get overlapping areas and bodies. This seems like it might work for my purpose since I would just get the reference to things that the spell hit. However, I’m still not sure if the enemy would use this or the spell would use this. Additionally, the documentation says something about the collisions being processed at the same time and to consider using signals, but I don’t really understand why you might want to use this or signals over the other. Which is more appropriate to use and why?

Code:

Spell:

Player:

World/Gameplay:

Enemy:

I’d think your problem is that in your enemy script, you’re trying to connect to a signal from the spell node, but that node doesn’t get instantiated until the player casts the spell, so… Presumably, there is nothing to connect to when the game starts.

You could an autoload as a kind of signal bus. This video has a good explanation and example (and in general is a good video to watch, as it explains many fundamental concepts).

However, I can see that your spell is an Area2D. Try connecting the body_entered signal to a function that looks like this:

func _on_body_entered(body):
    if body.is_in_group("Enemies"):
        body.take_damage(damage)

And then in the Enemy script, add the take_damage method:

func take_damage(damage: int):
    health -= damage

The difference compared to your current code is that:

  • We’re using the body_entered signal instead of area_entered, because your Enemy appears to be a CharacterBody2D, which is a body, not an area
  • We’re calling a function directly on the enemy node rather than using a signal, since we only want to affect the enemies that have entered the spell area, rather than all enemies.
2 Likes

Thanks. I’ll try this out a little later. Just to clarify though, where do I make the on_body_entered function? Is that in the spell itself? Is it fine to connect the signal to the same place it came from? Or am I misunderstanding?

Yes, on the spell itself, and yes, you can absolutely connect a signal to a script on the same node. It’s a very common thing to do.

2 Likes

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