mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-03 05:48:42 +03:00
Added beginner 2D movement tutorial
This commit is contained in:
207
tutorials/2d/2d_movement.rst
Normal file
207
tutorials/2d/2d_movement.rst
Normal file
@@ -0,0 +1,207 @@
|
||||
.. _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
|
||||
|
||||
We'll use :ref:`KinematicBody2D <class_KinematicBody2D>` for these examples,
|
||||
but the principles will apply to other node types (Area2D, RigidBody2D) as well.
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
Each example below uses the same scene setup. Start with a ``KinematicBody2D`` with two
|
||||
children: ``Sprite`` and ``CollisionShape2D``. You can use the Godot icon ("icon.png")
|
||||
for the Sprite's texture or use any other 2D image you have available.
|
||||
|
||||
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.png
|
||||
|
||||
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 diagonal movement can be chosen by pressing two keys at once.
|
||||
|
||||
.. image:: img/movement_8way.gif
|
||||
|
||||
Add a script to the kinematic body and add the following code:
|
||||
|
||||
::
|
||||
|
||||
extends KinematicBody2D
|
||||
|
||||
export (int) var speed = 200
|
||||
|
||||
var velocity = Vector2()
|
||||
|
||||
func get_input():
|
||||
velocity = Vector2()
|
||||
if Input.is_action_pressed('right'):
|
||||
velocity.x += 1
|
||||
if Input.is_action_pressed('left'):
|
||||
velocity.x -= 1
|
||||
if Input.is_action_pressed('down'):
|
||||
velocity.y += 1
|
||||
if Input.is_action_pressed('up'):
|
||||
velocity.y -= 1
|
||||
velocity = velocity.normalized() * speed
|
||||
|
||||
func _physics_process(delta):
|
||||
get_input()
|
||||
move_and_slide(velocity)
|
||||
|
||||
In the ``get_input()`` function we check for the four key events and sum them
|
||||
up to get the velocity vector. This has the benefit of making two opposite keys
|
||||
cancel each other out, but will also result in diagonal movement being faster
|
||||
due to the two directions being added together.
|
||||
|
||||
We can prevent that if we *normalize* the velocity, which means we set
|
||||
its *length* to ``1``, and multiply by the desired speed.
|
||||
|
||||
.. tip:: If you've never used vector math before, or just need a refresher,
|
||||
you can see an explanation of vector usage in Godot at :ref:`doc_vector_math`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
extends KinematicBody2D
|
||||
|
||||
export (int) var speed = 200
|
||||
export (float) var rot_speed = 1.5
|
||||
|
||||
var velocity = Vector2()
|
||||
var rot_dir = 0
|
||||
|
||||
func get_input():
|
||||
rot_dir = 0
|
||||
velocity = Vector2()
|
||||
if Input.is_action_pressed('right'):
|
||||
rot_dir += 1
|
||||
if Input.is_action_pressed('left'):
|
||||
rot_dir -= 1
|
||||
if Input.is_action_pressed('down'):
|
||||
velocity = Vector2(-speed, 0).rotated(rotation)
|
||||
if Input.is_action_pressed('up'):
|
||||
velocity = Vector2(speed, 0).rotated(rotation)
|
||||
|
||||
func _physics_process(delta):
|
||||
get_input()
|
||||
rotation += rot_dir * rot_speed * delta
|
||||
move_and_slide(velocity)
|
||||
|
||||
Here we've added two new variables to track our rotation direction and speed.
|
||||
Again, pressing both keys at once will cancel out and result in no rotation.
|
||||
The rotation is applied directly to the body's ``rotation`` property.
|
||||
|
||||
To set the velocity, we use the ``Vector2.rotated()`` method so that it points
|
||||
in the same direction as the body. ``rotated()`` is a very useful vector function
|
||||
that you can use in many circumstances where you would otherwise need to apply
|
||||
trigonometric functions.
|
||||
|
||||
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
|
||||
|
||||
::
|
||||
|
||||
extends KinematicBody2D
|
||||
|
||||
export (int) var speed = 200
|
||||
|
||||
var velocity = Vector2()
|
||||
|
||||
func get_input():
|
||||
look_at(get_global_mouse_position())
|
||||
velocity = Vector2()
|
||||
if Input.is_action_pressed('down'):
|
||||
velocity = Vector2(-speed, 0).rotated(rotation)
|
||||
if Input.is_action_pressed('up'):
|
||||
velocity = Vector2(speed, 0).rotated(rotation)
|
||||
|
||||
func _physics_process(delta):
|
||||
get_input()
|
||||
move_and_slide(velocity)
|
||||
|
||||
Note that the :ref:`Node2D <class_Node2D>` ``look_at()`` method exists just
|
||||
for this purpose. Without this function, you could get the same effect by
|
||||
setting the angle like this:
|
||||
|
||||
::
|
||||
|
||||
rotation = get_global_mouse_position().angle_to_point(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
|
||||
|
||||
::
|
||||
|
||||
extends KinematicBody2D
|
||||
|
||||
export (int) var speed = 200
|
||||
|
||||
var target = Vector2()
|
||||
var velocity = Vector2()
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed('click'):
|
||||
target = get_global_mouse_position()
|
||||
|
||||
func _physics_process(delta):
|
||||
velocity = (target - position).normalized() * speed
|
||||
# rotation = velocity.angle()
|
||||
if (target - position).length() > 5:
|
||||
move_and_slide(velocity)
|
||||
|
||||
|
||||
Note the ``length()`` 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 ``rotation`` 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:
|
||||
:download:`2D_movement_demo.zip <files/2D_movement_demo.zip>`
|
||||
BIN
tutorials/2d/files/2D_movement_demo.zip
Normal file
BIN
tutorials/2d/files/2D_movement_demo.zip
Normal file
Binary file not shown.
BIN
tutorials/2d/img/movement_8way.gif
Normal file
BIN
tutorials/2d/img/movement_8way.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
BIN
tutorials/2d/img/movement_click.gif
Normal file
BIN
tutorials/2d/img/movement_click.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
BIN
tutorials/2d/img/movement_inputs.png
Normal file
BIN
tutorials/2d/img/movement_inputs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
tutorials/2d/img/movement_rotate1.gif
Normal file
BIN
tutorials/2d/img/movement_rotate1.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
BIN
tutorials/2d/img/movement_rotate2.gif
Normal file
BIN
tutorials/2d/img/movement_rotate2.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
@@ -10,3 +10,4 @@
|
||||
using_tilemaps
|
||||
custom_drawing_in_2d
|
||||
particle_systems_2d
|
||||
2d_movement
|
||||
|
||||
Reference in New Issue
Block a user