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