signals.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. .. Intention: give the user a first taste of signals. We should write more
  2. documentation in the scripting/ section.
  3. .. Note: GDScript snippets use one line return instead of two because they're
  4. really short.
  5. .. meta::
  6. :keywords: Signal
  7. .. _doc_signals:
  8. Using Signals
  9. =============
  10. In this lesson, we will look at signals. They are messages that nodes emit when
  11. something specific happens to them, like a button being pressed. Other nodes can
  12. connect to that signal and call a function when the event occurs.
  13. It is a delegation mechanism built into Godot that allows one game object to
  14. react to a change in another without them referencing one another. Using signals
  15. limits `coupling
  16. <https://en.wikipedia.org/wiki/Coupling_(computer_programming)>`_ and keeps your
  17. code flexible.
  18. For example, you might have a life bar on the screen that represents the
  19. player’s health. When the player takes damage or uses a healing potion, you want
  20. the bar to reflect the change. To do so, in Godot, you would use signals.
  21. .. note:: As mentioned in the introduction, signals are Godot's version of the
  22. observer pattern. You can learn more about it here:
  23. https://gameprogrammingpatterns.com/observer.html
  24. We will now use a signal to make our Godot icon from last part move and stop
  25. by pressing a button.
  26. .. Example
  27. Scene setup
  28. -----------
  29. Create a new scene by going to the menu Scene -> New Scene.
  30. .. image:: img/signals_01_new_scene.png
  31. In the Scene dock, click the 2D Scene button. This will add a Node2D as our
  32. root.
  33. .. image:: img/signals_02_2d_scene.png
  34. In the FileSystem dock, click and drag the ``Sprite.tscn`` file you saved
  35. previously onto the Node2D to instantiate it.
  36. .. image:: img/signals_03_dragging_scene.png
  37. We want to add another node as a sibling of the Sprite. To do so, right-click on
  38. Node2D and select Add Child Node.
  39. .. image:: img/signals_04_add_child_node.png
  40. Search for the Button node type and add it.
  41. .. image:: img/signals_05_add_button.png
  42. The node is small by default. Click and drag on the bottom-right handle of the
  43. Button in the viewport to resize it.
  44. .. image:: img/signals_06_drag_button.png
  45. If you don't see the handles, ensure the select tool is active in the toolbar.
  46. .. image:: img/signals_07_select_tool.png
  47. Click and drag on the button itself to move it closer to the sprite.
  48. You can also write a label on the Button by editing its Text property in the
  49. Inspector.
  50. .. image:: img/signals_08_toggle_motion_text.png
  51. Your scene tree and viewport should look like this.
  52. .. image:: img/signals_09_scene_setup.png
  53. Connecting a signal in the editor
  54. ---------------------------------
  55. Here, we want to connect the Button's "pressed" signal to our Sprite, and we
  56. want to call a new function that will toggle its motion on and off. We need to
  57. have a script attached to the Sprite node, which we do from the previous lesson.
  58. You can connect signals in the Node dock. Select the Button node and, on the
  59. right side of the editor, click on the tab named "Node" next to the Inspector.
  60. .. image:: img/signals_10_node_dock.png
  61. The dock displays a list of signals available on the selected node.
  62. .. image:: img/signals_11_pressed_signals.png
  63. Double-click the "pressed" signal to open the node connection window.
  64. .. image:: img/signals_12_node_connection.png
  65. There, you can connect the signal to the Sprite node. The node needs a receiver
  66. method, a function that Godot will call when the Button emits the signal. The
  67. editor generates one for you. By convention, we name these callback methods
  68. "_on_NodeName_signal_name". Here, it'll be "_on_Button_pressed".
  69. .. note::
  70. When connecting signals via the editor's Node dock, you can use two
  71. modes. The simple one only allows you to connect to nodes that have a
  72. script attached to them and creates a new callback function on them.
  73. .. image:: img/signals_advanced_connection_window.png
  74. The advanced view lets you connect to any node and any built-in
  75. function, add arguments to the callback, and set options. You can
  76. toggle the mode in the window's bottom-right by clicking the radio
  77. button.
  78. Click the connect button to complete the signal connection and jump to the
  79. Script workspace. You should see the new method with a connection icon in the
  80. left margin.
  81. .. image:: img/signals_13_signals_connection_icon.png
  82. If you click the icon, a window pops up and displays information about the
  83. connection. This feature is only available when connecting nodes in the editor.
  84. .. image:: img/signals_14_signals_connection_info.png
  85. Let's replace the line with the ``pass`` keyword with code that'll toggle the
  86. node's motion.
  87. Our Sprite moves thanks to code in the ``_process()`` function. Godot provides a
  88. method to toggle processing on and off: :ref:`Node.set_process()
  89. <class_Node_method_set_process>`. Another method of the Node class,
  90. ``is_processing()``, returns ``true`` if idle processing is active. We can use
  91. the ``not`` keyword to invert the value.
  92. .. tabs::
  93. .. code-tab:: gdscript GDScript
  94. func _on_Button_pressed():
  95. set_process(not is_processing())
  96. This function will toggle processing and, in turn, the icon's motion on and off
  97. upon pressing the button.
  98. Before trying the game, we need to simplify our ``_process()`` function to move
  99. the node automatically and not wait for user input. Replace it with the
  100. following code, which we saw two lessons ago:
  101. .. tabs::
  102. .. code-tab:: gdscript GDScript
  103. func _process(delta: float) -> void:
  104. rotation += angular_speed * delta
  105. var velocity = Vector2.UP.rotated(rotation) * speed
  106. position += velocity * delta
  107. Your complete Sprite.gd code should look like the following.
  108. .. tabs::
  109. .. code-tab:: gdscript GDScript
  110. extends Sprite
  111. var speed = 400
  112. var angular_speed = PI
  113. func _process(delta: float) -> void:
  114. rotation += angular_speed * delta
  115. var velocity = Vector2.UP.rotated(rotation) * speed
  116. position += velocity * delta
  117. func _on_Button_pressed():
  118. set_process(not is_processing())
  119. Run the scene now and click the button to see the sprite start and stop.
  120. Connecting a signal via code
  121. ----------------------------
  122. You can connect signals via code instead of using the editor. This is necessary
  123. when you create nodes or instantiate scenes inside of a script.
  124. Let's use a different node here. Godot has a :ref:`Timer <class_Timer>` node
  125. that's useful to implement skill cooldown times, weapon reloading, and more.
  126. Head back to the 2D workspace. You can either click the "2D" text at the top of
  127. the window or press :kbd:`F2` (:kbd:`Alt + 2` on macOS).
  128. In the Scene dock, right-click on the Sprite node and add a new node. Search for
  129. Timer and add the corresponding node. Your scene should now look like this.
  130. .. image:: img/signals_15_scene_tree.png
  131. Click the script icon next to Sprite to jump back to the scripting workspace.
  132. .. image:: img/signals_16_click_script.png
  133. We need to do two operations to connect the nodes via code:
  134. 1. Get a reference to the Timer from the Sprite.
  135. 2. Call the Timer's ``connect()`` method.
  136. .. note:: To connect to a signal via code, you need to call the ``connect()``
  137. method of the node you want to listen to. In this case, we want to
  138. listen to the Timer's "timeout" signal.
  139. To get a reference to a node relative to the current one, we use the method
  140. :ref:`Node.get_node() <class_Node_method_get_node>`. We can store the reference
  141. in a variable.
  142. .. tabs::
  143. .. code-tab:: gdscript GDScript
  144. extends Sprite
  145. #...
  146. func _ready():
  147. var timer = get_node("Timer")
  148. The function ``get_node()`` looks at the Sprite's children and gets nodes by
  149. their name. For example, if you renamed the Timer node to "BlinkingTimer" in the
  150. editor, you would have to change the call to ``get_node("BlinkingTimer")``.
  151. .. add seealso to a page that explains node features.
  152. We can now connect the Timer to the Sprite in the ``_ready()`` function.
  153. .. tabs::
  154. .. code-tab:: gdscript GDScript
  155. func _ready():
  156. var timer = get_node("Timer")
  157. timer.connect("timeout", self, "_on_Timer_timeout")
  158. The line reads like so: we connect the Timer's "timeout" signal to the node to
  159. which the script is attached (``self``). When the Timer emits "timeout", we want
  160. to call the function "_on_Timer_timeout", that we need to define. Let's add it
  161. at the bottom of our script and use it to toggle our sprite's visibility.
  162. .. tabs::
  163. .. code-tab:: gdscript GDScript
  164. func _on_Timer_timeout():
  165. visible = not visible
  166. The ``visible`` property is a boolean that controls the visibility of our node.
  167. The line ``visible = not visible`` toggles the value. If ``visible`` is
  168. ``true``, it becomes ``false``, and vice-versa.
  169. Custom signals
  170. --------------
  171. You can define custom signals in a script. Say, for example, that you want to
  172. show a game over screen when the player's health reaches zero. To do so, you
  173. could define a signal named "died" or "health_depleted" when their health
  174. reaches 0.
  175. .. tabs::
  176. .. code-tab:: gdscript GDScript
  177. extends Node2D
  178. signal health_depleted
  179. var health = 10
  180. .. note:: As signals represent events that just occurred, we generally use an
  181. action verb in the past tense in their names.
  182. Your signals work the same way as built-in ones: they appear in the Node tab and
  183. you can connect to them like any other.
  184. .. image:: img/signals_17_custom_signal.png
  185. To emit a signal in your scripts, call ``emit_signal()``.
  186. .. tabs::
  187. .. code-tab:: gdscript GDScript
  188. func take_damage(amount):
  189. health -= amount
  190. if health <= 0:
  191. emit_signal("health_depleted")
  192. A signal can optionally declare one or more arguments. Specify the argument
  193. names between parentheses:
  194. .. tabs::
  195. .. code-tab:: gdscript GDScript
  196. extends Node
  197. signal health_changed(old_value, new_value)
  198. .. note::
  199. The signal arguments show up in the editor's node dock, and Godot can use
  200. them to generate callback functions for you. However, you can still emit any
  201. number of arguments when you emit signals. So it's up to you to emit the
  202. correct values.
  203. To emit values along with the signal, add them as extra arguments to the
  204. ``emit_signal()`` function:
  205. .. tabs::
  206. .. code-tab:: gdscript GDScript
  207. func take_damage(amount):
  208. var old_health = health
  209. health -= amount
  210. emit_signal("health_changed", old_health, health)
  211. Summary
  212. -------
  213. Any node in Godot emits signals when something specific happens to them, like a
  214. button being pressed. Other nodes can connect to individual signals and react to
  215. selected events.
  216. Signals have many uses. With them, you can react to a node entering or exiting
  217. the game world, to a collision, to a character entering or leaving an area, to
  218. an element of the interface changing size, and much more.
  219. For example, an :ref:`Area2D <class_Area2D>` representing a coin emits a
  220. ``body_entered`` signal whenever the player's physics body enters its collision
  221. shape, allowing you to know when the player collected it.
  222. In the next section, :ref:`doc_your_first_2d_game`, you'll create a complete 2D
  223. game and put everything you learned so far into practice.