reckfellENGINE

C# signals: parameters and lifetime

Declare a custom signal, pass a value and manage subscription lifetime.

On this page

A custom signal

Save this as Health.cs and attach it to an ordinary entity:

C#
using Reckfell;

public partial class Health : Entity
{
    [Signal]
    public delegate void HealthChangedEventHandler(int remaining);

    public int Remaining { get; private set; } = 100;

    public void Damage(int amount)
    {
        if (amount <= 0 || Remaining == 0)
            return;

        Remaining = System.Math.Max(0, Remaining - amount);
        EmitSignal(SignalName.HealthChanged, Remaining);
    }
}

Apply [Signal] to a public delegate whose name ends with EventHandler. The generator creates the HealthChanged event and SignalName.HealthChanged. Parameters must be supported by Variant. Build the project so generated members appear in the IDE and editor.

Damage(25) reduces health from 100 to 75 and emits one event. Zero and negative damage do nothing. After death, further damage does not repeat the same zero-valued event. EmitSignal() emits the engine signal; do not invoke it as HealthChanged?.Invoke(...) here.

A listener with explicit disconnection

Save HealthListener.cs, attach it to another entity and assign Source to the object carrying Health. Assign the source before running or before AddChild() in code:

C#
using Reckfell;

public partial class HealthListener : Entity
{
    [Export] public Health? Source { get; set; }
    private Health? _subscribed;
    public int LastHealth { get; private set; }

    public override void _EnterTree()
    {
        if (!ReckfellObject.IsInstanceValid(Source))
            return;

        _subscribed = Source;
        _subscribed!.HealthChanged += OnHealthChanged;
        OnHealthChanged(_subscribed.Remaining);
    }

    public override void _ExitTree()
    {
        if (ReckfellObject.IsInstanceValid(_subscribed))
            _subscribed!.HealthChanged -= OnHealthChanged;
        _subscribed = null;
    }

    private void OnHealthChanged(int remaining)
    {
        LastHealth = remaining;
        ReckfellApi.Print("Health: ", remaining);
    }
}

The listener immediately reads current state: previous events are not replayed. Leaving the tree removes the subscription. Reentering creates one subscription instead of accumulating handlers. This example does not switch sources at runtime; implement explicit old-source disconnection and new-source connection if you change Source while active.

Do not assume automatic cleanup covers all C# delegates. Custom signals and lambdas capturing variables need lifetime management. To unsubscribe a lambda, keep the same delegate instance; a new lambda with identical text does not remove the original subscription.

Awaiting one signal

Place this method inside an entity script, with using Reckfell; and the Health class above:

C#
public async System.Threading.Tasks.Task WaitForNextDamage(Health health)
{
    Variant[] values = await ToSignal(health, Health.SignalName.HealthChanged);
    ReckfellApi.Print(values[0].AsInt32());
}

It completes on the next emission after awaiting starts. ToSignal() itself supplies neither a timeout nor cancellation. If the sender is freed before emitting, continuation is not guaranteed; design cancellation for long-lived operations and validate objects after await.

For OneShot or Deferred, use Connect() with a Callable and ReckfellObject.ConnectFlags, checking the returned Error. Subscribing with += does not pass these flags. See ReckfellObject and signal basics.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.