scripting_player_input.rst 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. .. Intention: only introduce one necessary input method at this point. The
  2. Inputs section of the docs should provide more guides comparing the various
  3. tools you have to manage the complexity of user input.
  4. .. _doc_scripting_player_input:
  5. Listening to player input
  6. =========================
  7. Building upon the previous lesson, :ref:`doc_scripting_first_script`, let's look
  8. at another important feature of any game: giving control to the player.
  9. To add this, we need to modify our ``sprite_2d.gd`` code.
  10. .. image:: img/scripting_first_script_moving_with_input.gif
  11. You have two main tools to process the player's input in Godot:
  12. 1. The built-in input callbacks, mainly ``_unhandled_input()``. Like
  13. ``_process()``, it's a built-in virtual function that Godot calls every time
  14. the player presses a key. It's the tool you want to use to react to events
  15. that don't happen every frame, like pressing :kbd:`Space` to jump. To learn
  16. more about input callbacks, see :ref:`doc_inputevent`.
  17. 2. The ``Input`` singleton. A singleton is a globally accessible object. Godot
  18. provides access to several in scripts. It's the right tool to check for input
  19. every frame.
  20. We're going to use the ``Input`` singleton here as we need to know if the player
  21. wants to turn or move every frame.
  22. For turning, we should use a new variable: ``direction``. In our ``_process()``
  23. function, replace the ``rotation += angular_speed * delta`` line with the
  24. code below.
  25. .. tabs::
  26. .. code-tab:: gdscript GDScript
  27. var direction = 0
  28. if Input.is_action_pressed("ui_left"):
  29. direction = -1
  30. if Input.is_action_pressed("ui_right"):
  31. direction = 1
  32. rotation += angular_speed * direction * delta
  33. .. code-tab:: csharp C#
  34. var direction = 0;
  35. if (Input.IsActionPressed("ui_left"))
  36. {
  37. direction = -1;
  38. }
  39. if (Input.IsActionPressed("ui_right"))
  40. {
  41. direction = 1;
  42. }
  43. Rotation += _angularSpeed * direction * (float)delta;
  44. Our ``direction`` local variable is a multiplier representing the direction in
  45. which the player wants to turn. A value of ``0`` means the player isn't pressing
  46. the left or the right arrow key. A value of ``1`` means the player wants to turn
  47. right, and ``-1`` means they want to turn left.
  48. To produce these values, we introduce conditions and the use of ``Input``. A
  49. condition starts with the ``if`` keyword in GDScript and ends with a colon. The
  50. condition is the expression between the keyword and the end of the line.
  51. To check if a key was pressed this frame, we call ``Input.is_action_pressed()``.
  52. The method takes a text string representing an input action and returns ``true``
  53. if the action is pressed, ``false`` otherwise.
  54. The two actions we use above, "ui_left" and "ui_right", are predefined in every
  55. Godot project. They respectively trigger when the player presses the left and
  56. right arrows on the keyboard or left and right on a gamepad's D-pad.
  57. .. note:: You can see and edit input actions in your project by going to Project
  58. -> Project Settings and clicking on the Input Map tab.
  59. Finally, we use the ``direction`` as a multiplier when we update the node's
  60. ``rotation``: ``rotation += angular_speed * direction * delta``.
  61. Comment out the lines ``var velocity = Vector2.UP.rotated(rotation) * speed`` and ``position += velocity * delta`` like this:
  62. .. tabs::
  63. .. code-tab:: gdscript GDScript
  64. #var velocity = Vector2.UP.rotated(rotation) * speed
  65. #position += velocity * delta
  66. .. code-tab:: csharp C#
  67. //var velocity = Vector2.Up.Rotated(Rotation) * _speed;
  68. //Position += velocity * (float)delta;
  69. This will ignore the code that moved the icon's position in a circle without user input from the previous exercise.
  70. If you run the scene with this code, the icon should rotate when you press
  71. :kbd:`Left` and :kbd:`Right`.
  72. Moving when pressing "up"
  73. -------------------------
  74. To only move when pressing a key, we need to modify the code that calculates the
  75. velocity. Uncomment the code and replace the line starting with ``var velocity`` with the code below.
  76. .. tabs::
  77. .. code-tab:: gdscript GDScript
  78. var velocity = Vector2.ZERO
  79. if Input.is_action_pressed("ui_up"):
  80. velocity = Vector2.UP.rotated(rotation) * speed
  81. .. code-tab:: csharp C#
  82. var velocity = Vector2.Zero;
  83. if (Input.IsActionPressed("ui_up"))
  84. {
  85. velocity = Vector2.Up.Rotated(Rotation) * _speed;
  86. }
  87. We initialize the ``velocity`` with a value of ``Vector2.ZERO``, another
  88. constant of the built-in ``Vector`` type representing a 2D vector of length 0.
  89. If the player presses the "ui_up" action, we then update the velocity's value,
  90. causing the sprite to move forward.
  91. Complete script
  92. ---------------
  93. Here is the complete ``sprite_2d.gd`` file for reference.
  94. .. tabs::
  95. .. code-tab:: gdscript GDScript
  96. extends Sprite2D
  97. var speed = 400
  98. var angular_speed = PI
  99. func _process(delta):
  100. var direction = 0
  101. if Input.is_action_pressed("ui_left"):
  102. direction = -1
  103. if Input.is_action_pressed("ui_right"):
  104. direction = 1
  105. rotation += angular_speed * direction * delta
  106. var velocity = Vector2.ZERO
  107. if Input.is_action_pressed("ui_up"):
  108. velocity = Vector2.UP.rotated(rotation) * speed
  109. position += velocity * delta
  110. .. code-tab:: csharp C#
  111. using Godot;
  112. public partial class MySprite2D : Sprite2D
  113. {
  114. private float _speed = 400;
  115. private float _angularSpeed = Mathf.Pi;
  116. public override void _Process(double delta)
  117. {
  118. var direction = 0;
  119. if (Input.IsActionPressed("ui_left"))
  120. {
  121. direction = -1;
  122. }
  123. if (Input.IsActionPressed("ui_right"))
  124. {
  125. direction = 1;
  126. }
  127. Rotation += _angularSpeed * direction * (float)delta;
  128. var velocity = Vector2.Zero;
  129. if (Input.IsActionPressed("ui_up"))
  130. {
  131. velocity = Vector2.Up.Rotated(Rotation) * _speed;
  132. }
  133. Position += velocity * (float)delta;
  134. }
  135. }
  136. If you run the scene, you should now be able to rotate with the left and right
  137. arrow keys and move forward by pressing :kbd:`Up`.
  138. .. image:: img/scripting_first_script_moving_with_input.gif
  139. Summary
  140. -------
  141. In summary, every script in Godot represents a class and extends one of the
  142. engine's built-in classes. The node types your classes inherit from give you
  143. access to properties, such as ``rotation`` and ``position`` in our sprite's case.
  144. You also inherit many functions, which we didn't get to use in this example.
  145. In GDScript, the variables you put at the top of the file are your class's
  146. properties, also called member variables. Besides variables, you can define
  147. functions, which, for the most part, will be your classes' methods.
  148. Godot provides several virtual functions you can define to connect your class
  149. with the engine. These include ``_process()``, to apply changes to the node
  150. every frame, and ``_unhandled_input()``, to receive input events like key and
  151. button presses from the users. There are quite a few more.
  152. The ``Input`` singleton allows you to react to the players' input anywhere in
  153. your code. In particular, you'll get to use it in the ``_process()`` loop.
  154. In the next lesson, :ref:`doc_signals`, we'll build upon the relationship between
  155. scripts and nodes by having our nodes trigger code in scripts.