Browse Source

Update "Dodge the Creeps" for 3.1

Chris Bradfield 6 years ago
parent
commit
93569bad53

BIN
getting_started/step_by_step/img/custom_font1.png


BIN
getting_started/step_by_step/img/custom_font2.png


BIN
getting_started/step_by_step/img/export_variable.png


BIN
getting_started/step_by_step/img/player_coll_shape.png


BIN
getting_started/step_by_step/img/player_scale.png


BIN
getting_started/step_by_step/img/set_collision_mask.png


BIN
getting_started/step_by_step/img/start_button_shortcut.png


+ 111 - 128
getting_started/step_by_step/your_first_game.rst

@@ -37,7 +37,7 @@ using to make the game. Unzip these files to your project folder.
 
 
 This game will use portrait mode, so we need to adjust the size of the
 This game will use portrait mode, so we need to adjust the size of the
 game window. Click on Project -> Project Settings -> Display -> Window and
 game window. Click on Project -> Project Settings -> Display -> Window and
-set "Width" to 480 and "Height" to 720.
+set "Width" to ``480`` and "Height" to ``720``.
 
 
 Organizing the project
 Organizing the project
 ~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -46,9 +46,9 @@ In this project, we will make 3 independent scenes: ``Player``,
 ``Mob``, and ``HUD``, which we will combine into the game's ``Main``
 ``Mob``, and ``HUD``, which we will combine into the game's ``Main``
 scene. In a larger project, it might be useful to make folders to hold
 scene. In a larger project, it might be useful to make folders to hold
 the various scenes and their scripts, but for this relatively small
 the various scenes and their scripts, but for this relatively small
-game, you can save your scenes and scripts in the root folder,
+game, you can save your scenes and scripts in the project's root folder,
 referred to as ``res://``.  You can see your project folders in the FileSystem
 referred to as ``res://``.  You can see your project folders in the FileSystem
-Dock in the upper left corner:
+Dock in the lower left corner:
 
 
 .. image:: img/filesystem_dock.png
 .. image:: img/filesystem_dock.png
 
 
@@ -69,7 +69,8 @@ node to the scene.
 
 
 With ``Area2D`` we can detect objects that overlap or run into the player.
 With ``Area2D`` we can detect objects that overlap or run into the player.
 Change its name to ``Player`` by clicking on the node's name.
 Change its name to ``Player`` by clicking on the node's name.
-This is the scene's root node. We can add additional nodes to the player to add functionality.
+This is the scene's root node. We can add additional nodes to the player to add
+functionality.
 
 
 Before we add any children to the ``Player`` node, we want to make sure we don't
 Before we add any children to the ``Player`` node, we want to make sure we don't
 accidentally move or resize them by clicking on them. Select the node and
 accidentally move or resize them by clicking on them. Select the node and
@@ -82,7 +83,7 @@ Save the scene. Click Scene -> Save, or press ``Ctrl+S`` on Windows/Linux or ``C
 
 
 .. note:: For this project, we will be following the Godot naming conventions.
 .. note:: For this project, we will be following the Godot naming conventions.
 
 
-          - **GDScript**: Classes (nodes) use PascalCase, variables and 
+          - **GDScript**: Classes (nodes) use PascalCase, variables and
             functions use snake_case, and constants use ALL_CAPS (See
             functions use snake_case, and constants use ALL_CAPS (See
             :ref:`doc_gdscript_styleguide`).
             :ref:`doc_gdscript_styleguide`).
 
 
@@ -102,7 +103,7 @@ An ``AnimatedSprite`` requires a :ref:`SpriteFrames <class_SpriteFrames>` resour
 list of the animations it can display. To create one, find the
 list of the animations it can display. To create one, find the
 ``Frames`` property in the Inspector and click "<null>" ->
 ``Frames`` property in the Inspector and click "<null>" ->
 "New SpriteFrames". Next, in the same location, click
 "New SpriteFrames". Next, in the same location, click
-``<SpriteFrames>`` to open the "SpriteFrames" panel:
+``<SpriteFrames>``, then click "Open Editor" to open the "SpriteFrames" panel:
 
 
 .. image:: img/spriteframes_panel.png
 .. image:: img/spriteframes_panel.png
 
 
@@ -125,13 +126,11 @@ Finally, add a :ref:`CollisionShape2D <class_CollisionShape2D>` as a child
 of ``Player``. This will determine the player's "hitbox", or the
 of ``Player``. This will determine the player's "hitbox", or the
 bounds of its collision area. For this character, a ``CapsuleShape2D``
 bounds of its collision area. For this character, a ``CapsuleShape2D``
 node gives the best fit, so next to "Shape" in the Inspector, click
 node gives the best fit, so next to "Shape" in the Inspector, click
-"<null>"" -> "New CapsuleShape2D".  Resize the shape to cover the sprite:
+"<null>"" -> "New CapsuleShape2D".  Using the two size handles, resize the
+shape to cover the sprite:
 
 
 .. image:: img/player_coll_shape.png
 .. image:: img/player_coll_shape.png
 
 
-.. warning:: Don't scale the shape's outline! Only use the
-             size handles (circled in red) to adjust the shape!
-
 When you're finished, your ``Player`` scene should look like this:
 When you're finished, your ``Player`` scene should look like this:
 
 
 .. image:: img/player_scene_nodes.png
 .. image:: img/player_scene_nodes.png
@@ -163,7 +162,7 @@ Start by declaring the member variables this object will need:
 
 
     extends Area2D
     extends Area2D
 
 
-    export (int) var speed  # How fast the player will move (pixels/sec).
+    export var speed = 400  # How fast the player will move (pixels/sec).
     var screensize  # Size of the game window.
     var screensize  # Size of the game window.
 
 
  .. code-tab:: csharp
  .. code-tab:: csharp
@@ -171,7 +170,7 @@ Start by declaring the member variables this object will need:
     public class Player : Area2D
     public class Player : Area2D
     {
     {
         [Export]
         [Export]
-        public int Speed; // How fast the player will move (pixels/sec).
+        public int Speed = 400; // How fast the player will move (pixels/sec).
 
 
         private Vector2 _screenSize; // Size of the game window.
         private Vector2 _screenSize; // Size of the game window.
     }
     }
@@ -180,7 +179,9 @@ Start by declaring the member variables this object will need:
 Using the ``export`` keyword on the first variable ``speed`` allows us to
 Using the ``export`` keyword on the first variable ``speed`` allows us to
 set its value in the Inspector. This can be handy for values that you
 set its value in the Inspector. This can be handy for values that you
 want to be able to adjust just like a node's built-in properties. Click on
 want to be able to adjust just like a node's built-in properties. Click on
-the ``Player`` node and set the speed property to ``400``.
+the ``Player`` node and you'll see the property now appears in the "Script
+Variables" section of the Inspector. Remember, if you change the value here, it
+will override the value written in the script.
 
 
 .. warning:: If you're using C#, you need to (re)build the project assemblies
 .. warning:: If you're using C#, you need to (re)build the project assemblies
              whenever you want to see new export variables or signals. This
              whenever you want to see new export variables or signals. This
@@ -208,7 +209,8 @@ which is a good time to find the size of the game window:
 
 
 Now we can use the ``_process()`` function to define what the player will do.
 Now we can use the ``_process()`` function to define what the player will do.
 ``_process()`` is called every frame, so we'll use it to update
 ``_process()`` is called every frame, so we'll use it to update
-elements of our game, which we expect will change often. Here we'll make it:
+elements of our game, which we expect will change often. For the player, we
+need to do the following:
 
 
 - Check for input.
 - Check for input.
 - Move in the given direction.
 - Move in the given direction.
@@ -216,7 +218,7 @@ elements of our game, which we expect will change often. Here we'll make it:
 
 
 First, we need to check for input - is the player pressing a key? For
 First, we need to check for input - is the player pressing a key? For
 this game, we have 4 direction inputs to check. Input actions are defined
 this game, we have 4 direction inputs to check. Input actions are defined
-in the Project Settings under "Input Map". You can define custom events and
+in the Project Settings under "Input Map". Here, you can define custom events and
 assign different keys, mouse events, or other inputs to them. For this demo,
 assign different keys, mouse events, or other inputs to them. For this demo,
 we will use the default events that are assigned to the arrow keys on the
 we will use the default events that are assigned to the arrow keys on the
 keyboard.
 keyboard.
@@ -229,7 +231,7 @@ or ``false`` if it isn't.
  .. code-tab:: gdscript GDScript
  .. code-tab:: gdscript GDScript
 
 
     func _process(delta):
     func _process(delta):
-        var velocity = Vector2() # The player's movement vector.
+        var velocity = Vector2()  # The player's movement vector.
         if Input.is_action_pressed("ui_right"):
         if Input.is_action_pressed("ui_right"):
             velocity.x += 1
             velocity.x += 1
         if Input.is_action_pressed("ui_left"):
         if Input.is_action_pressed("ui_left"):
@@ -283,11 +285,12 @@ or ``false`` if it isn't.
         }
         }
     }
     }
 
 
-We check each input and add/subtract from the ``velocity`` to obtain a
-total direction. For example, if you hold ``right`` and ``down`` at
-the same time, the resulting ``velocity`` vector will be ``(1, 1)``. In
-this case, since we're adding a horizontal and a vertical movement, the
-player would move *faster* than if it just moved horizontally.
+We start by setting the ``velocity`` to ``(0, 0)`` - by default the player
+should not be moving. Then we check each input and add/subtract from the
+``velocity`` to obtain a total direction. For example, if you hold ``right``
+and ``down`` at the same time, the resulting ``velocity`` vector will be
+``(1, 1)``. In this case, since we're adding a horizontal and a vertical
+movement, the player would move *faster* than if it just moved horizontally.
 
 
 We can prevent that if we *normalize* the velocity, which means we set
 We can prevent that if we *normalize* the velocity, which means we set
 its *length* to ``1``, and multiply by the desired speed. This means no
 its *length* to ``1``, and multiply by the desired speed. This means no
@@ -300,13 +303,13 @@ more fast diagonal movement.
 We also check whether the player is moving so we can start or stop the
 We also check whether the player is moving so we can start or stop the
 AnimatedSprite animation.
 AnimatedSprite animation.
 
 
-.. tip:: ``$`` returns the node at the relative path from this node, or returns ``null`` if the node is not found.
+.. tip:: In GDScript, ``$`` returns the node at the relative path from the current node, or returns ``null`` if the node is not found.
          Since AnimatedSprite is a child of the current node, we can use ``$AnimatedSprite``.
          Since AnimatedSprite is a child of the current node, we can use ``$AnimatedSprite``.
 
 
          ``$`` is shorthand for ``get_node()``.
          ``$`` is shorthand for ``get_node()``.
          So in the code above, ``$AnimatedSprite.play()`` is the same as ``get_node("AnimatedSprite").play()``.
          So in the code above, ``$AnimatedSprite.play()`` is the same as ``get_node("AnimatedSprite").play()``.
 
 
-Now that we have a movement direction, we can update ``Player``'s position
+Now that we have a movement direction, we can update the player's position
 and use ``clamp()`` to prevent it from leaving the screen by adding the following
 and use ``clamp()`` to prevent it from leaving the screen by adding the following
 to the bottom of the ``_process`` function:
 to the bottom of the ``_process`` function:
 
 
@@ -329,8 +332,9 @@ to the bottom of the ``_process`` function:
 .. tip:: *Clamping* a value means restricting it to a given range.
 .. tip:: *Clamping* a value means restricting it to a given range.
 
 
 Click "Play Scene" (``F6``) and confirm you can move the player
 Click "Play Scene" (``F6``) and confirm you can move the player
-around the screen in all directions. The console output that opens upon playing the scene can be closed
-by clicking ``Output`` (which should be highlighted in blue) in the lower left of the Bottom Panel.
+around the screen in all directions. The console output that opens upon playing
+the scene can be closed by clicking ``Output`` (which should be highlighted in
+blue) in the lower left of the Bottom Panel.
 
 
 .. warning:: If you get an error in the "Debugger" panel that refers to a "null instance",
 .. warning:: If you get an error in the "Debugger" panel that refers to a "null instance",
              this likely means you spelled the node name wrong. Node names are case-sensitive
              this likely means you spelled the node name wrong. Node names are case-sensitive
@@ -423,7 +427,7 @@ Add the following at the top of the script, after ``extends Area2d``:
  .. code-tab:: csharp
  .. code-tab:: csharp
 
 
     // Don't forget to rebuild the project so the editor knows about the new signal.
     // Don't forget to rebuild the project so the editor knows about the new signal.
-    
+
     [Signal]
     [Signal]
     public delegate void Hit();
     public delegate void Hit();
 
 
@@ -439,8 +443,9 @@ going to be ``RigidBody2D`` nodes, we want the
 ``body_entered( Object body )`` signal; this will be emitted when a
 ``body_entered( Object body )`` signal; this will be emitted when a
 body contacts the player. Click "Connect.." and then "Connect" again on
 body contacts the player. Click "Connect.." and then "Connect" again on
 the "Connecting Signal" window. We don't need to change any of these
 the "Connecting Signal" window. We don't need to change any of these
-settings - Godot will automatically create a function called
-``_on_Player_body_entered`` in your player's script.
+settings - Godot will automatically create a function in your player's script.
+This function will be called whenever the signal is emitted - it *handles* the
+signal.
 
 
 .. tip:: When connecting a signal, instead of having Godot create a
 .. tip:: When connecting a signal, instead of having Godot create a
          function for you, you can also give the name of an existing
          function for you, you can also give the name of an existing
@@ -452,9 +457,9 @@ Add this code to the function:
  .. code-tab:: gdscript GDScript
  .. code-tab:: gdscript GDScript
 
 
     func _on_Player_body_entered(body):
     func _on_Player_body_entered(body):
-        hide() # Player disappears after being hit.
+        hide()  # Player disappears after being hit.
         emit_signal("hit")
         emit_signal("hit")
-        $CollisionShape2D.disabled = true
+        $CollisionShape2D.call_deferred("set_disabled", true)
 
 
  .. code-tab:: csharp
  .. code-tab:: csharp
 
 
@@ -465,9 +470,14 @@ Add this code to the function:
         GetNode<CollisionShape2D>("CollisionShape2D").Disabled = true;
         GetNode<CollisionShape2D>("CollisionShape2D").Disabled = true;
     }
     }
 
 
-.. Note:: Disabling the area's collision shape means
-          it won't detect collisions. By turning it off, we make
-          sure we don't trigger the ``hit`` signal more than once.
+Each time an enemy hits the player, the signal is going to be emitted. We need
+to disable the player's collision so that we don't trigger the ``hit`` signal
+more than once.
+
+.. Note:: Disabling the area's collision shape can cause an error if it happens
+          in the middle of the engine's collision processing. Using ``call_deferred()``
+          allows us to have Godot wait to disable the shape until it's safe to
+          do so.
 
 
 The last piece for our player is to add a function we can call to reset
 The last piece for our player is to add a function we can call to reset
 the player when starting a new game.
 the player when starting a new game.
@@ -549,8 +559,8 @@ Add a script to the ``Mob`` and add the following member variables:
 
 
     extends RigidBody2D
     extends RigidBody2D
 
 
-    export (int) var min_speed # Minimum speed range.
-    export (int) var max_speed # Maximum speed range.
+    export var min_speed = 150  # Minimum speed range.
+    export var max_speed = 250  # Maximum speed range.
     var mob_types = ["walk", "swim", "fly"]
     var mob_types = ["walk", "swim", "fly"]
 
 
  .. code-tab:: csharp
  .. code-tab:: csharp
@@ -560,19 +570,19 @@ Add a script to the ``Mob`` and add the following member variables:
         // Don't forget to rebuild the project so the editor knows about the new export variables.
         // Don't forget to rebuild the project so the editor knows about the new export variables.
 
 
         [Export]
         [Export]
-        public int MinSpeed; // Minimum speed range.
+        public int MinSpeed = 150; // Minimum speed range.
 
 
         [Export]
         [Export]
-        public int MaxSpeed; // Maximum speed range.
+        public int MaxSpeed = 250; // Maximum speed range.
 
 
         private String[] _mobTypes = {"walk", "swim", "fly"};
         private String[] _mobTypes = {"walk", "swim", "fly"};
     }
     }
 
 
-We'll pick a random value between ``min_speed`` and ``max_speed`` for
-how fast each mob will move (it would be boring if they were all moving
-at the same speed). Set them to ``150`` and ``250`` in the Inspector. We
-also have an array containing the names of the three animations, which
-we'll use to select a random one.
+When we spawn a mob, we'll pick a random value between ``min_speed`` and
+``max_speed`` for how fast each mob will move (it would be boring if they
+were all moving at the same speed). We also have an array containing the names
+of the three animations, which we'll use to select a random one. Make sure
+you've spelled these the same in the script and in the SpriteFrames resource.
 
 
 Now let's look at the rest of the script. In ``_ready()`` we randomly
 Now let's look at the rest of the script. In ``_ready()`` we randomly
 choose one of the three animation types:
 choose one of the three animation types:
@@ -699,7 +709,7 @@ instance.
     public class Main : Node
     public class Main : Node
     {
     {
         // Don't forget to rebuild the project so the editor knows about the new export variable.
         // Don't forget to rebuild the project so the editor knows about the new export variable.
-    
+
         [Export]
         [Export]
         public PackedScene Mob;
         public PackedScene Mob;
 
 
@@ -759,9 +769,9 @@ function to set everything up for a new game:
         GetNode<Timer>("StartTimer").Start();
         GetNode<Timer>("StartTimer").Start();
     }
     }
 
 
-Now connect the ``timeout()`` signal of each of the Timer nodes (``StartTimer``, ``ScoreTimer`` ,and ``MobTimer``).
-``StartTimer`` will start the other two timers. ``ScoreTimer`` will
-increment the score by 1.
+Now connect the ``timeout()`` signal of each of the Timer nodes (``StartTimer``,
+``ScoreTimer`` ,and ``MobTimer``) to the main script. ``StartTimer`` will start
+the other two timers. ``ScoreTimer`` will increment the score by 1.
 
 
 .. tabs::
 .. tabs::
  .. code-tab:: gdscript GDScript
  .. code-tab:: gdscript GDScript
@@ -816,8 +826,9 @@ Add the following code:
         # Add some randomness to the direction.
         # Add some randomness to the direction.
         direction += rand_range(-PI / 4, PI / 4)
         direction += rand_range(-PI / 4, PI / 4)
         mob.rotation = direction
         mob.rotation = direction
-        # Choose the velocity.
-        mob.set_linear_velocity(Vector2(rand_range(mob.min_speed, mob.max_speed), 0).rotated(direction))
+        # Set the velocity (speed & direction).
+        mob.linear_velocity = Vector2(rand_range(mob.min_speed, mob.max_speed), 0)
+        mob.linear_velocity = mob.linear_velocity.rotated(direction)
 
 
  .. code-tab:: csharp
  .. code-tab:: csharp
 
 
@@ -880,6 +891,22 @@ Create the following as children of the ``HUD`` node:
 -  :ref:`Button <class_Button>` named ``StartButton``.
 -  :ref:`Button <class_Button>` named ``StartButton``.
 -  :ref:`Timer <class_Timer>` named ``MessageTimer``.
 -  :ref:`Timer <class_Timer>` named ``MessageTimer``.
 
 
+Click on the ``ScoreLabel`` and type a number into the _Text_ field in the
+Inspector. The default font for ``Control`` nodes is small and doesn't scale
+well. There is a font file included in the game assets called
+"Xolonium-Regular.ttf". To use this font, do the following for each of
+the three ``Control`` nodes:
+
+1. Under "Custom Fonts", choose "New DynamicFont"
+
+.. image:: img/custom_font1.png
+
+2. Click on the "DynamicFont" you added, and under "Font/Font Data",
+   choose "Load" and select the "Xolonium-Regular.ttf" file. You must
+   also set the font's ``Size``. A setting of ``64`` works well.
+
+.. image:: img/custom_font2.png
+
 .. note:: **Anchors and Margins:** ``Control`` nodes have a position and size,
 .. note:: **Anchors and Margins:** ``Control`` nodes have a position and size,
           but they also have anchors and margins. Anchors define the
           but they also have anchors and margins. Anchors define the
           origin - the reference point for the edges of the node. Margins
           origin - the reference point for the edges of the node. Margins
@@ -898,60 +925,27 @@ placement, use the following settings:
 ScoreLabel
 ScoreLabel
 ~~~~~~~~~~
 ~~~~~~~~~~
 
 
--  ``Layout``: "Center Top"
--  ``Margin``:
-
-   -  Left: ``-25``
-   -  Top: ``0``
-   -  Right: ``25``
-   -  Bottom: ``100``
-
--  Text: ``0``
+-  *Text* : ``0``
+-  *Layout* : "Top Wide"
+-  *Align* : "Center"
 
 
 MessageLabel
 MessageLabel
 ~~~~~~~~~~~~
 ~~~~~~~~~~~~
 
 
--  ``Layout``: "Center"
--  ``Margin``:
-
-   -  Left: ``-200``
-   -  Top: ``-150``
-   -  Right: ``200``
-   -  Bottom: ``0``
-
--  Text: ``Dodge the Creeps!``
+-  *Text* : ``Dodge the Creeps!``
+-  *Layout* : "HCenter Wide"
+-  *Align* : "Center"
 
 
 StartButton
 StartButton
 ~~~~~~~~~~~
 ~~~~~~~~~~~
 
 
--  ``Layout``: "Center Bottom"
--  ``Margin``:
+-  *Text* : ``Start``
+-  *Layout* : "Center Bottom"
+-  *Margin* :
 
 
-   -  Left: ``-100``
    -  Top: ``-200``
    -  Top: ``-200``
-   -  Right: ``100``
    -  Bottom: ``-100``
    -  Bottom: ``-100``
 
 
--  Text: ``Start``
-
-To make the text of the ``MessageLabel`` fit the game's window click
-the small icon next to your text property. This will open up a new
-window where you can add a new line between the words.
-The default font for ``Control`` nodes is small and doesn't scale
-well. There is a font file included in the game assets called
-"Xolonium-Regular.ttf". To use this font, do the following for each of
-the three ``Control`` nodes:
-
-1. Under "Custom Fonts", choose "New DynamicFont"
-
-.. image:: img/custom_font1.png
-
-2. Click on the "DynamicFont" you added, and under "Font Data",
-   choose "Load" and select the "Xolonium-Regular.ttf" file. You must
-   also set the font's ``Size``. A setting of ``64`` works well.
-
-.. image:: img/custom_font2.png
-
 Now add this script to ``HUD``:
 Now add this script to ``HUD``:
 
 
 .. tabs::
 .. tabs::
@@ -1003,9 +997,10 @@ temporarily, such as "Get Ready". On the ``MessageTimer``, set the
     func show_game_over():
     func show_game_over():
         show_message("Game Over")
         show_message("Game Over")
         yield($MessageTimer, "timeout")
         yield($MessageTimer, "timeout")
-        $StartButton.show()
         $MessageLabel.text = "Dodge the\nCreeps!"
         $MessageLabel.text = "Dodge the\nCreeps!"
         $MessageLabel.show()
         $MessageLabel.show()
+        yield(get_tree().create_timer(1), 'timeout')
+        $StartButton.show()
 
 
  .. code-tab:: csharp
  .. code-tab:: csharp
 
 
@@ -1024,8 +1019,13 @@ temporarily, such as "Get Ready". On the ``MessageTimer``, set the
     }
     }
 
 
 This function is called when the player loses. It will show "Game
 This function is called when the player loses. It will show "Game
-Over" for 2 seconds, then return to the title screen and show the
-"Start" button.
+Over" for 2 seconds, then return to the title screen and, after a brief pause,
+show the "Start" button.
+
+.. note:: When you need to pause for a brief time, an alternative to using a
+          Timer node is to use the SceneTree's ``create_timer()`` function. This
+          can be very useful to delay, such as in the above code, where we want
+          to wait a little bit of time before showing the "Start" button.
 
 
 .. tabs::
 .. tabs::
  .. code-tab:: gdscript GDScript
  .. code-tab:: gdscript GDScript
@@ -1072,8 +1072,8 @@ Connecting HUD to Main
 ~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~
 
 
 Now that we're done creating the ``HUD`` scene, save it and go back to ``Main``.
 Now that we're done creating the ``HUD`` scene, save it and go back to ``Main``.
-Instance the ``HUD`` scene in ``Main`` like you did the ``Player`` scene, and place it at the
-bottom of the tree. The full tree should look like this,
+Instance the ``HUD`` scene in ``Main`` like you did the ``Player`` scene, and
+place it at the bottom of the tree. The full tree should look like this,
 so make sure you didn't miss anything:
 so make sure you didn't miss anything:
 
 
 .. image:: img/completed_main_scene.png
 .. image:: img/completed_main_scene.png
@@ -1136,13 +1136,13 @@ Background
 ~~~~~~~~~~
 ~~~~~~~~~~
 
 
 The default gray background is not very appealing, so let's change its
 The default gray background is not very appealing, so let's change its
-color. One way to do this is to use a :ref:`ColorRect <class_ColorRect>` node. Make it the
-first node under ``Main`` so that it will be drawn behind the other
+color. One way to do this is to use a :ref:`ColorRect <class_ColorRect>` node.
+Make it the first node under ``Main`` so that it will be drawn behind the other
 nodes. ``ColorRect`` only has one property: ``Color``. Choose a color
 nodes. ``ColorRect`` only has one property: ``Color``. Choose a color
 you like and drag the size of the ``ColorRect`` so that it covers the
 you like and drag the size of the ``ColorRect`` so that it covers the
 screen.
 screen.
 
 
-You can also add a background image, if you have one, by using a
+You could also add a background image, if you have one, by using a
 ``Sprite`` node.
 ``Sprite`` node.
 
 
 Sound effects
 Sound effects
@@ -1163,40 +1163,23 @@ and ``$Music.stop()`` in the ``game_over()`` function.
 
 
 Finally, add ``$DeathSound.play()`` in the ``game_over()`` function.
 Finally, add ``$DeathSound.play()`` in the ``game_over()`` function.
 
 
-Particles
-~~~~~~~~~
-
-For one last bit of visual appeal, let's add a trail effect to the
-player's movement. Choose your ``Player`` scene and add a
-:ref:`Particles2D <class_Particles2D>` node named ``Trail``.
-
-There are a large number of properties to choose from when
-configuring particles. Feel free to experiment and create different
-effects. For the effect in this example, use the following settings:
-
-.. image:: img/particle_trail_settings.png
-
-You also need to create a ``Material`` by clicking on ``<null>`` and
-then "New ParticlesMaterial". The settings for that are below:
-
-.. image:: img/particle_trail_settings2.png
-
-To make the gradient for the "Color Ramp" setting, we want a gradient taking
-the alpha (transparency) of the sprite from 0.5 (semi-transparent) to
-0.0 (fully transparent).
+Keyboard Shortcut
+~~~~~~~~~~~~~~~~~
 
 
-Click "New GradientTexture", then under "Gradient", click "New Gradient". You'll
-see a window like this:
+Since the game is played with keyboard controls, it would be convenient if we
+could also start the game by pressing a key on the keyboard. One way to do this
+is using the "Shortcut" property of the ``Button`` node.
 
 
-.. image:: img/color_gradient_ui.png
+In the ``HUD`` scene, select the ``StartButton`` and find its _Shortcut_ property
+in the Inspector. Select "New Shortcut" and click on the "Shortcut" item. A
+second _Shortcut_ property will appear. Select "New InputEventAction" and click
+the new "InputEvent". Finally, in the _Action_ property, type the name "ui_select".
+This is the default input event associated with the spacebar.
 
 
-The left and right boxes represent the start and end colors. Click on each
-and then click the large square on the right to choose the color. For the first
-color, set the ``A`` (alpha) value to around halfway. For the second, set it
-all the way to ``0``.
+.. image:: img/start_button_shortcut.png
 
 
-.. seealso:: See :ref:`Particles2D <class_Particles2D>` for more details on using
-             particle effects.
+Now when the start button appears, you can either click it or press the spacebar
+to start the game.
 
 
 Project files
 Project files
 -------------
 -------------