Write the first three parts of the 3D tutorial

This commit is contained in:
Nathan Lovato
2020-11-23 14:43:53 -06:00
parent 566e86bec2
commit e32454978c
53 changed files with 683 additions and 0 deletions

View File

@@ -0,0 +1,164 @@
.. _doc_first_3d_game_game_area:
Setting up the game area
========================
In this first part, we're going to set up the game area. Lets get started by
importing the start assets and setting up the game scene.
Weve prepared a Godot project with the 3D models and sounds well use for this
tutorial, linked in the index page. If you haven't done so yet, you can download
the archive here: `Squash the Creeps assets
<https://github.com/GDQuest/godot-3d-dodge-the-creeps/releases/tag/1.0.0>`__.
Once you downloaded it, extract the .zip archive on your computer. Open the
Godot project manager and click the *Import* button.
|image1|
In the import popup, enter the full path to the freshly created directory
``squash_the_creeps_start/``. You can click the *Browse* button on the right to
open a file browser and navigate to the ``project.godot`` file the folder
contains.
|image2|
Click *Import & Edit* to open the project in the editor.
|image3|
The start project contains an icon and two folders: ``art/`` and ``fonts/``.
There, you will find the art assets and music well use in the game.
|image4|
There are two 3D models, ``player.glb`` and ``mob.glb``, some materials that
belong to these models, and a music track.
Setting up the playable area
----------------------------
Were going to create our main scene with a plain *Node* as its root. In the
*Scene* dock, click the *Add Node* button represented by a “+” icon in the
top-left and double-click on *Node*. Name the node “Main”. Alternatively, to add
a node to the scene, you can press Ctrl a (or Cmd a on MacOS).
|image5|
Save the scene as ``Main.tscn`` by pressing Ctrl s (Cmd s on MacOS).
Well start by adding a floor thatll prevent the characters from falling. To
create static colliders like the floor, walls, or ceilings, you can use
*StaticBody* nodes. They require a *CollisionShape* node as their child to
define the collision area. With the *Main* node selected, add a *StaticBody*
node, then a *CollisionShape*. Rename the *StaticBody* as *Ground*.
|image6|
A warning sign next to the *CollisionShape* appears because we havent defined
its shape. If you click the icon, a popup appears to give you more information.
|image7|
To create a shape, with the *CollisionShape* selected, head to the *Inspector*
and click the *[empty]* field next to the *Shape* property. Create a new *Box
Shape*.
|image8|
The box shape is perfect for flat ground and walls. Its thickness makes it
reliable to block even fast-moving objects.
A boxs wireframe appears in the viewport with three orange dots. You can click
and drag these to edit the shapes extents interactively. We can also precisely
set the size in the inspector. Click on the *BoxShape* to expand the resource.
Set its *Extents* to ``30`` on the X axis, ``1`` for the Y axis, and ``30`` for
the Z axis.
|image9|
.. note::
In 3D, translation and size units are in meters. The boxs total size is
twice its extents: ``60`` by ``60`` meters on the ground plane and ``2``
units tall. The ground plane is defined by the X and Z axes, while the Y
axis represents the height.
Collision shapes are invisible. We need to add a visual floor that goes along
with it. Select the *Ground* node and add a *MeshInstance* as its child.
|image10|
In the *Inspector*, click on the field next to *Mesh* and create a *CubeMesh*
resource to create a visible cube.
|image11|
Once again, its too small by default. Click the cube icon to expand the
resource and set its *Size* to ``60``, ``2`` ``, and ``60``. As the cube
resource works with a size rather than extents, we need to use these values so
it matches our collision shape.
|image12|
You should see a wide grey slab that covers the grid and blue and red axes in
the viewport.
Were going to move the ground down so we can see the floor grid. Select the
*Ground* node, hold the Ctrl key down to turn on grid snapping (Cmd on MacOS),
and click and drag down on the Y axis. Its the green arrow in the move gizmo.
|image13|
.. note::
If you can't see the 3D object manipulator like on the image above, ensure
the *Select Mode* is active in the toolbar above the view.
|image14|
Move the ground down ``1`` meter. A label in the bottom-left corner of the
viewport tells you how much youre translating the node.
|image15|
.. note::
Moving the *Ground* node down moves both children along with it.
Ensure you move the *Ground* node, **not** the *MeshInstance* or the
*CollisionShape*.
Lets add a directional light so our scene isnt all grey. Select the *Main*
node and add a *DirectionalLight* as a child of it. We need to move it and
rotate it. Move it up by clicking and dragging on the manipulators green arrow
and click and drag on the red arc to rotate it around the X axis, until the
ground is lit.
In the *Inspector*, turn on *Shadow -> Enabled* by clicking the checkbox.
|image16|
At this point, your project should look like this.
|image17|
Thats our starting point. In the next part, we will work on the player scene
and base movement.
.. |image1| image:: img/01.game_setup/01.import_button.png
.. |image2| image:: img/01.game_setup/02.browse_to_project_folder.png
.. |image3| image:: img/01.game_setup/03.import_and_edit.png
.. |image4| image:: img/01.game_setup/04.start_assets.png
.. |image5| image:: img/01.game_setup/05.main_node.png
.. |image6| image:: img/01.game_setup/06.staticbody_node.png
.. |image7| image:: img/01.game_setup/07.collision_shape_warning.png
.. |image8| image:: img/01.game_setup/08.create_box_shape.png
.. |image9| image:: img/01.game_setup/09.box_extents.png
.. |image10| image:: img/01.game_setup/10.mesh_instance.png
.. |image11| image:: img/01.game_setup/11.cube_mesh.png
.. |image12| image:: img/01.game_setup/12.cube_resized.png
.. |image13| image:: img/01.game_setup/13.move_gizmo_y_axis.png
.. |image14| image:: img/01.game_setup/14.select_mode_icon.png
.. |image15| image:: img/01.game_setup/15.translation_amount.png
.. |image16| image:: img/01.game_setup/16.turn_on_shadows.png
.. |image17| image:: img/01.game_setup/17.project_with_light.png

View File

@@ -0,0 +1,177 @@
.. _doc_first_3d_game_player_scene_and_input:
Player scene and input actions
==============================
In the next two lessons, we will design the player scene, register custom input
actions, and code player movement. By the end, youll have a playable character
that moves in eight directions.
.. TODO: add player animated gif?
.. player_movement.gif
Create a new scene by going to the Scene menu in the top-left and clicking *New
Scene*. Create a *KinematicBody* node as the root and name it *Player*.
|image0|
Kinematic bodies are complementary to the area and rigid bodies used in the 2D
game tutorial. Like rigid bodies, they can move and collide with the
environment, but instead of being controlled by the physics engine, you dictate
their movement. You will see how we use the nodes unique features when we code
the jump and squash mechanics.
.. seealso::
To learn more about the different physics node types, see the
:ref:`doc_physics_introduction`.
For now, were going to create a basic rig for our characters 3D model. This
will allow us to rotate the model later via code while it plays an animation.
Add a *Spatial* node as a child of *Player* and name it *Pivot*. Then, in the
FileSystem dock, expand the ``art/`` folder by double-clicking it and drag and
drop ``player.glb`` onto the *Pivot* node.
|image1|
This should instantiate the model as a child of *Pivot*. You can rename it to
*Character*.
|image2|
.. note::
The ``.glb`` files contain 3D scene data based on the open-source GLTF 2.0
specification. Theyre a modern and powerful alternative to a proprietary format
like FBX, which Godot also supports. To produce these files, we designed the
model in `Blender 3D <https://www.blender.org/>`__ and exported it to GLTF.
As with all kinds of physics nodes, we need a collision shape for our character
to collide with the environment. Select the *Player* node again and add a
*CollisionShape*. In the *Inspector*, assign a *SphereShape* to the *Shape*
property. The spheres wireframe appears below the character.
|image3|
It will be the shape the physics engine uses to collide with the environment, so
we want it to better fit the 3D model. Shrink it a bit by dragging the orange
dot in the viewport. My sphere has a radius of about ``0.8`` meters.
Then, move the shape up so its bottom roughly aligns with the grids plane.
|image4|
You can toggle the models visibility by clicking the eye icon next to the
*Character* or the *Pivot* nodes.
|image5|
Save the scene as ``Player.tscn``.
With the nodes ready, we can almost get coding. But first, we need to define
some input actions.
Creating input actions
----------------------
To move the character, we will listen to the players input, like pressing the
arrow keys. In Godot, while we could write all the key bindings in code, theres
a powerful system that allows you to assign a label to a set of keys and
buttons. This simplifies our scripts and makes them more readable.
This system is the Input Map. To access its editor, head to the *Project* menu
and select *Project Settings…*.
|image6|
At the top, there are multiple tabs. Click on *Input Map*. This window allows
you to add new actions at the top; they are your labels. In the bottom part, you
can bind keys to these actions.
|image7|
Godot projects come with some predefined actions designed for user interface
design, which we could use here. But were defining our own to support gamepads.
Were going to name our actions ``move_left``, ``move_right``, ``move_up``,
``move_down``, and ``jump``.
To add an action, write its name in the bar at the top and press Enter.
|image8|
Create the five actions. Your window should have them all listed at the bottom.
|image9|
To bind a key or button to an action, click the “+” button to its right. Do this
for ``move_left`` and in the drop-down menu, click *Key*.
|image10|
This option allows you to add a keyboard input. A popup appears and waits for
you to press a key. Press the left arrow key and click *OK*.
|image11|
Do the same for the A key.
|image12|
Lets now add support for a gamepads left joystick. Click the “+” button again
but this time, select *Joy Axis*.
|image13|
The popup gives you two drop-down menus. On the left, you can select a gamepad
by index. *Device 0* corresponds to the first plugged gamepad, *Device 1*
corresponds to the second, and so on. You can select the joystick and direction
you want to bind to the input action on the right. Leave the default values and
press the *Add* button.
|image14|
Do the same for the other input actions. For example, bind the right arrow, D,
and The left joysticks right axis to ``move_right``. After binding all keys,
your interface should look like this.
|image15|
We have the ``jump`` action left to set up. Bind the Space key and the gamepads
A button. To bind a gamepads button, select the joy button option in the menu.
|image16|
Leave the default values and click the *Add* button.
|image17|
Your jump input action should look like this.
|image18|
Thats all the actions we need for this game. You can use this menu to label any
groups of keys and buttons in your projects.
In the next part, well code and test the players movement.
.. |image0| image:: img/02.player_input/01.new_scene.png
.. |image1| image:: img/02.player_input/02.instantiating_the_model.png
.. |image2| image:: img/02.player_input/03.scene_structure.png
.. |image3| image:: img/02.player_input/04.sphere_shape.png
.. |image4| image:: img/02.player_input/05.moving_the_sphere_up.png
.. |image5| image:: img/02.player_input/06.toggling_visibility.png
.. |image6| image:: img/02.player_input/07.project_settings.png
.. |image7| image:: img/02.player_input/07.input_map_tab.png
.. |image8| image:: img/02.player_input/07.adding_action.png
.. |image9| image:: img/02.player_input/08.actions_list_empty.png
.. |image10| image:: img/02.player_input/08.create_key_action.png
.. |image11| image:: img/02.player_input/09.keyboard_key_popup.png
.. |image12| image:: img/02.player_input/09.keyboard_keys.png
.. |image13| image:: img/02.player_input/10.joy_axis_option.png
.. |image14| image:: img/02.player_input/11.joy_axis_popup.png
.. |image15| image:: img/02.player_input/12.move_inputs_mapped.png
.. |image16| image:: img/02.player_input/13.joy_button_option.png
.. |image17| image:: img/02.player_input/14.add_jump_button.png
.. |image18| image:: img/02.player_input/14.jump_input_action.png

View File

@@ -0,0 +1,280 @@
.. _doc_first_3d_game_player_movement:
Moving the player with code
===========================
Its time to code! Were going to use the input actions we created in the last
part to move the character.
Right-click the *Player* node and select *Attach Script* to add a new script to
it. In the popup, set the *Template* to *Empty* before pressing the *Create*
button.
|image0|
Lets start with the classs properties. Were going to define a movement speed,
a fall acceleration representing gravity, and a velocity well use to move the
character.
::
extends KinematicBody
# How fast the player moves in meters per second.
export var speed = 14
# The downward acceleration when in the air, in meters per second squared.
export var fall_acceleration = 75
var velocity = Vector3.ZERO
These are common properties for a moving body. The ``velocity`` is a 3D vector
combining a speed with a direction. Here, we define it as a property because
were going to build upon its value frame after frame.
.. note::
The values are quite different from 2D code because distances are in meters.
While in 2D, a thousand units (pixels) may only correspond to half of your
screens width, in 3D, its a kilometer.
Lets code the movement now. We start by calculating the input direction vector
using the global ``Input`` object, in ``_physics_process()``.
::
func _physics_process(delta):
# We create a local variable to store the input direction.
var direction = Vector3.ZERO
# We check for each move input and update the direction accordingly.
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_down"):
# Notice how we are working with the vector's x and z axes.
# In 3D, the XZ plane is the ground plane.
direction.z += 1
if Input.is_action_pressed("move_up"):
direction.z -= 1
Here, were going to make all calculations using the ``_physics_process()``
virtual function. Like ``_process()``, it allows you to update the node every
frame, but its designed specifically for physics-related code like moving a
kinematic or rigid body.
.. seealso::
To learn more about the difference between ``_process()`` and
``_physics_process()``, see :ref:`doc_idle_and_physics_processing`.
We start by initializing a ``direction`` variable to ``Vector3.ZERO``. Then, we
check if the player is pressing one or more of the ``move_*`` inputs and update
the vectors ``x`` and ``z`` components accordingly. These correspond to the
ground planes axes.
These four conditions give us eight possibilities and eight possible directions.
In case the player presses, say, both W and D simultaneously, the vector will
have a length of about ``1.4``. But if they press a single key, it will have a
length of ``1``. We want the vectors length to be consistent. To do so, we can
call its ``normalize()`` method.
::
#func _physics_process(delta):
#...
if direction.length() > 0:
direction = direction.normalized()
$Pivot.look_at(translation + direction, Vector3.UP)
Here, we only normalize the vector if the direction has a length greater than
zero, which means the player is pressing a direction key.
In this case, we also get the *Pivot* node and call its ``look_at()`` method.
This method takes a position in space to look at in global coordinates and the
up direction. In this case, we can use the ``Vector3.UP`` constant.
.. note::
A nodes local coordinates, like ``translation``, are relative to their
parent. Global coordinates are relative to the worlds main axes you can see
in the viewport instead.
In 3D, the property that contains a nodes position is ``translation``. By
adding the ``direction`` to it, we get a position to look at thats one meter
away from the *Player*.
Then, we update the velocity. We have to calculate the ground velocity and the
fall speed separately. Be sure to go back one tab so the lines are inside the
``_physics_process()`` function but outside the condition we just wrote.
::
#if direction.length() > 0:
#direction = direction.normalized()
#$Pivot.look_at(translation + direction, Vector3.UP)
# Ground velocity
velocity.x = direction.x * speed
velocity.z = direction.z * speed
# Vertical velocity
velocity.y -= fall_acceleration * delta
# Moving the character
velocity = move_and_slide(velocity, Vector3.UP)
For the vertical velocity, we subtract the fall acceleration multiplied by the
delta time every frame. Notice the use of the ``-=`` operator, which is a
shorthand for ``variable = variable - ...``.
This line of code will cause our character to fall in every frame. This may seem
strange if its already on the floor. But we have to do this for the character
to collide with the ground every.
The physics engine can only detect interactions with walls, the floor, or other
bodies during a given frame if movement and collisions happen. We will use this
property later to code the jump.
On the last line, we call ``KinematicBody.move_and_slide()``. Its a powerful
method of the ``KinematicBody`` class that allows you to move a character
smoothly. If it hits a wall midway through a motion, the engine will try to
smooth it out for you.
The function takes two parameters: our velocity and the up direction. It moves
the character and returns a leftover velocity after applying collisions. When
hitting the floor or a wall, the function will reduce or reset the speed in that
direction from you. In our case, storing the functions returned value prevents
the character from accumulating vertical momentum, which could otherwise get so
big the character would move through the ground slab after a while.
And thats all the code you need to move the character on the floor.
Here is the complete ``Player.gd`` code for reference.
::
extends KinematicBody
# How fast the player moves in meters per second.
export var speed = 14
# The downward acceleration when in the air, in meters per second squared.
export var fall_acceleration = 75
var velocity = Vector3.ZERO
func _physics_process(delta):
var direction = Vector3.ZERO
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_down"):
direction.z += 1
if Input.is_action_pressed("move_up"):
direction.z -= 1
if direction.length() > 0:
direction = direction.normalized()
$Pivot.look_at(translation + direction, Vector3.UP)
velocity.x = direction.x * speed
velocity.z = direction.z * speed
velocity.y -= fall_acceleration * delta
velocity = move_and_slide(velocity, Vector3.UP)
Testing our players movement
-----------------------------
Were going to put our player in the *Main* scene to test it. To do so, we need
to instantiate the player and then add a camera. Unlike in 2D, in 3D, you wont
see anything if your viewport doesnt have a camera pointing at something.
Save your *Player* scene and open the *Main* scene. You can click on the *Main*
tab at the top of the editor to do so.
|image1|
If you closed the scene before, head to the *FileSystem* dock and double-click
``Main.tscn`` to re-open it.
To instantiate the *Player*, right-click on the *Main* node and select *Instance
Child Scene*.
|image2|
In the popup, double-click *Player.tscn*. The character should appear in the
center of the viewport.
Adding a camera
~~~~~~~~~~~~~~~
Lets add the camera next. Like we did with our *Player*\ s *Pivot*, were
going to create a basic rig. Right-click on the *Main* node again and select
*Add Child Node* this time. Create a new *Position3D*, name it *CameraPivot*,
and add a *Camera* node as a child of it. Your scene tree should look like this.
|image3|
Notice the *Preview* checkbox that appears in the top-left when you have the
*Camera* selected. You can click it to preview the in-game camera projection.
|image4|
Were going to use the *Pivot* to rotate the camera as if it was on a crane.
Lets first split the 3D view to be able to freely navigate the scene and see
what the camera sees.
In the toolbar right above the viewport, click on *View*, then *2 Viewports*.
You can also press Ctrl 2 (Cmd 2 on MacOS).
|image5|
On the bottom view, select the *Camera* and turn on camera preview by clicking
the checkbox.
|image6|
In the top view, move the camera about ``19`` units on the Z axis (the blue
one).
|image7|
Heres where the magic happens. Select the *CameraPivot* and rotate it ``45``
degrees around the X axis (using the red circle). Youll see the camera move as
if it was attached to a crane.
|image8|
You can run the scene by pressing F6 and press the arrow keys to move the
character.
|image9|
We can see some empty space around the character due to the perspective
projection. In this game, were going to use an orthographic projection instead
to better frame the gameplay area and make it easier for the player to read
distances.
Select the *Camera* again and in the *Inspector*, set the *Projection* to
*Orthogonal* and the *Size* to ``19``. The character should now look flatter and
the ground should fill the background.
|image10|
With that, we have both player movement and the view in place. Next, we will
work on the monsters.
.. |image0| image:: img/03.player_movement_code/01.attach_script_to_player.png
.. |image1| image:: img/03.player_movement_code/02.clicking_main_tab.png
.. |image2| image:: img/03.player_movement_code/03.instance_child_scene.png
.. |image3| image:: img/03.player_movement_code/04.scene_tree_with_camera.png
.. |image4| image:: img/03.player_movement_code/05.camera_preview_checkbox.png
.. |image5| image:: img/03.player_movement_code/06.two_viewports.png
.. |image6| image:: img/03.player_movement_code/07.camera_preview_checkbox.png
.. |image7| image:: img/03.player_movement_code/08.camera_moved.png
.. |image8| image:: img/03.player_movement_code/09.camera_rotated.png
.. |image9| image:: img/03.player_movement_code/10.camera_perspective.png
.. |image10| image:: img/03.player_movement_code/11.camera_orthographic.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -0,0 +1,61 @@
Your first 3D game
==================
In this step-by-step tutorial series, you will create your first complete 3D
game with Godot. By the end of the series, you will have a simple yet finished
project of your own like the animated gif below.
|image0|
The game well code here is similar to :ref:`doc_your_first_game`, with a twist:
you can now jump and your goal is to squash the creeps. This way, you will both
**recognize patterns** you learned in the previous tutorial and **build upon
them** with new code and features.
You will learn to:
- Work with 3D coordinates with a jumping mechanic.
- Use kinematic bodies to move 3D characters and detect when and how they
collide.
- Use physics layers and a group to detect interactions with specific entities.
- Code basic procedural gameplay by instancing monsters at regular time
intervals.
- Design a movement animation and change its speed at run-time.
- Draw a simple interface on a 3D game.
And more.
This tutorial is for beginners who followed the complete getting started series.
Well start slow with detailed instructions and shorten them as we do similar
steps. If youre an experienced programmer, you can browse the complete demos
source code here: `Squash the Creep source code
<https://github.com/GDQuest/godot-3d-dodge-the-creeps/>`__.
.. note::
You can follow this series without having done the 2D one. However, if
youre new to game development, we recommend you to start with 2D. 3D game
code is always more complex and the 2D series will give you foundations to
follow along more comfortably.
We prepared some game assets so we can jump straight to the code. You can
download them here: `Squash the Creeps assets
<https://github.com/GDQuest/godot-3d-dodge-the-creeps/releases/tag/1.0.0>`__.
We will first work on a basic prototype for the players movement. We will then
add the monsters that well spawn randomly around the screen. After that, well
implement the jump and squashing mechanic before refining the game with some
nice animation. Well wrap up with the score and the retry screen.
Contents
--------
.. toctree::
:maxdepth: 1
:name: toc-learn-introduction
01.game_setup
02.player_input
03.player_movement_code
.. |image0| image:: img/squash-the-creeps-final.gif

View File

@@ -67,6 +67,7 @@ The main documentation for the site is organized into the following sections:
getting_started/introduction/index
getting_started/step_by_step/index
getting_started/first_3d_game/index
.. The sections below are sorted alphabetically. Please keep them that way.