2d_movement.rst 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. .. _doc_2d_movement:
  2. 2D movement overview
  3. ====================
  4. Introduction
  5. ------------
  6. Every beginner has been there: "How do I move my character?" Depending on the
  7. style of game you're making, you may have special requirements, but in general
  8. the movement in most 2D games is based on a small number of designs.
  9. We'll use :ref:`CharacterBody2D <class_CharacterBody2D>` for these examples,
  10. but the principles will apply to other node types (Area2D, RigidBody2D) as well.
  11. .. _doc_2d_movement_setup:
  12. Setup
  13. -----
  14. Each example below uses the same scene setup. Start with a ``CharacterBody2D`` with two
  15. children: ``Sprite2D`` and ``CollisionShape2D``. You can use the Godot icon ("icon.png")
  16. for the Sprite2D's texture or use any other 2D image you have.
  17. Open ``Project -> Project Settings`` and select the "Input Map" tab. Add the following
  18. input actions (see :ref:`InputEvent <doc_inputevent>` for details):
  19. .. image:: img/movement_inputs.webp
  20. 8-way movement
  21. --------------
  22. In this scenario, you want the user to press the four directional keys (up/left/down/right
  23. or W/A/S/D) and move in the selected direction. The name "8-way movement" comes from the
  24. fact that the player can move diagonally by pressing two keys at the same time.
  25. .. video:: video/movement_8way.webm
  26. :alt: 8-way movement
  27. :autoplay:
  28. :loop:
  29. :muted:
  30. :align: default
  31. :width: 100%
  32. Add a script to the character body and add the following code:
  33. .. tabs::
  34. .. code-tab:: gdscript GDScript
  35. extends CharacterBody2D
  36. @export var speed = 400
  37. func get_input():
  38. var input_direction = Input.get_vector("left", "right", "up", "down")
  39. velocity = input_direction * speed
  40. func _physics_process(delta):
  41. get_input()
  42. move_and_slide()
  43. .. code-tab:: csharp
  44. using Godot;
  45. public partial class Movement : CharacterBody2D
  46. {
  47. [Export]
  48. public int Speed { get; set; } = 400;
  49. public void GetInput()
  50. {
  51. Vector2 inputDirection = Input.GetVector("left", "right", "up", "down");
  52. Velocity = inputDirection * Speed;
  53. }
  54. public override void _PhysicsProcess(double delta)
  55. {
  56. GetInput();
  57. MoveAndSlide();
  58. }
  59. }
  60. In the ``get_input()`` function, we use :ref:`Input <class_Input>` ``get_vector()`` to check for the
  61. four key events and sum return a direction vector.
  62. We can then set our velocity by multiplying this direction vector, which has a
  63. length of ``1``, by our desired speed.
  64. .. tip:: If you've never used vector math before, or need a refresher,
  65. you can see an explanation of vector usage in Godot at :ref:`doc_vector_math`.
  66. .. note::
  67. If the code above does nothing when you press the keys, double-check that
  68. you've set up input actions correctly as described in the
  69. :ref:`doc_2d_movement_setup` part of this tutorial.
  70. Rotation + movement
  71. -------------------
  72. This type of movement is sometimes called "Asteroids-style" because it resembles
  73. how that classic arcade game worked. Pressing left/right rotates the character,
  74. while up/down moves it forward or backward in whatever direction it's facing.
  75. .. video:: video/movement_rotate_keyboard.webm
  76. :alt: Rotation + movement
  77. :autoplay:
  78. :loop:
  79. :muted:
  80. :align: default
  81. :width: 100%
  82. .. tabs::
  83. .. code-tab:: gdscript GDScript
  84. extends CharacterBody2D
  85. @export var speed = 400
  86. @export var rotation_speed = 1.5
  87. var rotation_direction = 0
  88. func get_input():
  89. rotation_direction = Input.get_axis("left", "right")
  90. velocity = transform.x * Input.get_axis("down", "up") * speed
  91. func _physics_process(delta):
  92. get_input()
  93. rotation += rotation_direction * rotation_speed * delta
  94. move_and_slide()
  95. .. code-tab:: csharp
  96. using Godot;
  97. public partial class Movement : CharacterBody2D
  98. {
  99. [Export]
  100. public int Speed { get; set; } = 400;
  101. [Export]
  102. public float RotationSpeed { get; set; } = 1.5f;
  103. private float _rotationDirection;
  104. public void GetInput()
  105. {
  106. _rotationDirection = Input.GetAxis("left", "right");
  107. Velocity = Transform.X * Input.GetAxis("down", "up") * Speed;
  108. }
  109. public override void _PhysicsProcess(double delta)
  110. {
  111. GetInput();
  112. Rotation += _rotationDirection * RotationSpeed * (float)delta;
  113. MoveAndSlide();
  114. }
  115. }
  116. Here we've added two variables to track our rotation direction and speed.
  117. The rotation is applied directly to the body's ``rotation`` property.
  118. To set the velocity, we use the body's ``transform.x`` which is a vector pointing
  119. in the body's "forward" direction, and multiply that by the speed.
  120. Rotation + movement (mouse)
  121. ---------------------------
  122. This style of movement is a variation of the previous one. This time, the direction
  123. is set by the mouse position instead of the keyboard. The character will always
  124. "look at" the mouse pointer. The forward/back inputs remain the same, however.
  125. .. video:: video/movement_rotate_mouse.webm
  126. :alt: Rotation + movement (mouse)
  127. :autoplay:
  128. :loop:
  129. :muted:
  130. :align: default
  131. :width: 100%
  132. .. tabs::
  133. .. code-tab:: gdscript GDScript
  134. extends CharacterBody2D
  135. @export var speed = 400
  136. func get_input():
  137. look_at(get_global_mouse_position())
  138. velocity = transform.x * Input.get_axis("down", "up") * speed
  139. func _physics_process(delta):
  140. get_input()
  141. move_and_slide()
  142. .. code-tab:: csharp
  143. using Godot;
  144. public partial class Movement : CharacterBody2D
  145. {
  146. [Export]
  147. public int Speed { get; set; } = 400;
  148. public void GetInput()
  149. {
  150. LookAt(GetGlobalMousePosition());
  151. Velocity = Transform.X * Input.GetAxis("down", "up") * Speed;
  152. }
  153. public override void _PhysicsProcess(double delta)
  154. {
  155. GetInput();
  156. MoveAndSlide();
  157. }
  158. }
  159. Here we're using the :ref:`Node2D <class_Node2D>` ``look_at()`` method to
  160. point the player towards the mouse's position. Without this function, you
  161. could get the same effect by setting the angle like this:
  162. .. tabs::
  163. .. code-tab:: gdscript GDScript
  164. rotation = get_global_mouse_position().angle_to_point(position)
  165. .. code-tab:: csharp
  166. var rotation = GetGlobalMousePosition().AngleToPoint(Position);
  167. Click-and-move
  168. --------------
  169. This last example uses only the mouse to control the character. Clicking
  170. on the screen will cause the player to move to the target location.
  171. .. video:: video/movement_click.webm
  172. :alt: Click-and-move
  173. :autoplay:
  174. :loop:
  175. :muted:
  176. :align: default
  177. :width: 100%
  178. .. tabs::
  179. .. code-tab:: gdscript GDScript
  180. extends CharacterBody2D
  181. @export var speed = 400
  182. var target = position
  183. func _input(event):
  184. # Use is_action_pressed to only accept single taps as input instead of mouse drags.
  185. if event.is_action_pressed(&"click"):
  186. target = get_global_mouse_position()
  187. func _physics_process(delta):
  188. velocity = position.direction_to(target) * speed
  189. # look_at(target)
  190. if position.distance_to(target) > 10:
  191. move_and_slide()
  192. .. code-tab:: csharp
  193. using Godot;
  194. public partial class Movement : CharacterBody2D
  195. {
  196. [Export]
  197. public int Speed { get; set; } = 400;
  198. private Vector2 _target;
  199. public override void _Input(InputEvent @event)
  200. {
  201. // Use IsActionPressed to only accept single taps as input instead of mouse drags.
  202. if (@event.IsActionPressed("click"))
  203. {
  204. _target = GetGlobalMousePosition();
  205. }
  206. }
  207. public override void _PhysicsProcess(double delta)
  208. {
  209. Velocity = Position.DirectionTo(_target) * Speed;
  210. // LookAt(_target);
  211. if (Position.DistanceTo(_target) > 10)
  212. {
  213. MoveAndSlide();
  214. }
  215. }
  216. }
  217. Note the ``distance_to()`` check we make prior to movement. Without this test,
  218. the body would "jitter" upon reaching the target position, as it moves
  219. slightly past the position and tries to move back, only to move too far and
  220. repeat.
  221. Uncommenting the ``look_at()`` line will also turn the body to point in its
  222. direction of motion if you prefer.
  223. .. tip:: This technique can also be used as the basis of a "following" character.
  224. The ``target`` position can be that of any object you want to move to.
  225. Summary
  226. -------
  227. You may find these code samples useful as starting points for your own projects.
  228. Feel free to use them and experiment with them to see what you can make.
  229. You can download this sample project here:
  230. `2d_movement_starter.zip <https://github.com/godotengine/godot-docs-project-starters/releases/download/latest-4.x/2d_movement_starter.zip>`_