Sending/receiving a custom signal from a raycast

Godot Version

4.3

Question

`So I am messing around trying to make a simple 2d platformer. The player can point around a gun that shoots and kills enemies. I have set up a health system using component nodes that get parented to each enemy. The only missing link here is getting the gun to damage the enemies.

I have a Node2D with a gun script. This gun uses a separate Raycast2D node to shoot. This ray collides with an Area2D node that has a custom health script on it. When the gun hits the Area2D, I want to send a signal that decreases health on the attached health script.

This is the whole gun script, mildly simplified.

using Godot;

public partial class gunscript : Node2D
{

    [Signal] public delegate void SendDamageEventHandler(float somedamage);

    [Export] public RayCast2D myRaycast;
    Vector2 targetPos = Vector2.Zero;

    public override void _PhysicsProcess(double delta)
    {
        targetPos = GetLocalMousePosition();

        Vector2 aimNormal = (targetPos - this.Position).Normalized();

        if (Input.IsActionJustPressed("shoot"))
        {

            myRaycast.TargetPosition = aimNormal * 1000f;
            myRaycast.ForceRaycastUpdate();

            Area2D hit;
            if (myRaycast.IsColliding())
            {
                //!!!PROBLEM HERE!!!
            }
        }

    }
}

The unknown problem starts right when I try to have something happen when the raycast detects a hit. The goal is to take the Area2D I collide with, connect to the Area2D’s “HealthComponent” script, and decrease health by 1.

I have tried looking for several solutions, however I started out using my incompetent C# intuition. I would think it would be possible to do something like in the following two examples, but that’s unfortunately not how things work.

if (myRaycast.IsColliding())
{
    //CS0308 The non-generic method 'RayCast2D.GetCollider()' cannot be used with type arguments
    HealthComponent health = myRaycast.GetCollider<HealthComponent>();
    //do not know what to do afterwards if the above line would have worked
}
Area2D hit;
if (myRaycast.IsColliding())
{
    hit = (Area2D)myRaycast.GetCollider();
    //CS0030 Cannot convert type 'Godot.Area2D' to 'HealthComponent'
    HealthComponent health = (HealthComponent)hit;
    //do not know what to do afterwards if the above line would have worked
}

I have seen plenty of gdscript tutorials giving examples of code that works. These specific examples are impossible for me to translate either due to functional differences or lack of deep C# knowledge. As far as I’m aware, there is no way to directly translate the following example into C#.

area2d hit
if myRaycast.is_colliding():
    hit = myRaycast.get_colliding()
    if hit is HealthComponent:
        var health : HealthComponent = hit
        health.damage(1.0)

A dubious website that claims to be able to translate gdscript to C# gave a result that showed me a kind of solution I didn’t know about. The way it does the second “if” statement seems like it could work, but makes no sense either to me or to the compiler.

Area2D hit;
if (myRaycast.IsColliding())
{
    //CS8121 An expression of type 'Area2D' cannot be handled by a pattern of type 'HealthComponent'.
    if (hit is HealthComponent health)
    {
        health.Damage(1.0f);
    }
}

The most obvious solution to a normal person would be to use a signal, but I feel like I’m missing critical knowledge for this specific scenario. After about an hour of searching, I came across the Connect function to connect signals to each other. I’m not able to intuit how it should work, and I cant understand what the documentation for C# signals is telling me to do. From my understanding, it is incredibly easy to link signals between built-in nodes, but incredibly hard to link custom signals provided by an attached script.

Area2D hit;
if (myRaycast.IsColliding())
{
    //CS0103 The name 'Damage' does not exist in the current context
    hit.Connect(gunscript.SignalName.SendDamage, Callable.From(TakeDamage), (uint)GodotObject.ConnectFlags.OneShot);
    //do not know what to do afterwards if the above line would have worked
}

I cant simply EmitSignal once the raycast detects a hit, since the signals required can’t be connected by hand in the editor. The game is generative, I have no idea when or where what kinds of enemies will be placed around. I am very tired and withered from clawing for solutions. Forums are my last resort here. Any input would be heavily appreciated.
`

I don’t think you needed use signals

IDamageable.cs

public interface IDamageable
{
    void Damage(float damageTaken);
}

Bullet.cs

if (RayCastDown.IsColliding())
				{
					if (RayCastDown.GetCollider() is IDamageable damageable)
                                 {
                                    damageable.Damage(10f)
                                 }

All enemies, and destroyable colliders now can implement IDamageable interface and is going works