Connect signal with parameters in godot 4 (c#)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By zen3001
    private void _Ready(){
        SomeButton = GetNode<Button>("SomeButton");
        String Param1 = "Very cool parameter.";    
        SomeButton.Connect(PopupMenu.SignalName.IndexPressed, new Callable(this, nameof(this.CoolMethod)));
    }
    private void CoolMethod(string Param1){ GD.Print(Param1); }

this is the code I have currently to load my game without error.
however I also want the method to be called with ‘Param1’ as the parameter, in gdscript I can just type the function and give what ever parameter directy but I can’t figure out how to use these callables in c# with custom parameters.

:bust_in_silhouette: Reply From: leo1mml

For now, I guess you can use the Callable.bind(params…) method after creating the callable.
egg:

Callable method = new Callable(this, callbackName).bind(new Godot.Collections.Array<Godot.Node> { boss });
timer.Timeout += method;

It seems this method is not ported to C# yet. :confused:

I tried your code but it throws Cannot resolve symbol bind.

Instead, this works for me.

StateMachine.cs

[Signal]
public delegate void CurStateUpdateEventHandler(string stateName);
...
EmitSignal(SignalName.CurStateUpdate, stateName);

StateMachineDebugger.cs

stateMachineNode.CurStateUpdate += stateName => UpdateLabelText(label, stateName);
...
private void UpdateLabelText(Label label, string text)
{
    label.Text = text;
}

doc

nofacer | 2022-10-28 16:48

this one worked for me, but I’ve discovered it’s an undeveloped feature in the beta and apparently is to be fixed on full release of 4

zen3001 | 2022-11-22 18:17

:bust_in_silhouette: Reply From: nofacer

this works for me. C# language features — Godot Engine (latest) documentation in English

StateMachine.cs

[Signal]
public delegate void CurStateUpdateEventHandler(string stateName);
...
EmitSignal(SignalName.CurStateUpdate, stateName);

StateMachineDebugger.cs

stateMachineNode.CurStateUpdate += stateName => UpdateLabelText(label, stateName);
...
private void UpdateLabelText(Label label, string text)
{
    label.Text = text;
}
:bust_in_silhouette: Reply From: suribe

You can also create an Action, which can use any variable or value available in its current scope, and then create a Callable from it. In that way, you can do practically whatever you want without being tied to the limitations of Callable.

private void CoolMethod(string Param1) {
  GD.Print(Param1);
}


private void _Ready() {
    SomeButton = GetNode<Button>("SomeButton");
    String Param1 = "Very cool parameter.";
    Action myAction = () => { CoolMethod(Param1); };
    SomeButton.Connect(PopupMenu.SignalName.IndexPressed, Callable.From(myAction)));
}

Perfect! Thanks a lot!

Kiamo | 2022-12-26 22:17

:bust_in_silhouette: Reply From: Barrrettt

Thanks to the answer above (suribe) I tried it this way and it works.

private Button buStart;

public override void _Ready() {
    buStart = GetNode<Button>("%buPlay");
    buStart.Pressed += () => { onClickStartGame(true, true); };
}

private void onClickStartGame(bool server, bool withPlayer) {
    GD.Print("Oleee!");
}

Hello, I’m doing exactly as your example but I’m getting the error Callable.generics.cs:20 @ void Godot.Callable.<ThrowIfArgCountMismatch>g__ThrowArgCountMismatch|0_0(int, int, string): System.ArgumentException: Invalid argument count for invoking callable. Expected 0 arguments, received 1. (Parameter 'args'), do you know what could be the cause?

my code

 public void Init()
  {
    CardState child = GetNode<CardState>("CardUI");
    void myAction() { OnTransitionRequested(child, child.state); }
    child.Connect(CardState.SignalName.TransitionRequested, Callable.From(myAction));
  }

  public void OnTransitionRequested(CardState child, int state)
  {
    GD.Print("OnTransitionRequested");
  }

 public override void OnGuiInput(InputEvent inputEvent)
  {
    if (inputEvent.IsActionPressed("left_click"))
    {
      int toState = (int)State.CLICKED;
      EmitSignal(CardState.SignalName.TransitionRequested, toState);
    }
  }

Thanks