• Godot Help
  • The correct way to implement character-spikes interaction

I have a player and a few spikes around:

The spike object contains an Area3D object. I connected its "body_entered" signal to a method named "OnEnter" in a script which belongs to the same Area3D object. The signal is received correctly and I can detect it when the player collides with the region of spikes.

I instantiated several of these spikes and they work perfectly. Here is the script of the spikes:

`public partial class Spike01Area : Area3D
{
public override void _Ready()
{
}

public override void _Process(double delta)
{
}

public void OnEnter(Node3D body)
{
	GD.Print("This: " + this.Name);
	GD.Print("Body: " + body.Name);
}

}`

Now I can get a reference to the player object from the scene root and call a method inside the player object to induce some damage to the player or wrap the player to a respawn point. But what happens if a character other than the player falls into the spikes? I want other things like monsters and enemies also be able to receive damage when they touch the spikes.

The "OnEnter" method receives a "body" argument. How can I access to the owner of this "body" object? I want to notify the player or a monster if they fall in the spikes. What is the correct way of doing this interaction?

I tried writing an interface (ICharacter) and add some virtual methods to it, which are to be called when the game object collides with spikes. But it didn't make any sense to me when I started writing it, since it implies that every game object derived from "ICharacter" must be able to fall in the spikes. I don't know, maybe it was the correct way.

I also thought of adding an Area3D object to the player, so that it can detect the spikes through a layer mask and receive the damage notification directly itself. But in this way, every monster must have its own detection system.

What is the best way of implementing this interaction? Can you please share your experiences?

    Ahsalhan The player scene should have an area node that detects spikes and resends the signal to the main player script where the damage calculation ought to be handled.

    Ahsalhan the signal of the area already detects bodies entering. You just need to apply logic. So go into your Inspector, click the Signals tab of your Area, then connect the signal to the script that needs it. Then it's as simple as:

    func _on_Area3D_entered(body):
            if body.name == "Player":
                   ## do something
            if body.name == "Enemy":
                   ## do something else

    Note: Mine is in GDScript and I notice you're in C? You should be able to suss it out though. I BELIEVE IN YOU.

    Both previous suggestions are good. I'll add another two methods to round out your options!

    You can check the body for a method, say take_damage, and if it has this method you call the method. This allows you to implement the take damage functionality however you like for your different objects and allows you to keep that logic with the object in question.

    func _on_area_entered(area):
        if area.has_method("take_damage"):
            area.take_damage(damage)

    https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-method-has-method

    Similar to has_method you could check if the object is in a pre-defined group you've assigned and if so, then apply damage.

    func _on_area_entered(area):
        if area.is_in_group("damage"):
            area.take_damage(damage)

    https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-is-in-group

    Also - be careful about your collision shape size. If you make it too big, (as in larger than the graphic) your spikes will kill people at weird geometries. Go too small and you can "miss" them.