diff --git a/getting_started/first_3d_game/01.game_setup.rst b/getting_started/first_3d_game/01.game_setup.rst new file mode 100644 index 000000000..d79d96d0a --- /dev/null +++ b/getting_started/first_3d_game/01.game_setup.rst @@ -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. Let’s get started by +importing the start assets and setting up the game scene. + +We’ve prepared a Godot project with the 3D models and sounds we’ll 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 +`__. + +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 we’ll 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 +---------------------------- + +We’re 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). + +We’ll start by adding a floor that’ll 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 haven’t 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 box’s wireframe appears in the viewport with three orange dots. You can click +and drag these to edit the shape’s 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 box’s 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, it’s 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. + +We’re 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. It’s 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 you’re 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*. + +Let’s add a directional light so our scene isn’t 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 manipulator’s 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| + +That’s 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 diff --git a/getting_started/first_3d_game/02.player_input.rst b/getting_started/first_3d_game/02.player_input.rst new file mode 100644 index 000000000..238530683 --- /dev/null +++ b/getting_started/first_3d_game/02.player_input.rst @@ -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, you’ll 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 node’s 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, we’re going to create a basic rig for our character’s 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. They’re 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 `__ 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 sphere’s 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 grid’s plane. + +|image4| + +You can toggle the model’s 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 player’s input, like pressing the +arrow keys. In Godot, while we could write all the key bindings in code, there’s +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 we’re defining our own to support gamepads. + +We’re 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| + +Let’s now add support for a gamepad’s 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 joystick’s 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 gamepad’s +A button. To bind a gamepad’s 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| + +That’s 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, we’ll code and test the player’s 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 diff --git a/getting_started/first_3d_game/03.player_movement_code.rst b/getting_started/first_3d_game/03.player_movement_code.rst new file mode 100644 index 000000000..a1e7cb016 --- /dev/null +++ b/getting_started/first_3d_game/03.player_movement_code.rst @@ -0,0 +1,280 @@ +.. _doc_first_3d_game_player_movement: + +Moving the player with code +=========================== + +It’s time to code! We’re 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| + +Let’s start with the class’s properties. We’re going to define a movement speed, +a fall acceleration representing gravity, and a velocity we’ll 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 +we’re 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 + screen’s width, in 3D, it’s a kilometer. + +Let’s 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, we’re going to make all calculations using the ``_physics_process()`` +virtual function. Like ``_process()``, it allows you to update the node every +frame, but it’s 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 vector’s ``x`` and ``z`` components accordingly. These correspond to the +ground plane’s 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 vector’s 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 node’s local coordinates, like ``translation``, are relative to their + parent. Global coordinates are relative to the world’s main axes you can see + in the viewport instead. + +In 3D, the property that contains a node’s position is ``translation``. By +adding the ``direction`` to it, we get a position to look at that’s 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 it’s 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()``. It’s 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 function’s 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 that’s 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 player’s movement +----------------------------- + +We’re 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 won’t +see anything if your viewport doesn’t 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 +~~~~~~~~~~~~~~~ + +Let’s add the camera next. Like we did with our *Player*\ ’s *Pivot*, we’re +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| + +We’re going to use the *Pivot* to rotate the camera as if it was on a crane. +Let’s 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| + +Here’s where the magic happens. Select the *CameraPivot* and rotate it ``45`` +degrees around the X axis (using the red circle). You’ll 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, we’re 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 diff --git a/getting_started/first_3d_game/img/01.game_setup/01.import_button.png b/getting_started/first_3d_game/img/01.game_setup/01.import_button.png new file mode 100644 index 000000000..72d299170 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/01.import_button.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/02.browse_to_project_folder.png b/getting_started/first_3d_game/img/01.game_setup/02.browse_to_project_folder.png new file mode 100644 index 000000000..4e1076705 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/02.browse_to_project_folder.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/03.import_and_edit.png b/getting_started/first_3d_game/img/01.game_setup/03.import_and_edit.png new file mode 100644 index 000000000..8a863c631 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/03.import_and_edit.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/04.start_assets.png b/getting_started/first_3d_game/img/01.game_setup/04.start_assets.png new file mode 100644 index 000000000..95b4f8100 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/04.start_assets.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/05.main_node.png b/getting_started/first_3d_game/img/01.game_setup/05.main_node.png new file mode 100644 index 000000000..0ecfd5b84 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/05.main_node.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/06.staticbody_node.png b/getting_started/first_3d_game/img/01.game_setup/06.staticbody_node.png new file mode 100644 index 000000000..faed0c334 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/06.staticbody_node.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/07.collision_shape_warning.png b/getting_started/first_3d_game/img/01.game_setup/07.collision_shape_warning.png new file mode 100644 index 000000000..db2b35dfe Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/07.collision_shape_warning.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/08.create_box_shape.png b/getting_started/first_3d_game/img/01.game_setup/08.create_box_shape.png new file mode 100644 index 000000000..cbf6e9a16 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/08.create_box_shape.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/09.box_extents.png b/getting_started/first_3d_game/img/01.game_setup/09.box_extents.png new file mode 100644 index 000000000..8cd4765ec Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/09.box_extents.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/10.mesh_instance.png b/getting_started/first_3d_game/img/01.game_setup/10.mesh_instance.png new file mode 100644 index 000000000..f7da07d6b Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/10.mesh_instance.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/11.cube_mesh.png b/getting_started/first_3d_game/img/01.game_setup/11.cube_mesh.png new file mode 100644 index 000000000..2d615d58d Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/11.cube_mesh.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/12.cube_resized.png b/getting_started/first_3d_game/img/01.game_setup/12.cube_resized.png new file mode 100644 index 000000000..a5a3272c6 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/12.cube_resized.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/13.move_gizmo_y_axis.png b/getting_started/first_3d_game/img/01.game_setup/13.move_gizmo_y_axis.png new file mode 100644 index 000000000..1a72939ed Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/13.move_gizmo_y_axis.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/14.select_mode_icon.png b/getting_started/first_3d_game/img/01.game_setup/14.select_mode_icon.png new file mode 100644 index 000000000..6366c72c4 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/14.select_mode_icon.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/15.translation_amount.png b/getting_started/first_3d_game/img/01.game_setup/15.translation_amount.png new file mode 100644 index 000000000..d9fd97e1d Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/15.translation_amount.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/16.turn_on_shadows.png b/getting_started/first_3d_game/img/01.game_setup/16.turn_on_shadows.png new file mode 100644 index 000000000..3fd7f0ea4 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/16.turn_on_shadows.png differ diff --git a/getting_started/first_3d_game/img/01.game_setup/17.project_with_light.png b/getting_started/first_3d_game/img/01.game_setup/17.project_with_light.png new file mode 100644 index 000000000..493fc7912 Binary files /dev/null and b/getting_started/first_3d_game/img/01.game_setup/17.project_with_light.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/01.new_scene.png b/getting_started/first_3d_game/img/02.player_input/01.new_scene.png new file mode 100644 index 000000000..e7f8cb650 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/01.new_scene.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/02.instantiating_the_model.png b/getting_started/first_3d_game/img/02.player_input/02.instantiating_the_model.png new file mode 100644 index 000000000..501649fb6 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/02.instantiating_the_model.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/03.scene_structure.png b/getting_started/first_3d_game/img/02.player_input/03.scene_structure.png new file mode 100644 index 000000000..10de5c3f9 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/03.scene_structure.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/04.sphere_shape.png b/getting_started/first_3d_game/img/02.player_input/04.sphere_shape.png new file mode 100644 index 000000000..e64f36ceb Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/04.sphere_shape.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/05.moving_the_sphere_up.png b/getting_started/first_3d_game/img/02.player_input/05.moving_the_sphere_up.png new file mode 100644 index 000000000..ae2490239 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/05.moving_the_sphere_up.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/06.toggling_visibility.png b/getting_started/first_3d_game/img/02.player_input/06.toggling_visibility.png new file mode 100644 index 000000000..f951483cd Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/06.toggling_visibility.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/07.adding_action.png b/getting_started/first_3d_game/img/02.player_input/07.adding_action.png new file mode 100644 index 000000000..1e087973f Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/07.adding_action.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/07.input_map_tab.png b/getting_started/first_3d_game/img/02.player_input/07.input_map_tab.png new file mode 100644 index 000000000..eb971e3f9 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/07.input_map_tab.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/07.project_settings.png b/getting_started/first_3d_game/img/02.player_input/07.project_settings.png new file mode 100644 index 000000000..0ca63b6a8 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/07.project_settings.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/08.actions_list_empty.png b/getting_started/first_3d_game/img/02.player_input/08.actions_list_empty.png new file mode 100644 index 000000000..b97dc0a67 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/08.actions_list_empty.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/08.create_key_action.png b/getting_started/first_3d_game/img/02.player_input/08.create_key_action.png new file mode 100644 index 000000000..555f9c455 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/08.create_key_action.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/09.keyboard_key_popup.png b/getting_started/first_3d_game/img/02.player_input/09.keyboard_key_popup.png new file mode 100644 index 000000000..728ab408a Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/09.keyboard_key_popup.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/09.keyboard_keys.png b/getting_started/first_3d_game/img/02.player_input/09.keyboard_keys.png new file mode 100644 index 000000000..42e9a95a9 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/09.keyboard_keys.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/10.joy_axis_option.png b/getting_started/first_3d_game/img/02.player_input/10.joy_axis_option.png new file mode 100644 index 000000000..4d09320b8 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/10.joy_axis_option.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/11.joy_axis_popup.png b/getting_started/first_3d_game/img/02.player_input/11.joy_axis_popup.png new file mode 100644 index 000000000..3fcf6fedb Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/11.joy_axis_popup.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/12.move_inputs_mapped.png b/getting_started/first_3d_game/img/02.player_input/12.move_inputs_mapped.png new file mode 100644 index 000000000..3606461df Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/12.move_inputs_mapped.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/13.joy_button_option.png b/getting_started/first_3d_game/img/02.player_input/13.joy_button_option.png new file mode 100644 index 000000000..3c6af9fbc Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/13.joy_button_option.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/14.add_jump_button.png b/getting_started/first_3d_game/img/02.player_input/14.add_jump_button.png new file mode 100644 index 000000000..cb2d3db96 Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/14.add_jump_button.png differ diff --git a/getting_started/first_3d_game/img/02.player_input/14.jump_input_action.png b/getting_started/first_3d_game/img/02.player_input/14.jump_input_action.png new file mode 100644 index 000000000..555f8070a Binary files /dev/null and b/getting_started/first_3d_game/img/02.player_input/14.jump_input_action.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/01.attach_script_to_player.png b/getting_started/first_3d_game/img/03.player_movement_code/01.attach_script_to_player.png new file mode 100644 index 000000000..856ba4688 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/01.attach_script_to_player.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/02.clicking_main_tab.png b/getting_started/first_3d_game/img/03.player_movement_code/02.clicking_main_tab.png new file mode 100644 index 000000000..3cd87786a Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/02.clicking_main_tab.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/03.instance_child_scene.png b/getting_started/first_3d_game/img/03.player_movement_code/03.instance_child_scene.png new file mode 100644 index 000000000..e5256edb8 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/03.instance_child_scene.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/04.scene_tree_with_camera.png b/getting_started/first_3d_game/img/03.player_movement_code/04.scene_tree_with_camera.png new file mode 100644 index 000000000..1e021e496 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/04.scene_tree_with_camera.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/05.camera_preview_checkbox.png b/getting_started/first_3d_game/img/03.player_movement_code/05.camera_preview_checkbox.png new file mode 100644 index 000000000..a08c85875 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/05.camera_preview_checkbox.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/06.two_viewports.png b/getting_started/first_3d_game/img/03.player_movement_code/06.two_viewports.png new file mode 100644 index 000000000..509e9c04a Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/06.two_viewports.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/07.camera_preview_checkbox.png b/getting_started/first_3d_game/img/03.player_movement_code/07.camera_preview_checkbox.png new file mode 100644 index 000000000..753201b09 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/07.camera_preview_checkbox.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/08.camera_moved.png b/getting_started/first_3d_game/img/03.player_movement_code/08.camera_moved.png new file mode 100644 index 000000000..93eec8cd1 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/08.camera_moved.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/09.camera_rotated.png b/getting_started/first_3d_game/img/03.player_movement_code/09.camera_rotated.png new file mode 100644 index 000000000..ad91884f7 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/09.camera_rotated.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/10.camera_perspective.png b/getting_started/first_3d_game/img/03.player_movement_code/10.camera_perspective.png new file mode 100644 index 000000000..7a056d078 Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/10.camera_perspective.png differ diff --git a/getting_started/first_3d_game/img/03.player_movement_code/11.camera_orthographic.png b/getting_started/first_3d_game/img/03.player_movement_code/11.camera_orthographic.png new file mode 100644 index 000000000..cf2c2f6ee Binary files /dev/null and b/getting_started/first_3d_game/img/03.player_movement_code/11.camera_orthographic.png differ diff --git a/getting_started/first_3d_game/img/squash-the-creeps-final.gif b/getting_started/first_3d_game/img/squash-the-creeps-final.gif new file mode 100644 index 000000000..f0ea80757 Binary files /dev/null and b/getting_started/first_3d_game/img/squash-the-creeps-final.gif differ diff --git a/getting_started/first_3d_game/index.rst b/getting_started/first_3d_game/index.rst new file mode 100644 index 000000000..03032d20f --- /dev/null +++ b/getting_started/first_3d_game/index.rst @@ -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 we’ll 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. +We’ll start slow with detailed instructions and shorten them as we do similar +steps. If you’re an experienced programmer, you can browse the complete demo’s +source code here: `Squash the Creep source code +`__. + +.. note:: + + You can follow this series without having done the 2D one. However, if + you’re 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 +`__. + +We will first work on a basic prototype for the player’s movement. We will then +add the monsters that we’ll spawn randomly around the screen. After that, we’ll +implement the jump and squashing mechanic before refining the game with some +nice animation. We’ll 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 diff --git a/index.rst b/index.rst index 6b09b29b6..729e40015 100644 --- a/index.rst +++ b/index.rst @@ -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.