|
@@ -3,8 +3,8 @@
|
|
Jumping and squashing monsters
|
|
Jumping and squashing monsters
|
|
==============================
|
|
==============================
|
|
|
|
|
|
-In this part, we’ll add the ability to jump, to squash the monsters. In the next
|
|
|
|
-lesson, we’ll make the player die when a monster hits them on the ground.
|
|
|
|
|
|
+In this part, we'll add the ability to jump, to squash the monsters. In the next
|
|
|
|
+lesson, we'll make the player die when a monster hits them on the ground.
|
|
|
|
|
|
First, we have to change a few settings related to physics interactions. Enter
|
|
First, we have to change a few settings related to physics interactions. Enter
|
|
the world of :ref:`physics layers
|
|
the world of :ref:`physics layers
|
|
@@ -20,7 +20,7 @@ Masks control the layers that a body will listen to and detect. This affects
|
|
collision detection. When you want two bodies to interact, you need at least one
|
|
collision detection. When you want two bodies to interact, you need at least one
|
|
to have a mask corresponding to the other.
|
|
to have a mask corresponding to the other.
|
|
|
|
|
|
-If that’s confusing, don’t worry, we’ll see three examples in a second.
|
|
|
|
|
|
+If that's confusing, don't worry, we'll see three examples in a second.
|
|
|
|
|
|
The important point is that you can use layers and masks to filter physics
|
|
The important point is that you can use layers and masks to filter physics
|
|
interactions, control performance, and remove the need for extra conditions in
|
|
interactions, control performance, and remove the need for extra conditions in
|
|
@@ -30,12 +30,12 @@ By default, all physics bodies and areas are set to both layer and mask ``0``.
|
|
This means they all collide with each other.
|
|
This means they all collide with each other.
|
|
|
|
|
|
Physics layers are represented by numbers, but we can give them names to keep
|
|
Physics layers are represented by numbers, but we can give them names to keep
|
|
-track of what’s what.
|
|
|
|
|
|
+track of what's what.
|
|
|
|
|
|
Setting layer names
|
|
Setting layer names
|
|
~~~~~~~~~~~~~~~~~~~
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
-Let’s give our physics layers a name. Go to *Project -> Project Settings*.
|
|
|
|
|
|
+Let's give our physics layers a name. Go to *Project -> Project Settings*.
|
|
|
|
|
|
|image0|
|
|
|image0|
|
|
|
|
|
|
@@ -52,7 +52,7 @@ Assigning layers and masks
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
In the *Main* scene, select the *Ground* node. In the *Inspector*, expand the
|
|
In the *Main* scene, select the *Ground* node. In the *Inspector*, expand the
|
|
-*Collision* section. There, you can see the node’s layers and masks as a grid of
|
|
|
|
|
|
+*Collision* section. There, you can see the node's layers and masks as a grid of
|
|
buttons.
|
|
buttons.
|
|
|
|
|
|
|image2|
|
|
|image2|
|
|
@@ -64,11 +64,11 @@ one. Then, toggle off the *Mask* by clicking on it.
|
|
|image3|
|
|
|image3|
|
|
|
|
|
|
As I mentioned above, the *Mask* property allows a node to listen to interaction
|
|
As I mentioned above, the *Mask* property allows a node to listen to interaction
|
|
-with other physics objects, but we don’t need it to have collisions. The
|
|
|
|
-*Ground* doesn’t need to listen to anything; it’s just there to prevent
|
|
|
|
|
|
+with other physics objects, but we don't need it to have collisions. The
|
|
|
|
+*Ground* doesn't need to listen to anything; it's just there to prevent
|
|
creatures from falling.
|
|
creatures from falling.
|
|
|
|
|
|
-Note that you can click the “...” button on the right side of the properties to
|
|
|
|
|
|
+Note that you can click the "..." button on the right side of the properties to
|
|
see a list of named checkboxes.
|
|
see a list of named checkboxes.
|
|
|
|
|
|
|image4|
|
|
|image4|
|
|
@@ -76,34 +76,34 @@ see a list of named checkboxes.
|
|
Next up are the *Player* and the *Mob*. Open ``Player.tscn`` by double-clicking
|
|
Next up are the *Player* and the *Mob*. Open ``Player.tscn`` by double-clicking
|
|
the file in the *FileSystem* dock.
|
|
the file in the *FileSystem* dock.
|
|
|
|
|
|
-Select the *Player* node and set its *Collision -> Mask* to both “enemies” and
|
|
|
|
-“world”. You can leave the default *Layer* property as the first layer is the
|
|
|
|
-“player” one.
|
|
|
|
|
|
+Select the *Player* node and set its *Collision -> Mask* to both "enemies" and
|
|
|
|
+"world". You can leave the default *Layer* property as the first layer is the
|
|
|
|
+"player" one.
|
|
|
|
|
|
|image5|
|
|
|image5|
|
|
|
|
|
|
Then, open the *Mob* scene by double-clicking on ``Mob.tscn`` and select the
|
|
Then, open the *Mob* scene by double-clicking on ``Mob.tscn`` and select the
|
|
*Mob* node.
|
|
*Mob* node.
|
|
|
|
|
|
-Set its *Collision -> Layer* to “enemies” and its *Collision -> Mask* to both
|
|
|
|
-“player”.
|
|
|
|
|
|
+Set its *Collision -> Layer* to "enemies" and its *Collision -> Mask* to both
|
|
|
|
+"player".
|
|
|
|
|
|
|image6|
|
|
|image6|
|
|
|
|
|
|
These settings mean the monsters will move through one another. If you want the
|
|
These settings mean the monsters will move through one another. If you want the
|
|
-monsters to collide with and slide against each other, turn on the “enemies”
|
|
|
|
|
|
+monsters to collide with and slide against each other, turn on the "enemies"
|
|
mask.
|
|
mask.
|
|
|
|
|
|
.. note::
|
|
.. note::
|
|
|
|
|
|
- The mobs don’t need to mask the “world” layer because they only move
|
|
|
|
- on the XZ plane. We don’t apply any gravity to them by design.
|
|
|
|
|
|
+ The mobs don't need to mask the "world" layer because they only move
|
|
|
|
+ on the XZ plane. We don't apply any gravity to them by design.
|
|
|
|
|
|
Jumping
|
|
Jumping
|
|
-------
|
|
-------
|
|
|
|
|
|
The jumping mechanic itself requires only two lines of code. Open the *Player*
|
|
The jumping mechanic itself requires only two lines of code. Open the *Player*
|
|
-script. We need a value to control the jump’s strength and update
|
|
|
|
|
|
+script. We need a value to control the jump's strength and update
|
|
``_physics_process()`` to code the jump.
|
|
``_physics_process()`` to code the jump.
|
|
|
|
|
|
After the line that defines ``fall_acceleration``, at the top of the script, add
|
|
After the line that defines ``fall_acceleration``, at the top of the script, add
|
|
@@ -129,37 +129,37 @@ called ``move_and_slide()``.
|
|
|
|
|
|
#...
|
|
#...
|
|
|
|
|
|
-That’s all you need to jump!
|
|
|
|
|
|
+That's all you need to jump!
|
|
|
|
|
|
The ``is_on_floor()`` method is a tool from the ``KinematicBody`` class. It
|
|
The ``is_on_floor()`` method is a tool from the ``KinematicBody`` class. It
|
|
-returns ``true`` if the body collided with the floor in this frame. That’s why
|
|
|
|
|
|
+returns ``true`` if the body collided with the floor in this frame. That's why
|
|
we apply gravity to the *Player*: so we collide with the floor instead of
|
|
we apply gravity to the *Player*: so we collide with the floor instead of
|
|
floating over it like the monsters.
|
|
floating over it like the monsters.
|
|
|
|
|
|
-If the character is on the floor and the player presses “jump”, we instantly
|
|
|
|
|
|
+If the character is on the floor and the player presses "jump", we instantly
|
|
give them a lot of vertical speed. In games, you really want controls to be
|
|
give them a lot of vertical speed. In games, you really want controls to be
|
|
responsive and giving instant speed boosts like these, while unrealistic, feel
|
|
responsive and giving instant speed boosts like these, while unrealistic, feel
|
|
great.
|
|
great.
|
|
|
|
|
|
-Notice that the Y axis is positive upwards. That’s unlike 2D, where the Y axis
|
|
|
|
|
|
+Notice that the Y axis is positive upwards. That's unlike 2D, where the Y axis
|
|
is positive downward.
|
|
is positive downward.
|
|
|
|
|
|
Squashing monsters
|
|
Squashing monsters
|
|
------------------
|
|
------------------
|
|
|
|
|
|
-Let’s add the squash mechanic next. We’re going to make the character bounce
|
|
|
|
|
|
+Let's add the squash mechanic next. We're going to make the character bounce
|
|
over monsters and kill them at the same time.
|
|
over monsters and kill them at the same time.
|
|
|
|
|
|
We need to detect collisions with a monster and to differentiate them from
|
|
We need to detect collisions with a monster and to differentiate them from
|
|
-collisions with the floor. To do so, we can use Godot’s :ref:`group
|
|
|
|
|
|
+collisions with the floor. To do so, we can use Godot's :ref:`group
|
|
<doc_groups>` tagging feature.
|
|
<doc_groups>` tagging feature.
|
|
|
|
|
|
Open the scene ``Mob.tscn`` again and select the *Mob* node. Go to the *Node*
|
|
Open the scene ``Mob.tscn`` again and select the *Mob* node. Go to the *Node*
|
|
dock on the right to see a list of signals. The *Node* dock has two tabs:
|
|
dock on the right to see a list of signals. The *Node* dock has two tabs:
|
|
-*Signals*, which you’ve already used, and *Groups*, which allows you to assign
|
|
|
|
|
|
+*Signals*, which you've already used, and *Groups*, which allows you to assign
|
|
tags to nodes.
|
|
tags to nodes.
|
|
|
|
|
|
-Click on it to reveal a field where you can write a tag name. Enter “mob” in the
|
|
|
|
|
|
+Click on it to reveal a field where you can write a tag name. Enter "mob" in the
|
|
field and click the *Add* button.
|
|
field and click the *Add* button.
|
|
|
|
|
|
|image7|
|
|
|image7|
|
|
@@ -178,7 +178,7 @@ Coding the squash mechanic
|
|
Head back to the *Player* script to code the squash and bounce.
|
|
Head back to the *Player* script to code the squash and bounce.
|
|
|
|
|
|
At the top of the script, we need another property, ``bounce_impulse``. When
|
|
At the top of the script, we need another property, ``bounce_impulse``. When
|
|
-squashing an enemy, we don’t necessarily want the character to go as high up as
|
|
|
|
|
|
+squashing an enemy, we don't necessarily want the character to go as high up as
|
|
when jumping.
|
|
when jumping.
|
|
|
|
|
|
::
|
|
::
|
|
@@ -189,13 +189,13 @@ when jumping.
|
|
|
|
|
|
Then, at the bottom of ``_physics_process()``, add the following loop. With
|
|
Then, at the bottom of ``_physics_process()``, add the following loop. With
|
|
``move_and_slide()``, Godot makes the body move sometimes multiple times in a
|
|
``move_and_slide()``, Godot makes the body move sometimes multiple times in a
|
|
-row to smooth out the character’s motion. So we have to loop over all collisions
|
|
|
|
|
|
+row to smooth out the character's motion. So we have to loop over all collisions
|
|
that may have happened.
|
|
that may have happened.
|
|
|
|
|
|
In every iteration of the loop, we check if we landed on a mob. If so, we kill
|
|
In every iteration of the loop, we check if we landed on a mob. If so, we kill
|
|
it and bounce.
|
|
it and bounce.
|
|
|
|
|
|
-With this code, if no collisions occurred on a given frame, the loop won’t run.
|
|
|
|
|
|
+With this code, if no collisions occurred on a given frame, the loop won't run.
|
|
|
|
|
|
::
|
|
::
|
|
|
|
|
|
@@ -213,7 +213,7 @@ With this code, if no collisions occurred on a given frame, the loop won’t run
|
|
mob.squash()
|
|
mob.squash()
|
|
velocity.y = bounce_impulse
|
|
velocity.y = bounce_impulse
|
|
|
|
|
|
-That’s a lot of new functions. Here’s some more information about them.
|
|
|
|
|
|
+That's a lot of new functions. Here's some more information about them.
|
|
|
|
|
|
The functions ``get_slide_count()`` and ``get_slide_collision()`` both come from
|
|
The functions ``get_slide_count()`` and ``get_slide_collision()`` both come from
|
|
the :ref:`KinematicBody<class_KinematicBody>` class and are related to
|
|
the :ref:`KinematicBody<class_KinematicBody>` class and are related to
|
|
@@ -222,7 +222,7 @@ the :ref:`KinematicBody<class_KinematicBody>` class and are related to
|
|
``get_slide_collision()`` returns a
|
|
``get_slide_collision()`` returns a
|
|
:ref:`KinematicCollision<class_KinematicCollision>` object that holds
|
|
:ref:`KinematicCollision<class_KinematicCollision>` object that holds
|
|
information about where and how the collision occurred. For example, we use its
|
|
information about where and how the collision occurred. For example, we use its
|
|
-``collider`` property to check if we collided with a “mob” by calling
|
|
|
|
|
|
+``collider`` property to check if we collided with a "mob" by calling
|
|
``is_in_group()`` on it: ``collision.collider.is_in_group("mob")``.
|
|
``is_in_group()`` on it: ``collision.collider.is_in_group("mob")``.
|
|
|
|
|
|
.. note::
|
|
.. note::
|
|
@@ -261,9 +261,9 @@ destroy the mob.
|
|
We will use the signal to add points to the score in the next lesson.
|
|
We will use the signal to add points to the score in the next lesson.
|
|
|
|
|
|
With that, you should be able to kill monsters by jumping on them. You can press
|
|
With that, you should be able to kill monsters by jumping on them. You can press
|
|
-F5 to try the game and set ``Main.tscn`` as your project’s main scene.
|
|
|
|
|
|
+F5 to try the game and set ``Main.tscn`` as your project's main scene.
|
|
|
|
|
|
-However, the player won’t die yet. We’ll work on that in the next part.
|
|
|
|
|
|
+However, the player won't die yet. We'll work on that in the next part.
|
|
|
|
|
|
.. |image0| image:: img/06.jump_and_squash/02.project_settings.png
|
|
.. |image0| image:: img/06.jump_and_squash/02.project_settings.png
|
|
.. |image1| image:: img/06.jump_and_squash/03.physics_layers.png
|
|
.. |image1| image:: img/06.jump_and_squash/03.physics_layers.png
|