123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- .. _doc_c_sharp_signals:
- C# signals
- ==========
- For a detailed explanation of signals in general, see the :ref:`doc_signals` section in the step
- by step tutorial.
- Signals are implemented using C# events, the idiomatic way to represent
- :ref:`the observer pattern<doc_key_concepts_signals>` in C#. This is the
- recommended way to use signals in C# and the focus of this page.
- In some cases it's necessary to use the older
- :ref:`Connect()<class_object_method_connect>` and
- :ref:`Disconnect()<class_object_method_disconnect>` APIs.
- See :ref:`using_connect_and_disconnect` for more details.
- Signals as C# events
- --------------------
- To provide more type-safety, Godot signals are also all available through `events <https://learn.microsoft.com/en-us/dotnet/csharp/events-overview>`_.
- You can handle these events, as any other event, with the ``+=`` and ``-=`` operators.
- .. code-block:: csharp
- Timer myTimer = GetNode<Timer>("Timer");
- myTimer.Timeout += () => GD.Print("Timeout!");
- In addition, you can always access signal names associated with a node type through its nested
- ``SignalName`` class. This is useful when, for example, you want to await on a signal (see :ref:`doc_c_sharp_differences_await`).
- .. code-block:: csharp
- await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
- .. warning::
- While all engine signals connected as events are automatically disconnected when nodes are freed, custom
- signals connected using ``+=`` aren't. Meaning that: you will need to manually disconnect (using ``-=``)
- all the custom signals you connected as C# events (using ``+=``).
- An alternative to manually disconnecting using ``-=`` is to
- :ref:`use Connect <using_connect_and_disconnect>` rather than ``+=``.
- See `Godot issue #70414 <https://github.com/godotengine/godot/issues/70414>`_.
- Custom signals as C# events
- ---------------------------
- To declare a custom event in your C# script, use the ``[Signal]`` attribute on a public delegate type.
- Note that the name of this delegate needs to end with ``EventHandler``.
- .. code-block:: csharp
- [Signal]
- public delegate void MySignalEventHandler();
- [Signal]
- public delegate void MySignalWithArgumentEventHandler(string myString);
- Once this is done, Godot will create the appropriate events automatically behind the scenes. You
- can then use said events as you'd do for any other Godot signal. Note that events are named using
- your delegate's name minus the final ``EventHandler`` part.
- .. code-block:: csharp
- public override void _Ready()
- {
- MySignal += () => GD.Print("Hello!");
- MySignalWithArgument += SayHelloTo;
- }
- private void SayHelloTo(string name)
- {
- GD.Print($"Hello {name}!");
- }
- .. warning::
- If you want to connect to these signals in the editor, you will need to (re)build the project
- to see them appear.
- You can click the **Build** button in the upper-right corner of the editor to do so.
- Signal emission
- ---------------
- To emit signals, use the ``EmitSignal`` method. Note that, as for signals defined by the engine,
- your custom signal names are listed under the nested ``SignalName`` class.
- .. code-block:: csharp
- public void MyMethodEmittingSignals()
- {
- EmitSignal(SignalName.MySignal);
- EmitSignal(SignalName.MySignalWithArgument, "World");
- }
- In contrast with other C# events, you cannot use ``Invoke`` to raise events tied to Godot signals.
- Signals support arguments of any :ref:`Variant-compatible type <c_sharp_variant_compatible_types>`.
- Consequently, any ``Node`` or ``RefCounted`` will be compatible automatically, but custom data objects will need
- to inherit from ``GodotObject`` or one of its subclasses.
- .. code-block:: csharp
- using Godot;
- public partial class DataObject : GodotObject
- {
- public string MyFirstString { get; set; }
- public string MySecondString { get; set; }
- }
- Bound values
- ------------
- Sometimes you'll want to bind values to a signal when the connection is established, rather than
- (or in addition to) when the signal is emitted. To do so, you can use an anonymous function like in
- the following example.
- Here, the :ref:`Button.Pressed <class_BaseButton_signal_pressed>` signal do not take any argument. But we
- want to use the same ``ModifyValue`` for both the "plus" and "minus" buttons. So we bind the
- modifier value at the time we're connecting the signals.
- .. code-block:: csharp
- public int Value { get; private set; } = 1;
- public override void _Ready()
- {
- Button plusButton = GetNode<Button>("PlusButton");
- plusButton.Pressed += () => ModifyValue(1);
- Button minusButton = GetNode<Button>("MinusButton");
- minusButton.Pressed += () => ModifyValue(-1);
- }
- private void ModifyValue(int modifier)
- {
- Value += modifier;
- }
- Signal creation at runtime
- --------------------------
- Finally, you can create custom signals directly while your game is running. Use the ``AddUserSignal``
- method for that. Be aware that it should be executed before any use of said signals (either
- connecting to them or emitting them). Also, note that signals created this way won't be visible through the
- ``SignalName`` nested class.
- .. code-block:: csharp
- public override void _Ready()
- {
- AddUserSignal("MyCustomSignal");
- EmitSignal("MyCustomSignal");
- }
- .. _using_connect_and_disconnect:
- Using Connect and Disconnect
- ----------------------------
- In general, it isn't recommended to use
- :ref:`Connect()<class_object_method_connect>` and
- :ref:`Disconnect()<class_object_method_disconnect>`. These APIs don't provide as
- much type safety as the events. However, they're necessary for
- :ref:`connecting to signals defined by GDScript <connecting_to_signals_cross_language>`
- and passing :ref:`ConnectFlags<enum_Object_ConnectFlags>`.
- In the following example, pressing the button for the first time prints
- ``Greetings!``. ``OneShot`` disconnects the signal, so pressing the button again
- does nothing.
- .. code-block:: csharp
- public override void _Ready()
- {
- Button button = GetNode<Button>("GreetButton");
- button.Connect(Button.SignalName.Pressed, Callable.From(OnButtonPressed), (uint)GodotObject.ConnectFlags.OneShot);
- }
- public void OnButtonPressed()
- {
- GD.Print("Greetings!");
- }
|