Browse Source

remove FPS tutorial to match master branch

Nathan Lovato 3 years ago
parent
commit
4d97da48dc
32 changed files with 0 additions and 5599 deletions
  1. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_BlenderFiles.zip
  2. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Finished.zip
  3. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Part_1.zip
  4. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Part_2.zip
  5. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Part_3.zip
  6. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Part_4.zip
  7. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Part_5.zip
  8. BIN
      tutorials/3d/fps_tutorial/files/Godot_FPS_Starter.zip
  9. BIN
      tutorials/3d/fps_tutorial/img/AnimationPlayerAddTrack.png
  10. BIN
      tutorials/3d/fps_tutorial/img/AnimationPlayerCallFuncTrack.png
  11. BIN
      tutorials/3d/fps_tutorial/img/AnimationPlayerInsertKey.png
  12. BIN
      tutorials/3d/fps_tutorial/img/AutoloadAddSingleton.png
  13. BIN
      tutorials/3d/fps_tutorial/img/FinishedTutorialPicture.png
  14. BIN
      tutorials/3d/fps_tutorial/img/LocalSpaceExample.png
  15. BIN
      tutorials/3d/fps_tutorial/img/LocalSpaceExampleGizmo.png
  16. BIN
      tutorials/3d/fps_tutorial/img/LocalSpaceExample_3D.png
  17. BIN
      tutorials/3d/fps_tutorial/img/PartFiveFinished.png
  18. BIN
      tutorials/3d/fps_tutorial/img/PartFourFinished.png
  19. BIN
      tutorials/3d/fps_tutorial/img/PartOneFinished.png
  20. BIN
      tutorials/3d/fps_tutorial/img/PartThreeFinished.png
  21. BIN
      tutorials/3d/fps_tutorial/img/PartTwoFinished.png
  22. BIN
      tutorials/3d/fps_tutorial/img/PlayerSceneTree.png
  23. BIN
      tutorials/3d/fps_tutorial/img/ProjectSettingsAddKey.png
  24. BIN
      tutorials/3d/fps_tutorial/img/WorldSpaceExample.png
  25. BIN
      tutorials/3d/fps_tutorial/img/WorldSpaceExample_3D.png
  26. 0 13
      tutorials/3d/fps_tutorial/index.rst
  27. 0 967
      tutorials/3d/fps_tutorial/part_five.rst
  28. 0 790
      tutorials/3d/fps_tutorial/part_four.rst
  29. 0 852
      tutorials/3d/fps_tutorial/part_one.rst
  30. 0 1041
      tutorials/3d/fps_tutorial/part_six.rst
  31. 0 697
      tutorials/3d/fps_tutorial/part_three.rst
  32. 0 1239
      tutorials/3d/fps_tutorial/part_two.rst

BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_BlenderFiles.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Finished.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Part_1.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Part_2.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Part_3.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Part_4.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Part_5.zip


BIN
tutorials/3d/fps_tutorial/files/Godot_FPS_Starter.zip


BIN
tutorials/3d/fps_tutorial/img/AnimationPlayerAddTrack.png


BIN
tutorials/3d/fps_tutorial/img/AnimationPlayerCallFuncTrack.png


BIN
tutorials/3d/fps_tutorial/img/AnimationPlayerInsertKey.png


BIN
tutorials/3d/fps_tutorial/img/AutoloadAddSingleton.png


BIN
tutorials/3d/fps_tutorial/img/FinishedTutorialPicture.png


BIN
tutorials/3d/fps_tutorial/img/LocalSpaceExample.png


BIN
tutorials/3d/fps_tutorial/img/LocalSpaceExampleGizmo.png


BIN
tutorials/3d/fps_tutorial/img/LocalSpaceExample_3D.png


BIN
tutorials/3d/fps_tutorial/img/PartFiveFinished.png


BIN
tutorials/3d/fps_tutorial/img/PartFourFinished.png


BIN
tutorials/3d/fps_tutorial/img/PartOneFinished.png


BIN
tutorials/3d/fps_tutorial/img/PartThreeFinished.png


BIN
tutorials/3d/fps_tutorial/img/PartTwoFinished.png


BIN
tutorials/3d/fps_tutorial/img/PlayerSceneTree.png


BIN
tutorials/3d/fps_tutorial/img/ProjectSettingsAddKey.png


BIN
tutorials/3d/fps_tutorial/img/WorldSpaceExample.png


BIN
tutorials/3d/fps_tutorial/img/WorldSpaceExample_3D.png


+ 0 - 13
tutorials/3d/fps_tutorial/index.rst

@@ -1,13 +0,0 @@
-FPS tutorial
-============
-
-.. toctree::
-   :maxdepth: 1
-   :name: toc-3D-fps-tutorial
-
-   part_one
-   part_two
-   part_three
-   part_four
-   part_five
-   part_six

+ 0 - 967
tutorials/3d/fps_tutorial/part_five.rst

@@ -1,967 +0,0 @@
-.. _doc_fps_tutorial_part_five:
-
-Part 5
-======
-
-Part overview
--------------
-
-In this part, we're going to add grenades to the player, give the player the ability to grab and throw objects, and add turrets!
-
-.. image:: img/PartFiveFinished.png
-
-.. note:: You are assumed to have finished :ref:`doc_fps_tutorial_part_four` before moving on to this part of the tutorial.
-          The finished project from :ref:`doc_fps_tutorial_part_four` will be the starting project for part 5
-
-Let's get started!
-
-Adding grenades
----------------
-
-Firstly, let's give the player some grenades to play with. Open up ``Grenade.tscn``.
-
-There are a few things to note here, the first and foremost being that the grenades are going to use :ref:`RigidBody <class_RigidBody>` nodes.
-We're going to use :ref:`RigidBody <class_RigidBody>` nodes for our grenades so they bounce around the world in a (somewhat) realistic manner.
-
-The second thing to note is ``Blast_Area``. This is an :ref:`Area <class_Area>` node that will represent the blast radius of the grenade.
-
-Finally, the last thing to note is ``Explosion``. This is the :ref:`Particles <class_Particles>` node that will emit an explosion effect when
-the grenade explodes. One thing to note here is that we have ``One shot`` enabled. This is so we emit all the particles at once. The particles are also emitted using world
-coordinates instead of local coordinates, so we have ``Local Coords`` unchecked as well.
-
-.. note:: If you want, you can see how the particles are set up by looking through the particle's ``Process Material`` and ``Draw Passes``.
-
-Let's write the code needed for the grenade. Select ``Grenade`` and make a new script called ``Grenade.gd``. Add the following:
-
-::
-
-    extends RigidBody
-
-    const GRENADE_DAMAGE = 60
-
-    const GRENADE_TIME = 2
-    var grenade_timer = 0
-
-    const EXPLOSION_WAIT_TIME = 0.48
-    var explosion_wait_timer = 0
-
-    var rigid_shape
-    var grenade_mesh
-    var blast_area
-    var explosion_particles
-
-    func _ready():
-        rigid_shape = $Collision_Shape
-        grenade_mesh = $Grenade
-        blast_area = $Blast_Area
-        explosion_particles = $Explosion
-
-        explosion_particles.emitting = false
-        explosion_particles.one_shot = true
-
-    func _process(delta):
-
-        if grenade_timer < GRENADE_TIME:
-            grenade_timer += delta
-            return
-        else:
-            if explosion_wait_timer <= 0:
-                explosion_particles.emitting = true
-
-                grenade_mesh.visible = false
-                rigid_shape.disabled = true
-
-                mode = RigidBody.MODE_STATIC
-
-                var bodies = blast_area.get_overlapping_bodies()
-                for body in bodies:
-                    if body.has_method("bullet_hit"):
-                        body.bullet_hit(GRENADE_DAMAGE, body.global_transform.looking_at(global_transform.origin, Vector3(0, 1, 0)))
-
-                # This would be the perfect place to play a sound!
-
-
-            if explosion_wait_timer < EXPLOSION_WAIT_TIME:
-                explosion_wait_timer += delta
-
-                if explosion_wait_timer >= EXPLOSION_WAIT_TIME:
-                    queue_free()
-
-Let's go over what's happening, starting with the class variables:
-
-* ``GRENADE_DAMAGE``: The amount of damage the grenade causes when it explodes.
-* ``GRENADE_TIME``: The amount of time the grenade takes (in seconds) to explode once it's created/thrown.
-* ``grenade_timer``: A variable for tracking how long the grenade has been created/thrown.
-* ``EXPLOSION_WAIT_TIME``: The amount of time needed (in seconds) to wait before we destroy the grenade scene after the explosion
-* ``explosion_wait_timer``: A variable for tracking how much time has passed since the grenade exploded.
-* ``rigid_shape``: The :ref:`CollisionShape <class_CollisionShape>` for the grenade's :ref:`RigidBody <class_RigidBody>`.
-* ``grenade_mesh``: The :ref:`MeshInstance <class_MeshInstance>` for the grenade.
-* ``blast_area``: The blast :ref:`Area <class_Area>` used to damage things when the grenade explodes.
-* ``explosion_particles``: The :ref:`Particles <class_Particles>` that come out when the grenade explodes.
-
-Notice how ``EXPLOSION_WAIT_TIME`` is a rather strange number (``0.48``). This is because we want ``EXPLOSION_WAIT_TIME`` to be equal to the length of time
-the explosion particles are emitting, so when the particles are done we destroy/free the grenade. We calculate ``EXPLOSION_WAIT_TIME`` by taking the particle's life time
-and dividing it by the particle's speed scale. This gets us the exact time the explosion particles will last.
-
-______
-
-Now let's turn our attention to ``_ready``.
-
-First we get all the nodes we'll need and assign them to the proper class variables.
-
-We need to get the :ref:`CollisionShape <class_CollisionShape>` and :ref:`MeshInstance <class_MeshInstance>` because similarly to the target in :ref:`doc_fps_tutorial_part_four`,
-we will be hiding the grenade's mesh and disabling the collision shape when the grenade explodes.
-
-The reason we need to get the blast :ref:`Area <class_Area>` is so we can damage everything inside it when the grenade explodes. We'll be using code similar to the knife
-code in the player. We need the :ref:`Particles <class_Particles>` so we can emit particles when the grenade explodes.
-
-After we get all the nodes and assign them to their class variables, we then make sure the explosion particles are not emitting, and that they are set to
-emit in one shot. This is to be extra sure the particles will behave the way we expect them to.
-
-______
-
-Now let's look at ``_process``.
-
-Firstly, we check to see if the ``grenade_timer`` is less than ``GRENADE_TIME``. If it is, we add ``delta`` and return. This is so the grenade has to wait ``GRENADE_TIME`` seconds
-before exploding, allowing the :ref:`RigidBody <class_RigidBody>` to move around.
-
-If ``grenade_timer`` is at ``GRENADE_TIMER`` or higher, we then need to check if the grenade has waited long enough and needs to explode. We do this by checking to see
-if ``explosion_wait_timer`` is equal to ``0`` or less. Since we will be adding ``delta`` to ``explosion_wait_timer`` right after, whatever code under the check
-will only be called once, right when the grenade has waited long enough and needs to explode.
-
-If the grenade has waited long enough to explode, we first tell the ``explosion_particles`` to emit. Then we make ``grenade_mesh`` invisible, and disable ``rigid_shape``, effectively
-hiding the grenade.
-
-We then set the :ref:`RigidBody <class_RigidBody>`'s mode to ``MODE_STATIC`` so the grenade does not move.
-
-Then we get all the bodies in ``blast_area``, check to see if they have the ``bullet_hit`` method/function, and if they do, we call it and pass in ``GRENADE_DAMAGE`` and
-the transform from the body looking at the grenade. This makes it where the bodies exploded by the grenade will explode outwards from the grenade's position.
-
-We then check to see if ``explosion_wait_timer`` is less than ``EXPLOSION_WAIT_TIME``. If it is, we add ``delta`` to ``explosion_wait_timer``.
-
-Next, we check to see if ``explosion_wait_timer`` is greater than or equal to ``EXPLOSION_WAIT_TIME``. Because we added ``delta``, this will only be called once.
-If ``explosion_wait_timer`` is greater or equal to ``EXPLOSION_WAIT_TIME``, the grenade has waited long enough to let the :ref:`Particles <class_Particles>` play
-and we can free/destroy the grenade, as we no longer need it.
-
-______
-
-Let's quickly get the sticky grenade set up too. Open up ``Sticky_Grenade.tscn``.
-
-``Sticky_Grenade.tscn`` is almost identical to ``Grenade.tscn``, with one small addition. We now have a second
-:ref:`Area <class_Area>`, called ``Sticky_Area``. We will be using ``Stick_Area`` to detect when the sticky grenade has collided with
-the environment and needs to stick to something.
-
-Select ``Sticky_Grenade`` and make a new script called ``Sticky_Grenade.gd``. Add the following:
-
-::
-
-    extends RigidBody
-
-    const GRENADE_DAMAGE = 40
-
-    const GRENADE_TIME = 3
-    var grenade_timer = 0
-
-    const EXPLOSION_WAIT_TIME = 0.48
-    var explosion_wait_timer = 0
-
-    var attached = false
-    var attach_point = null
-
-    var rigid_shape
-    var grenade_mesh
-    var blast_area
-    var explosion_particles
-
-    var player_body
-
-    func _ready():
-        rigid_shape = $Collision_Shape
-        grenade_mesh = $Sticky_Grenade
-        blast_area = $Blast_Area
-        explosion_particles = $Explosion
-
-        explosion_particles.emitting = false
-        explosion_particles.one_shot = true
-
-        $Sticky_Area.connect("body_entered", self, "collided_with_body")
-
-
-    func collided_with_body(body):
-
-        if body == self:
-            return
-
-        if player_body != null:
-            if body == player_body:
-                return
-
-        if attached == false:
-            attached = true
-            attach_point = Spatial.new()
-            body.add_child(attach_point)
-            attach_point.global_transform.origin = global_transform.origin
-
-            rigid_shape.disabled = true
-
-            mode = RigidBody.MODE_STATIC
-
-
-    func _process(delta):
-
-        if attached == true:
-            if attach_point != null:
-                global_transform.origin = attach_point.global_transform.origin
-
-        if grenade_timer < GRENADE_TIME:
-            grenade_timer += delta
-            return
-        else:
-            if explosion_wait_timer <= 0:
-                explosion_particles.emitting = true
-
-                grenade_mesh.visible = false
-                rigid_shape.disabled = true
-
-                mode = RigidBody.MODE_STATIC
-
-                var bodies = blast_area.get_overlapping_bodies()
-                for body in bodies:
-                    if body.has_method("bullet_hit"):
-                        body.bullet_hit(GRENADE_DAMAGE, body.global_transform.looking_at(global_transform.origin, Vector3(0, 1, 0)))
-
-                # This would be the perfect place to play a sound!
-
-
-            if explosion_wait_timer < EXPLOSION_WAIT_TIME:
-                explosion_wait_timer += delta
-
-                if explosion_wait_timer >= EXPLOSION_WAIT_TIME:
-                    if attach_point != null:
-                        attach_point.queue_free()
-                    queue_free()
-
-The code above is almost identical to the code for ``Grenade.gd``, so let's just go over what's changed.
-
-Firstly, we have a few more class variables:
-
-* ``attached``: A variable for tracking whether or not the sticky grenade has attached to a :ref:`PhysicsBody <class_PhysicsBody>`.
-* ``attach_point``: A variable to hold a :ref:`Spatial <class_Spatial>` that will be at the position where the sticky grenade collided.
-* ``player_body``: The player's :ref:`KinematicBody <class_KinematicBody>`.
-
-They have been added to enable the sticky grenade to stick to any :ref:`PhysicsBody <class_PhysicsBody>` it might hit. We also now
-need the player's :ref:`KinematicBody <class_KinematicBody>` so the sticky grenade does not stick to the player when the player throws it.
-
-______
-
-Now let's look at the small change in ``_ready``. In ``_ready`` we've added a line of code so when any body enters ``Stick_Area``,
-the ``collided_with_body`` function is called.
-
-______
-
-Next let's take a look at ``collided_with_body``.
-
-Firstly, we make sure the sticky grenade is not colliding with itself.
-Because the sticky :ref:`Area <class_Area>` does not know it's attached to the grenade's :ref:`RigidBody <class_RigidBody>`,
-we need to make sure it's not going to stick to itself by checking to make sure the body it has collided with is not itself.
-If we have collided with ourself, we ignore it by returning.
-
-We then check to see if we have something assigned to ``player_body``, and if the body the sticky grenade has collided with is the player that threw it.
-If the body the sticky grenade has collided with is indeed ``player_body``, we ignore it by returning.
-
-Next, we check if the sticky grenade has attached to something already or not.
-
-If the sticky grenade is not attached, we then set ``attached`` to ``true`` so we know the sticky grenade has attached to something.
-
-We then make a new :ref:`Spatial <class_Spatial>` node, and make it a child of the body the sticky grenade collided with. We then set the :ref:`Spatial <class_Spatial>`'s position
-to the sticky grenade's current global position.
-
-.. note:: Because we've added the :ref:`Spatial <class_Spatial>` as a child of the body the sticky grenade has collided with, it will follow along with said body.
-          We can then use this :ref:`Spatial <class_Spatial>` to set the sticky grenade's position, so it is always at the same position relative to the body it collided with.
-
-We then disable ``rigid_shape`` so the sticky grenade is not constantly moving whatever body it has collided with.
-Finally, we set our mode to ``MODE_STATIC`` so the grenade does not move.
-
-______
-
-Finally, lets go over the few changes in ``_process``.
-
-Now we're checking to see if the sticky grenade is attached right at the top of ``_process``.
-
-If the sticky grenade is attached, we then make sure the attached point is not equal to ``null``.
-If the attached point is not equal to ``null``, we set the sticky grenade's global position (using its global :ref:`Transform <class_Transform>`'s origin) to the global position of
-the :ref:`Spatial <class_Spatial>` assigned to ``attach_point`` (using its global :ref:`Transform <class_Transform>`'s origin).
-
-The only other change is now before we free/destroy the sticky grenade is to check to see if the sticky grenade has an attached point.
-If it does, we also call ``queue_free`` on the attach point, so it's also freed/destroyed.
-
-Adding grenades to the player
------------------------------
-
-Now we need to add some code to ``Player.gd`` so we can use the grenades.
-
-Firstly, open up ``Player.tscn`` and expand the node tree until you get to ``Rotation_Helper``. Notice how in
-``Rotation_Helper`` we have a node called ``Grenade_Toss_Pos``. This is where we will be spawning the grenades.
-
-Also notice how it's slightly rotated on the ``X`` axis, so it's not pointing straight, but rather slightly up. By changing
-the rotation of ``Grenade_Toss_Pos``, you can change the angle at which the grenades are tossed.
-
-Okay, now let's start making the grenades work with the player. Add the following class variables to ``Player.gd``:
-
-::
-
-    var grenade_amounts = {"Grenade":2, "Sticky Grenade":2}
-    var current_grenade = "Grenade"
-    var grenade_scene = preload("res://Grenade.tscn")
-    var sticky_grenade_scene = preload("res://Sticky_Grenade.tscn")
-    const GRENADE_THROW_FORCE = 50
-
-* ``grenade_amounts``: The amount of grenades the player is currently carrying (for each type of grenade).
-* ``current_grenade``: The name of the grenade the player is currently using.
-* ``grenade_scene``: The grenade scene we worked on earlier.
-* ``sticky_grenade_scene``: The sticky grenade scene we worked on earlier.
-* ``GRENADE_THROW_FORCE``: The force at which the player will throw the grenades.
-
-Most of these variables are similar to how we have our weapons set up.
-
-.. tip:: While it's possible to make a more modular grenade system, I found it was not worth the additional complexity for just two grenades.
-         If you were going to make a more complex FPS with more grenades, you'd likely want to make a system for grenades similar to how we have the weapons set up.
-
-______
-
-Now we need to add some code in ``_process_input`` Add the following to ``_process_input``:
-
-::
-
-    # ----------------------------------
-    # Changing and throwing grenades
-
-    if Input.is_action_just_pressed("change_grenade"):
-        if current_grenade == "Grenade":
-            current_grenade = "Sticky Grenade"
-        elif current_grenade == "Sticky Grenade":
-            current_grenade = "Grenade"
-
-    if Input.is_action_just_pressed("fire_grenade"):
-        if grenade_amounts[current_grenade] > 0:
-            grenade_amounts[current_grenade] -= 1
-
-            var grenade_clone
-            if current_grenade == "Grenade":
-                grenade_clone = grenade_scene.instance()
-            elif current_grenade == "Sticky Grenade":
-                grenade_clone = sticky_grenade_scene.instance()
-                # Sticky grenades will stick to the player if we do not pass ourselves
-                grenade_clone.player_body = self
-
-            get_tree().root.add_child(grenade_clone)
-            grenade_clone.global_transform = $Rotation_Helper/Grenade_Toss_Pos.global_transform
-            grenade_clone.apply_impulse(Vector3(0, 0, 0), grenade_clone.global_transform.basis.z * GRENADE_THROW_FORCE)
-    # ----------------------------------
-
-Let's go over what's happening here.
-
-Firstly, we check to see if the ``change_grenade`` action has just been pressed. If it has, we then check to see which grenade the player is
-currently using. Based on the name of the grenade the player is currently using, we change ``current_grenade`` to the opposite grenade name.
-
-Next we check to see if the ``fire_grenade`` action has just been pressed. If it has, we then check to see if the player has more than ``0`` grenades for the
-current grenade type selected.
-
-If the player has more than ``0`` grenades, we then remove one from the grenade amounts for the current grenade.
-Then, based on the grenade the player is currently using, we instance the proper grenade scene and assign it to ``grenade_clone``.
-
-Next we add ``grenade_clone`` as a child of the node at the root and set its global :ref:`Transform <class_Transform>` to
-``Grenade_Toss_Pos``'s global :ref:`Transform <class_Transform>`. Finally, we apply an impulse to the grenade so that it is launched forward, relative
-to the ``Z`` directional vector of ``grenade_clone``'s.
-
-______
-
-Now the player can use both types of grenades, but there are still a few things we should probably add before we move on to adding the other things.
-
-We still need a way to show the player how many grenades are left, and we should probably add a way to get more grenades when the player picks up ammo.
-
-Firstly, let's change some of the code in ``Player.gd`` to show how many grenades are left. Change ``process_UI`` to the following:
-
-::
-
-    func process_UI(delta):
-        if current_weapon_name == "UNARMED" or current_weapon_name == "KNIFE":
-            # First line: Health, second line: Grenades
-            UI_status_label.text = "HEALTH: " + str(health) + \
-                    "\n" + current_grenade + ": " + str(grenade_amounts[current_grenade])
-        else:
-            var current_weapon = weapons[current_weapon_name]
-            # First line: Health, second line: weapon and ammo, third line: grenades
-            UI_status_label.text = "HEALTH: " + str(health) + \
-                    "\nAMMO: " + str(current_weapon.ammo_in_weapon) + "/" + str(current_weapon.spare_ammo) + \
-                    "\n" + current_grenade + ": " + str(grenade_amounts[current_grenade])
-
-Now we'll show how many grenades the player has left in the UI.
-
-While we're still in ``Player.gd``, let's add a function to add grenades to the player. Add the following function to ``Player.gd``:
-
-::
-
-    func add_grenade(additional_grenade):
-        grenade_amounts[current_grenade] += additional_grenade
-        grenade_amounts[current_grenade] = clamp(grenade_amounts[current_grenade], 0, 4)
-
-Now we can add a grenade using ``add_grenade``, and it will automatically be clamped to a maximum of ``4`` grenades.
-
-.. tip:: You can change the ``4`` to a constant if you want. You'd need to make a new global constant, something like ``MAX_GRENADES``, and
-         then change the clamp from ``clamp(grenade_amounts[current_grenade], 0, 4)`` to ``clamp(grenade_amounts[current_grenade], 0, MAX_GRENADES)``
-
-         If you do not want to limit how many grenades the player can carry, remove the line that clamps the grenades altogether!
-
-Now we have a function to add grenades, let's open up ``AmmoPickup.gd`` and use it!
-
-Open up ``AmmoPickup.gd`` and go to the ``trigger_body_entered`` function. Change it to the following:
-
-::
-
-    func trigger_body_entered(body):
-        if body.has_method("add_ammo"):
-            body.add_ammo(AMMO_AMOUNTS[kit_size])
-            respawn_timer = RESPAWN_TIME
-            kit_size_change_values(kit_size, false)
-
-        if body.has_method("add_grenade"):
-            body.add_grenade(GRENADE_AMOUNTS[kit_size])
-            respawn_timer = RESPAWN_TIME
-            kit_size_change_values(kit_size, false)
-
-Now we are also checking to see if the body has the ``add_grenade`` function. If it does, we call it like we call ``add_ammo``.
-
-You may have noticed we are using a new constant we have not defined yet, ``GRENADE_AMOUNTS``. Let's add it! Add the following class variable
-to ``AmmoPickup.gd`` with the other class variables:
-
-::
-
-    const GRENADE_AMOUNTS = [2, 0]
-
-* ``GRENADE_AMOUNTS``: The amount of grenades each pickup contains.
-
-Notice how the second element in ``GRENADE_AMOUNTS`` is ``0``. This is so the small ammo pickup does not give the player
-any additional grenades.
-
-______
-
-Now you should be able to throw grenades! Go give it a try!
-
-
-Adding the ability to grab and throw RigidBody nodes to the player
-------------------------------------------------------------------
-
-Next, let's give the player the ability to pick up and throw :ref:`RigidBody <class_RigidBody>` nodes.
-
-Open up ``Player.gd`` and add the following class variables:
-
-::
-
-    var grabbed_object = null
-    const OBJECT_THROW_FORCE = 120
-    const OBJECT_GRAB_DISTANCE = 7
-    const OBJECT_GRAB_RAY_DISTANCE = 10
-
-* ``grabbed_object``: A variable to hold the grabbed :ref:`RigidBody <class_RigidBody>` node.
-* ``OBJECT_THROW_FORCE``: The force with which the player throws the grabbed object.
-* ``OBJECT_GRAB_DISTANCE``: The distance away from the camera at which the player holds the grabbed object.
-* ``OBJECT_GRAB_RAY_DISTANCE``: The distance the :ref:`Raycast <class_Raycast>` goes. This is the player's grab distance.
-
-With that done, all we need to do is add some code to ``process_input``:
-
-::
-
-    # ----------------------------------
-    # Grabbing and throwing objects
-
-    if Input.is_action_just_pressed("fire_grenade") and current_weapon_name == "UNARMED":
-        if grabbed_object == null:
-            var state = get_world().direct_space_state
-
-            var center_position = get_viewport().size / 2
-            var ray_from = camera.project_ray_origin(center_position)
-            var ray_to = ray_from + camera.project_ray_normal(center_position) * OBJECT_GRAB_RAY_DISTANCE
-
-            var ray_result = state.intersect_ray(ray_from, ray_to, [self, $Rotation_Helper/Gun_Fire_Points/Knife_Point/Area])
-            if !ray_result.empty():
-                if ray_result["collider"] is RigidBody:
-                    grabbed_object = ray_result["collider"]
-                    grabbed_object.mode = RigidBody.MODE_STATIC
-
-                    grabbed_object.collision_layer = 0
-                    grabbed_object.collision_mask = 0
-
-        else:
-            grabbed_object.mode = RigidBody.MODE_RIGID
-
-            grabbed_object.apply_impulse(Vector3(0, 0, 0), -camera.global_transform.basis.z.normalized() * OBJECT_THROW_FORCE)
-
-            grabbed_object.collision_layer = 1
-            grabbed_object.collision_mask = 1
-
-            grabbed_object = null
-
-    if grabbed_object != null:
-        grabbed_object.global_transform.origin = camera.global_transform.origin + (-camera.global_transform.basis.z.normalized() * OBJECT_GRAB_DISTANCE)
-    # ----------------------------------
-
-Let's go over what's happening.
-
-Firstly, we check to see if the action pressed is the ``fire`` action, and that the player is using the ``UNARMED`` 'weapon'.
-This is because we only want the player to be able to pick up and throw objects when the player is not using any weapons. This is a design choice,
-but I feel it gives ``UNARMED`` a use.
-
-Next we check to see whether or not ``grabbed_object`` is ``null``.
-
-______
-
-If ``grabbed_object`` is ``null``, we want to see if we can pick up a :ref:`RigidBody <class_RigidBody>`.
-
-We first get the direct space state from the current :ref:`World <class_World>`. This is so we can cast a ray entirely from code, instead of having to
-use a :ref:`Raycast <class_Raycast>` node.
-
-.. note:: See :ref:`Ray-casting <doc_ray-casting>` for more information on raycasting in Godot.
-
-Then we get the center of the screen by dividing the current :ref:`Viewport <class_Viewport>` size in half. We then get the ray's origin point and end point using
-``project_ray_origin`` and ``project_ray_normal`` from the camera. If you want to know more about how these functions work, see :ref:`Ray-casting <doc_ray-casting>`.
-
-Next we send the ray into the space state and see if it gets a result. We add the player and the knife's :ref:`Area <class_Area>` as two exceptions so the player cannot carry
-themselves or the knife's collision :ref:`Area <class_Area>`.
-
-Then we check to see if we got a result back from the ray. If no object has collided with the ray, an empty Dictionary will be returned. If the Dictionary is not empty (i.e. at least one object has collided), we then see if the collider the ray collided with is a :ref:`RigidBody <class_RigidBody>`.
-
-If the ray collided with a :ref:`RigidBody <class_RigidBody>`, we set ``grabbed_object`` to the collider the ray collided with. We then set the mode on
-the :ref:`RigidBody <class_RigidBody>` we collided with to ``MODE_STATIC`` so it doesn't move in our hands.
-
-Finally, we set the grabbed :ref:`RigidBody <class_RigidBody>`'s collision layer and collision mask to ``0``.
-This will make the grabbed :ref:`RigidBody <class_RigidBody>` have no collision layer or mask, which means it will not be able to collide with anything as long as we are holding it.
-
-.. note::
-
-    See :ref:`Physics introduction <doc_physics_introduction_collision_layer_code_example>`
-    for more information on Godot collision masks.
-
-______
-
-If ``grabbed_object`` is not ``null``, then we need to throw the :ref:`RigidBody <class_RigidBody>` the player is holding.
-
-We first set the mode of the :ref:`RigidBody <class_RigidBody>` we are holding to ``MODE_RIGID``.
-
-.. note:: This is making a rather large assumption that all the rigid bodies will be using ``MODE_RIGID``. While that is the case for this tutorial series,
-          that may not be the case in other projects.
-
-          If you have rigid bodies with different modes, you may need to store the mode of the :ref:`RigidBody <class_RigidBody>` you
-          have picked up into a class variable so you can change it back to the mode it was in before you picked it up.
-
-Then we apply an impulse to send it flying forward. We send it flying in the direction the camera is facing, using the force we set in the ``OBJECT_THROW_FORCE`` variable.
-
-We then set the grabbed :ref:`RigidBody <class_RigidBody>`'s collision layer and mask to ``1``, so it can collide with anything on layer ``1`` again.
-
-.. note:: This is, once again, making a rather large assumption that all the rigid bodies will be only on collision layer ``1``, and all collision masks will be on layer ``1``.
-          If you are using this script in other projects, you may need to store the collision layer/mask of the :ref:`RigidBody <class_RigidBody>` in a variable before you change them to ``0``, so you would have the original collision layer/mask to set for them when you are reversing the process.
-
-Finally, we set ``grabbed_object`` to ``null`` since the player has successfully thrown the held object.
-
-______
-
-The last thing we do is check to see whether or not ``grabbed_object`` is equal to ``null``, outside all of the grabbing/throwing related code.
-
-.. note:: While technically not input related, it's easy enough to place the code moving the grabbed object here
-          because it's only two lines, and then all of the grabbing/throwing code is in one place
-
-If the player is holding an object, we set its global position to the camera's position plus ``OBJECT_GRAB_DISTANCE`` in the direction the camera is facing.
-
-______
-
-Before we test this, we need to change something in ``_physics_process``. While the player is holding an object, we do not
-want the player to be able to change weapons or reload, so change ``_physics_process`` to the following:
-
-::
-
-    func _physics_process(delta):
-        process_input(delta)
-        process_view_input(delta)
-        process_movement(delta)
-
-        if grabbed_object == null:
-            process_changing_weapons(delta)
-            process_reloading(delta)
-
-        # Process the UI
-        process_UI(delta)
-
-Now the player cannot change weapons or reload while holding an object.
-
-Now you can grab and throw RigidBody nodes while you're in the ``UNARMED`` state! Go give it a try!
-
-Adding a turret
----------------
-
-Next, let's make a turret to shoot the player!
-
-Open up ``Turret.tscn``. Expand ``Turret`` if it's not already expanded.
-
-Notice how the turret is broken up into several parts: ``Base``, ``Head``, ``Vision_Area``, and a ``Smoke`` :ref:`Particles <class_Particles>` node.
-
-Open up ``Base`` and you'll find it's a :ref:`StaticBody <class_StaticBody>` and a mesh. Open up ``Head`` and you'll find there are several meshes,
-a :ref:`StaticBody <class_StaticBody>` and a :ref:`Raycast <class_Raycast>` node.
-
-One thing to note with the ``Head`` is that the raycast will be where the turret's bullets will fire from if we are using raycasting. We also have two meshes called
-``Flash`` and ``Flash_2``. These will be the muzzle flash that briefly shows when the turret fires.
-
-``Vision_Area`` is an :ref:`Area <class_Area>` we'll use as the turret's ability to see. When something enters ``Vision_Area``, we'll assume the turret can see it.
-
-``Smoke`` is a :ref:`Particles <class_Particles>` node that will play when the turret is destroyed and repairing.
-
-______
-
-Now that we've looked at how the scene is set up, lets start writing the code for the turret. Select ``Turret`` and create a new script called ``Turret.gd``.
-Add the following to ``Turret.gd``:
-
-::
-
-    extends Spatial
-
-    export (bool) var use_raycast = false
-
-    const TURRET_DAMAGE_BULLET = 20
-    const TURRET_DAMAGE_RAYCAST = 5
-
-    const FLASH_TIME = 0.1
-    var flash_timer = 0
-
-    const FIRE_TIME = 0.8
-    var fire_timer = 0
-
-    var node_turret_head = null
-    var node_raycast = null
-    var node_flash_one = null
-    var node_flash_two = null
-
-    var ammo_in_turret = 20
-    const AMMO_IN_FULL_TURRET = 20
-    const AMMO_RELOAD_TIME = 4
-    var ammo_reload_timer = 0
-
-    var current_target = null
-
-    var is_active = false
-
-    const PLAYER_HEIGHT = 3
-
-    var smoke_particles
-
-    var turret_health = 60
-    const MAX_TURRET_HEALTH = 60
-
-    const DESTROYED_TIME = 20
-    var destroyed_timer = 0
-
-    var bullet_scene = preload("Bullet_Scene.tscn")
-
-    func _ready():
-
-        $Vision_Area.connect("body_entered", self, "body_entered_vision")
-        $Vision_Area.connect("body_exited", self, "body_exited_vision")
-
-        node_turret_head = $Head
-        node_raycast = $Head/Ray_Cast
-        node_flash_one = $Head/Flash
-        node_flash_two = $Head/Flash_2
-
-        node_raycast.add_exception(self)
-        node_raycast.add_exception($Base/Static_Body)
-        node_raycast.add_exception($Head/Static_Body)
-        node_raycast.add_exception($Vision_Area)
-
-        node_flash_one.visible = false
-        node_flash_two.visible = false
-
-        smoke_particles = $Smoke
-        smoke_particles.emitting = false
-
-        turret_health = MAX_TURRET_HEALTH
-
-
-    func _physics_process(delta):
-
-        if is_active == true:
-
-            if flash_timer > 0:
-                flash_timer -= delta
-
-                if flash_timer <= 0:
-                    node_flash_one.visible = false
-                    node_flash_two.visible = false
-
-            if current_target != null:
-
-                node_turret_head.look_at(current_target.global_transform.origin + Vector3(0, PLAYER_HEIGHT, 0), Vector3(0, 1, 0))
-
-                if turret_health > 0:
-
-                    if ammo_in_turret > 0:
-                        if fire_timer > 0:
-                            fire_timer -= delta
-                        else:
-                            fire_bullet()
-                    else:
-                        if ammo_reload_timer > 0:
-                            ammo_reload_timer -= delta
-                        else:
-                            ammo_in_turret = AMMO_IN_FULL_TURRET
-
-        if turret_health <= 0:
-            if destroyed_timer > 0:
-                destroyed_timer -= delta
-            else:
-                turret_health = MAX_TURRET_HEALTH
-                smoke_particles.emitting = false
-
-
-    func fire_bullet():
-
-        if use_raycast == true:
-            node_raycast.look_at(current_target.global_transform.origin + Vector3(0, PLAYER_HEIGHT, 0), Vector3(0, 1, 0))
-
-            node_raycast.force_raycast_update()
-
-            if node_raycast.is_colliding():
-                var body = node_raycast.get_collider()
-                if body.has_method("bullet_hit"):
-                    body.bullet_hit(TURRET_DAMAGE_RAYCAST, node_raycast.get_collision_point())
-
-            ammo_in_turret -= 1
-
-        else:
-            var clone = bullet_scene.instance()
-            var scene_root = get_tree().root.get_children()[0]
-            scene_root.add_child(clone)
-
-            clone.global_transform = $Head/Barrel_End.global_transform
-            clone.scale = Vector3(8, 8, 8)
-            clone.BULLET_DAMAGE = TURRET_DAMAGE_BULLET
-            clone.BULLET_SPEED = 60
-
-            ammo_in_turret -= 1
-
-        node_flash_one.visible = true
-        node_flash_two.visible = true
-
-        flash_timer = FLASH_TIME
-        fire_timer = FIRE_TIME
-
-        if ammo_in_turret <= 0:
-            ammo_reload_timer = AMMO_RELOAD_TIME
-
-
-    func body_entered_vision(body):
-        if current_target == null:
-            if body is KinematicBody:
-                current_target = body
-                is_active = true
-
-
-    func body_exited_vision(body):
-        if current_target != null:
-            if body == current_target:
-                current_target = null
-                is_active = false
-
-                flash_timer = 0
-                fire_timer = 0
-                node_flash_one.visible = false
-                node_flash_two.visible = false
-
-
-    func bullet_hit(damage, bullet_hit_pos):
-        turret_health -= damage
-
-        if turret_health <= 0:
-            smoke_particles.emitting = true
-            destroyed_timer = DESTROYED_TIME
-
-This is quite a bit of code, so let's break it down function by function. Let's first look at the class variables:
-
-* ``use_raycast``: An exported boolean so we can change whether the turret uses objects or raycasting for bullets.
-* ``TURRET_DAMAGE_BULLET``: The amount of damage a single bullet scene does.
-* ``TURRET_DAMAGE_RAYCAST``: The amount of damage a single :ref:`Raycast <class_Raycast>` bullet does.
-* ``FLASH_TIME``: The amount of time (in seconds) the muzzle flash meshes are visible.
-* ``flash_timer``: A variable for tracking how long the muzzle flash meshes have been visible.
-* ``FIRE_TIME``: The amount of time (in seconds) needed to fire a bullet.
-* ``fire_timer``: A variable for tracking how much time has passed since the turret last fired.
-* ``node_turret_head``: A variable to hold the ``Head`` node.
-* ``node_raycast``: A variable to hold the :ref:`Raycast <class_Raycast>` node attached to the turret's head.
-* ``node_flash_one``: A variable to hold the first muzzle flash :ref:`MeshInstance <class_MeshInstance>`.
-* ``node_flash_two``: A variable to hold the second muzzle flash :ref:`MeshInstance <class_MeshInstance>`.
-* ``ammo_in_turret``: The amount of ammo currently in the turret.
-* ``AMMO_IN_FULL_TURRET``: The amount of ammo in a full turret.
-* ``AMMO_RELOAD_TIME``: The amount of time it takes the turret to reload.
-* ``ammo_reload_timer``: A variable for tracking how long the turret has been reloading.
-* ``current_target``: The turret's current target.
-* ``is_active``: A variable for tracking whether the turret is able to fire at the target.
-* ``PLAYER_HEIGHT``: The amount of height we're adding to the target so we're not shooting at its feet.
-* ``smoke_particles``: A variable to hold the smoke particles node.
-* ``turret_health``: The amount of health the turret currently has.
-* ``MAX_TURRET_HEALTH``: The amount of health a fully healed turret has.
-* ``DESTROYED_TIME``: The amount of time (in seconds) it takes for a destroyed turret to repair itself.
-* ``destroyed_timer``: A variable for tracking the amount of time a turret has been destroyed.
-* ``bullet_scene``: The bullet scene the turret fires (same scene as the player's pistol)
-
-Whew, that's quite a few class variables!
-
-______
-
-Let's go through ``_ready`` next.
-
-Firstly, we get the vision area and connect the ``body_entered`` and ``body_exited`` signals to ``body_entered_vision`` and ``body_exited_vision``, respectively.
-
-We then get all the nodes and assign them to their respective variables.
-
-Next, we add some exceptions to the :ref:`Raycast <class_Raycast>` so the turret cannot hurt itself.
-
-Then we make both flash meshes invisible at start, since we are not going to be firing during ``_ready``.
-
-We then get the smoke particles node and assign it to the ``smoke_particles`` variable. We also set ``emitting`` to ``false`` to ensure the particles are
-not emitting until the turret is broken.
-
-Finally, we set the turret's health to ``MAX_TURRET_HEALTH`` so it starts at full health.
-
-______
-
-Now let's go through ``_physics_process``.
-
-Firstly, we check whether the turret is active. If the turret is active, we want to process the firing code.
-
-Next, if ``flash_timer`` is greater than zero, meaning the flash meshes are visible, we want to remove
-delta from ``flash_timer``. If ``flash_timer`` gets to zero or less after we've subtracted ``delta``, we want to hide
-both of the flash meshes.
-
-Next, we check whether the turret has a target. If the turret has a target, we make the turret head look at it, adding ``PLAYER_HEIGHT`` so it is not
-aiming at the player's feet.
-
-We then check whether the turret's health is greater than zero. If it is, we then check whether there is ammo in the turret.
-
-If there is, we then check whether ``fire_timer`` is greater than zero. If it is, the turret cannot fire and we need to
-remove ``delta`` from ``fire_timer``. If ``fire_timer`` is less than or equal to zero, the turret can fire a bullet, so we call the ``fire_bullet`` function.
-
-If there isn't any ammo in the turret, we check whether ``ammo_reload_timer`` is greater than zero. If it is,
-we subtract ``delta`` from ``ammo_reload_timer``. If ``ammo_reload_timer`` is less than or equal to zero, we set ``ammo_in_turret`` to ``AMMO_IN_FULL_TURRET`` because
-the turret has waited long enough to refill its ammo.
-
-Next, we check whether the turret's health is less than or equal to ``0`` outside of whether it is active or not. If the turret's health is zero or less, we then
-check whether ``destroyed_timer`` is greater than zero. If it is, we subtract ``delta`` from ``destroyed_timer``.
-
-If ``destroyed_timer`` is less than or equal to zero, we set ``turret_health`` to ``MAX_TURRET_HEALTH`` and stop emitting smoke particles by setting ``smoke_particles.emitting`` to
-``false``.
-
-______
-
-Next let's go through ``fire_bullet``.
-
-Firstly, we check whether the turret is using a raycast.
-
-The code for using a raycast is almost entirely the same as the code in the rifle from :ref:`doc_fps_tutorial_part_two`, so
-I'm only going to go over it briefly.
-
-We first make the raycast look at the target, ensuring the raycast will hit the target if nothing is in the way. We then force the raycast to update so we get a frame
-perfect collision check. We then check whether the raycast has collided with anything. If it has, we then check
-whether the collided body has the ``bullet_hit`` method. If it does, we call it and pass in the damage a single raycast bullet does along with the raycast's transform.
-We then subtract ``1`` from ``ammo_in_turret``.
-
-If the turret is not using a raycast, we spawn a bullet object instead. This code is almost entirely the same as the code in the pistol from :ref:`doc_fps_tutorial_part_two`, so
-like with the raycast code, I'm only going to go over it briefly.
-
-We first make a bullet clone and assign it to ``clone``. We then add that as a child of the root node. We set the bullet's global transform to
-the barrel end, scale it up since it's too small, and set its damage and speed using the turret's constant class variables. We then subtract ``1`` from
-``ammo_in_turret``.
-
-Then, regardless of which bullet method we used, we make both of the muzzle flash meshes visible. We set ``flash_timer`` and ``fire_timer``
-to ``FLASH_TIME`` and ``FIRE_TIME``, respectively. We then check whether the turret has used the last bullet in its ammo. If it has,
-we set ``ammo_reload_timer`` to ``AMMO_RELOAD_TIME`` so the turret reloads.
-
-______
-
-Let's look at ``body_entered_vision`` next, and thankfully it is rather short.
-
-We first check whether the turret currently has a target by checking if ``current_target`` is equal to ``null``.
-If the turret does not have a target, we then check whether the body that has just entered the vision :ref:`Area <class_Area>` is a :ref:`KinematicBody <class_KinematicBody>`.
-
-.. note:: We're assuming the turret should only fire at :ref:`KinematicBody <class_KinematicBody>` nodes since that is what the player is using.
-
-If the body that just entered the vision :ref:`Area <class_Area>` is a :ref:`KinematicBody <class_KinematicBody>`, we set ``current_target`` to the body, and set ``is_active`` to
-``true``.
-
-______
-
-Now let's look at ``body_exited_vision``.
-
-Firstly, we check whether the turret has a target. If it does, we then check whether the body that has just left the turret's vision :ref:`Area <class_Area>`
-is the turret's target.
-
-If the body that has just left the vision :ref:`Area <class_Area>` is the turret's current target, we set ``current_target`` to ``null``, set ``is_active`` to ``false``, and reset
-all the variables related to firing the turret since the turret no longer has a target to fire at.
-
-______
-
-Finally, let's look at ``bullet_hit``.
-
-We first subtract however much damage the bullet causes from the turret's health.
-
-Then, we check whether the turret has been destroyed (health being zero or less).
-If the turret is destroyed, we start emitting the smoke particles and set ``destroyed_timer`` to ``DESTROYED_TIME`` so the turret has to wait before being repaired.
-
-______
-
-Whew, with all of that done and coded, we only have one last thing to do before the turret is ready for use. Open up ``Turret.tscn`` if it's not already open and
-select one of the :ref:`StaticBody <class_StaticBody>` nodes from either ``Base`` or ``Head``. Create a new script called ``TurretBodies.gd`` and attach it to whichever
-:ref:`StaticBody <class_StaticBody>` you have selected.
-
-Add the following code to ``TurretBodies.gd``:
-
-::
-
-    extends StaticBody
-
-    export (NodePath) var path_to_turret_root
-
-    func _ready():
-        pass
-
-    func bullet_hit(damage, bullet_hit_pos):
-        if path_to_turret_root != null:
-            get_node(path_to_turret_root).bullet_hit(damage, bullet_hit_pos)
-
-All this code does is call ``bullet_hit`` on whatever node to which ``path_to_turret_root`` leads. Go back to the editor and assign the :ref:`NodePath <class_NodePath>`
-to the ``Turret`` node.
-
-Now select the other :ref:`StaticBody <class_StaticBody>` node (either in ``Body`` or ``Head``) and assign ``TurretBodies.gd`` script to it. Once the script is
-attached, assign again the :ref:`NodePath <class_NodePath>` to the ``Turret`` node.
-
-______
-
-The last thing we need to do is add a way for the player to be hurt. Since all the bullets use the ``bullet_hit`` function, we need to add that function to the player.
-
-Open ``Player.gd`` and add the following:
-
-::
-
-    func bullet_hit(damage, bullet_hit_pos):
-        health -= damage
-
-With all that done, you should have fully operational turrets! Go place a few in one/both/all of the scenes and give them a try!
-
-Final notes
------------
-
-.. image:: img/PartFiveFinished.png
-
-Now you can pick up :ref:`RigidBody <class_RigidBody>` nodes and throw grenades. We now also have turrets to fire at the player.
-
-In :ref:`doc_fps_tutorial_part_six`, we're going to add a main menu and a pause menu,
-add a respawn system for the player, and change/move the sound system so we can use it from any script.
-
-.. warning:: If you ever get lost, be sure to read over the code again!
-
-             You can download the finished project for this part here: :download:`Godot_FPS_Part_5.zip <files/Godot_FPS_Part_5.zip>`

+ 0 - 790
tutorials/3d/fps_tutorial/part_four.rst

@@ -1,790 +0,0 @@
-.. _doc_fps_tutorial_part_four:
-
-Part 4
-======
-
-Part overview
--------------
-
-In this part, we will be adding health pickups, ammo pickups, targets the player can destroy, support for joypads, and add the ability to change weapons with the scroll wheel.
-
-.. image:: img/PartFourFinished.png
-
-.. note:: You are assumed to have finished :ref:`doc_fps_tutorial_part_three` before moving on to this part of the tutorial.
-          The finished project from :ref:`doc_fps_tutorial_part_three` will be the starting project for part 4
-
-Let's get started!
-
-Adding joypad input
--------------------
-
-.. note:: In Godot, any game controller is referred to as a joypad. This includes:
-          Console controllers, Joysticks (like for flight simulators), Wheels (like for driving simulators), VR Controllers, and more!
-
-Firstly, we need to change a few things in our project's input map. Open up the project settings and select the ``Input Map`` tab.
-
-Now we need to add some joypad buttons to our various actions. Click the plus icon and select ``Joy Button``.
-
-.. image:: img/ProjectSettingsAddKey.png
-
-Feel free to use whatever button layout you want. Make sure that the device selected is set to ``0``. In the finished project, we will be using the following:
-
-* movement_sprint: ``Device 0, Button 4 (L, L1)``
-* fire: ``Device 0, Button 0 (PS Cross, XBox A, Nintendo B)``
-* reload: ``Device 0, Button 0 (PS Square, XBox X, Nintendo Y)``
-* flashlight: ``Device 0, Button 12 (D-Pad Up)``
-* shift_weapon_positive: ``Device 0, Button 15 (D-Pad Right)``
-* shift_weapon_negative: ``Device 0, Button 14 (D-Pad Left)``
-* fire_grenade: ``Device 0, Button 1 (PS Circle, XBox B, Nintendo A).``
-
-.. note:: These are already set up for you if you downloaded the starter assets
-
-Once you are happy with the input, close the project settings and save.
-
-______
-
-Now let's open up ``Player.gd`` and add joypad input.
-
-First, we need to define a few new class variables. Add the following class variables to ``Player.gd``:
-
-::
-
-    # You may need to adjust depending on the sensitivity of your joypad
-    var JOYPAD_SENSITIVITY = 2
-    const JOYPAD_DEADZONE = 0.15
-
-Let's go over what each of these does:
-
-* ``JOYPAD_SENSITIVITY``: This is how fast the joypad's joysticks will move the camera.
-* ``JOYPAD_DEADZONE``: The dead zone for the joypad. You may need to adjust depending on your joypad.
-
-.. note::  Many joypads jitter around a certain point. To counter this, we ignore any movement
-           within a radius of JOYPAD_DEADZONE. If we did not ignore said movement, the camera would jitter.
-
-           Also, we are defining ``JOYPAD_SENSITIVITY`` as a variable instead of a constant because we'll later be changing it.
-
-Now we are ready to start handling joypad input!
-
-______
-
-In ``process_input``, add the following code just before ``input_movement_vector = input_movement_vector.normalized()``:
-
-.. tabs::
- .. code-tab:: gdscript Xbox Controller
-
-    # Add joypad input if one is present
-    if Input.get_connected_joypads().size() > 0:
-
-        var joypad_vec = Vector2(0, 0)
-
-        if OS.get_name() == "Windows":
-            joypad_vec = Vector2(Input.get_joy_axis(0, 0), -Input.get_joy_axis(0, 1))
-        elif OS.get_name() == "X11":
-            joypad_vec = Vector2(Input.get_joy_axis(0, 1), Input.get_joy_axis(0, 2))
-        elif OS.get_name() == "OSX":
-            joypad_vec = Vector2(Input.get_joy_axis(0, 1), Input.get_joy_axis(0, 2))
-
-        if joypad_vec.length() < JOYPAD_DEADZONE:
-            joypad_vec = Vector2(0, 0)
-        else:
-            joypad_vec = joypad_vec.normalized() * ((joypad_vec.length() - JOYPAD_DEADZONE) / (1 - JOYPAD_DEADZONE))
-
-        input_movement_vector += joypad_vec
-
- .. code-tab:: gdscript PlayStation Controller
-
-    # Add joypad input if one is present
-    if Input.get_connected_joypads().size() > 0:
-
-        var joypad_vec = Vector2(0, 0)
-
-        if OS.get_name() == "Windows" or OS.get_name() == "X11":
-            joypad_vec = Vector2(Input.get_joy_axis(0, 0), -Input.get_joy_axis(0, 1))
-        elif OS.get_name() == "OSX":
-            joypad_vec = Vector2(Input.get_joy_axis(0, 1), Input.get_joy_axis(0, 2))
-
-        if joypad_vec.length() < JOYPAD_DEADZONE:
-            joypad_vec = Vector2(0, 0)
-        else:
-            joypad_vec = joypad_vec.normalized() * ((joypad_vec.length() - JOYPAD_DEADZONE) / (1 - JOYPAD_DEADZONE))
-
-        input_movement_vector += joypad_vec
-
-Let's go over what we're doing.
-
-Firstly, we check to see if there is a connected joypad.
-
-If there is a joypad connected, we then get its left stick axes for right/left and up/down.
-Because a wired Xbox 360 controller has different joystick axis mapping based on OS, we will use different axes based on
-the OS.
-
-.. warning:: This tutorial assumes you are using a XBox 360 or a PlayStation wired controller.
-             Also, I do not (currently) have access to a Mac computer, so the joystick axes may need changing.
-             If they do, please open a GitHub issue on the Godot documentation repository! Thanks!
-
-Next, we check to see if the joypad vector length is within the ``JOYPAD_DEADZONE`` radius.
-If it is, we set ``joypad_vec`` to an empty Vector2. If it is not, we use a scaled Radial Dead zone for precise dead zone calculation.
-
-.. note:: You can find a great article explaining all about how to handle joypad/controller dead zones
-          `here <https://web.archive.org/web/20191208161810/http://www.third-helix.com/2013/04/12/doing-thumbstick-dead-zones-right.html>`__.
-
-          We're using a translated version of the scaled radial dead zone code provided in that article.
-          The article is a great read, and I highly suggest giving it a look!
-
-Finally, we add ``joypad_vec`` to ``input_movement_vector``.
-
-.. tip:: Remember how we normalize ``input_movement_vector``? This is why! If we did not normalize ``input_movement_vector``, the player could
-         move faster if they pushed in the same direction with both the keyboard and the joypad!
-
-______
-
-Make a new function called ``process_view_input`` and add the following:
-
-.. tabs::
- .. code-tab:: gdscript Xbox Controller
-
-    func process_view_input(delta):
-
-        if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
-            return
-
-        # NOTE: Until some bugs relating to captured mice are fixed, we cannot put the mouse view
-        # rotation code here. Once the bug(s) are fixed, code for mouse view rotation code will go here!
-
-        # ----------------------------------
-        # Joypad rotation
-
-        var joypad_vec = Vector2()
-        if Input.get_connected_joypads().size() > 0:
-
-            if OS.get_name() == "Windows":
-                joypad_vec = Vector2(Input.get_joy_axis(0, 2), Input.get_joy_axis(0, 3))
-            elif OS.get_name() == "X11":
-                joypad_vec = Vector2(Input.get_joy_axis(0, 3), Input.get_joy_axis(0, 4))
-            elif OS.get_name() == "OSX":
-                joypad_vec = Vector2(Input.get_joy_axis(0, 3), Input.get_joy_axis(0, 4))
-
-            if joypad_vec.length() < JOYPAD_DEADZONE:
-                joypad_vec = Vector2(0, 0)
-            else:
-                joypad_vec = joypad_vec.normalized() * ((joypad_vec.length() - JOYPAD_DEADZONE) / (1 - JOYPAD_DEADZONE))
-
-            rotation_helper.rotate_x(deg2rad(joypad_vec.y * JOYPAD_SENSITIVITY))
-
-            rotate_y(deg2rad(joypad_vec.x * JOYPAD_SENSITIVITY * -1))
-
-            var camera_rot = rotation_helper.rotation_degrees
-            camera_rot.x = clamp(camera_rot.x, -70, 70)
-            rotation_helper.rotation_degrees = camera_rot
-        # ----------------------------------
-
- .. code-tab:: gdscript PlayStation Controller
-
-     func process_view_input(delta):
-
-        if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
-            return
-
-        # NOTE: Until some bugs relating to captured mice are fixed, we cannot put the mouse view
-        # rotation code here. Once the bug(s) are fixed, code for mouse view rotation code will go here!
-
-        # ----------------------------------
-        # Joypad rotation
-
-        var joypad_vec = Vector2()
-        if Input.get_connected_joypads().size() > 0:
-
-            if OS.get_name() == "Windows" or OS.get_name() == "X11":
-                joypad_vec = Vector2(Input.get_joy_axis(0, 2), Input.get_joy_axis(0, 3))
-            elif OS.get_name() == "OSX":
-                joypad_vec = Vector2(Input.get_joy_axis(0, 3), Input.get_joy_axis(0, 4))
-
-            if joypad_vec.length() < JOYPAD_DEADZONE:
-                joypad_vec = Vector2(0, 0)
-            else:
-                joypad_vec = joypad_vec.normalized() * ((joypad_vec.length() - JOYPAD_DEADZONE) / (1 - JOYPAD_DEADZONE))
-
-            rotation_helper.rotate_x(deg2rad(joypad_vec.y * JOYPAD_SENSITIVITY))
-
-            rotate_y(deg2rad(joypad_vec.x * JOYPAD_SENSITIVITY * -1))
-
-            var camera_rot = rotation_helper.rotation_degrees
-            camera_rot.x = clamp(camera_rot.x, -70, 70)
-            rotation_helper.rotation_degrees = camera_rot
-        # ----------------------------------
-
-Let's go over what's happening:
-
-Firstly, we check the mouse mode. If the mouse mode is not ``MOUSE_MODE_CAPTURED``, we want to return, which will skip the code below.
-
-Next, we define a new :ref:`Vector2 <class_Vector2>` called ``joypad_vec``. This will hold the right joystick position. Based on the OS, we set its values so
-it is mapped to the proper axes for the right joystick.
-
-.. warning:: As stated above, I do not (currently) have access to a Mac computer, so the joystick axes may need changing. If they do,
-             please open a GitHub issue on the Godot documentation repository! Thanks!
-
-We then account for the joypad's dead zone, exactly like in ``process_input``.
-
-Then, we rotate ``rotation_helper`` and the player's :ref:`KinematicBody <class_KinematicBody>` using ``joypad_vec``.
-
-Notice how the code that handles rotating the player and ``rotation_helper`` is exactly the same as the
-code in ``_input``. All we've done is change the values to use ``joypad_vec`` and ``JOYPAD_SENSITIVITY``.
-
-.. note:: Due to a few mouse-related bugs on Windows, we cannot put mouse rotation in ``process_view`` as well.
-          Once these bugs are fixed, this will likely be updated to place the mouse rotation here in ``process_view_input`` as well.
-
-Finally, we clamp the camera's rotation so the player cannot look upside down.
-
-______
-
-The last thing we need to do is add ``process_view_input`` to ``_physics_process``.
-
-Once ``process_view_input`` is added to ``_physics_process``, you should be able to play using a joypad!
-
-.. note:: I decided not to use the joypad triggers for firing because we'd then have to do some more axis managing, and because I prefer to use a shoulder buttons to fire.
-
-          If you want to use the triggers for firing, you will need to change how firing works in ``process_input``. You need to get the axis values for the triggers,
-          and check if it's over a certain value, say ``0.8`` for example. If it is, you add the same code as when the ``fire`` action was pressed.
-
-Adding mouse scroll wheel input
--------------------------------
-
-Let's add one more input related feature before we start working on the pickups and the target. Let's add the ability to change weapons using the scroll wheel on the mouse.
-
-Open up ``Player.gd`` and add the following class variables:
-
-::
-
-    var mouse_scroll_value = 0
-    const MOUSE_SENSITIVITY_SCROLL_WHEEL = 0.08
-
-Let's go over what each of these new variables will be doing:
-
-* ``mouse_scroll_value``: The value of the mouse scroll wheel.
-* ``MOUSE_SENSITIVITY_SCROLL_WHEEL``: How much a single scroll action increases mouse_scroll_value
-
-______
-
-Now let's add the following to ``_input``:
-
-::
-
-    if event is InputEventMouseButton and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
-        if event.button_index == BUTTON_WHEEL_UP or event.button_index == BUTTON_WHEEL_DOWN:
-            if event.button_index == BUTTON_WHEEL_UP:
-                mouse_scroll_value += MOUSE_SENSITIVITY_SCROLL_WHEEL
-            elif event.button_index == BUTTON_WHEEL_DOWN:
-                mouse_scroll_value -= MOUSE_SENSITIVITY_SCROLL_WHEEL
-
-            mouse_scroll_value = clamp(mouse_scroll_value, 0, WEAPON_NUMBER_TO_NAME.size() - 1)
-
-            if changing_weapon == false:
-                if reloading_weapon == false:
-                    var round_mouse_scroll_value = int(round(mouse_scroll_value))
-                    if WEAPON_NUMBER_TO_NAME[round_mouse_scroll_value] != current_weapon_name:
-                        changing_weapon_name = WEAPON_NUMBER_TO_NAME[round_mouse_scroll_value]
-                        changing_weapon = true
-                        mouse_scroll_value = round_mouse_scroll_value
-
-
-Let's go over what's happening here:
-
-Firstly, we check if the event is an ``InputEventMouseButton`` event and that the mouse mode is ``MOUSE_MODE_CAPTURED``.
-Then, we check to see if the button index is either a ``BUTTON_WHEEL_UP`` or ``BUTTON_WHEEL_DOWN`` index.
-
-If the event's index is indeed a button wheel index, we then check to see if it is a ``BUTTON_WHEEL_UP`` or ``BUTTON_WHEEL_DOWN`` index.
-Based on whether it is up or down, we add or subtract ``MOUSE_SENSITIVITY_SCROLL_WHEEL`` to/from ``mouse_scroll_value``.
-
-Next, we clamp mouse scroll value to ensure it is inside the range of selectable weapons.
-
-We then check to see if the player is changing weapons or reloading. If the player is doing neither, we round ``mouse_scroll_value`` and cast it to an ``int``.
-
-.. note:: We are casting ``mouse_scroll_value`` to an ``int`` so we can use it as a key in our dictionary. If we left it as a float,
-          we would get an error when we tried to run the project.
-
-Next, we check to see if the weapon name at ``round_mouse_scroll_value`` is not equal to the current weapon name using ``WEAPON_NUMBER_TO_NAME``.
-If the weapon is different from the player's current weapon, we assign ``changing_weapon_name``, set ``changing_weapon`` to ``true`` so the player will change weapons in
-``process_changing_weapon``, and set ``mouse_scroll_value`` to ``round_mouse_scroll_value``.
-
-.. tip:: The reason we are setting ``mouse_scroll_value`` to the rounded scroll value is because we do not want the player to keep their
-         mouse scroll wheel just in between values, giving them the ability to switch almost extremely fast. By assigning ``mouse_scroll_value``
-         to ``round_mouse_scroll_value``, we ensure that each weapon takes exactly the same amount of scrolling to change.
-
-______
-
-One more thing we need to change is in ``process_input``. In the code for changing weapons, add the following right after the line ``changing_weapon = true``:
-
-::
-
-    mouse_scroll_value = weapon_change_number
-
-Now the scroll value will be changed with the keyboard input. If we did not change this, the scroll value would be out of sync. If the scroll wheel were out of
-sync, scrolling forwards or backwards would not transition to the next/last weapon, but rather the next/last weapon the scroll wheel changed to.
-
-______
-
-Now you can change weapons using the scroll wheel! Go give it a whirl!
-
-Adding the health pickups
--------------------------
-
-Now that the player has health and ammo, we ideally need a way to replenish those resources.
-
-Open up ``Health_Pickup.tscn``.
-
-Expand ``Holder`` if it's not already expanded. Notice how we have two Spatial nodes, one called ``Health_Kit`` and another called ``Health_Kit_Small``.
-
-This is because we're actually going to be making two sizes of health pickups, one small and one large/normal. ``Health_Kit`` and ``Health_Kit_Small`` only
-have a single :ref:`MeshInstance <class_MeshInstance>` as their children.
-
-Next expand ``Health_Pickup_Trigger``. This is an :ref:`Area <class_Area>` node we're going to use to check if the player has walked close enough to pick up
-the health kit. If you expand it, you'll find two collision shapes, one for each size. We will be using a different collision shape size based on the size of the
-health pickup, so the smaller health pickup has a trigger collision shape closer to its size.
-
-The last thing to note is how we have an :ref:`AnimationPlayer <class_AnimationPlayer>` node so the health kit bobs and spins around slowly.
-
-Select ``Health_Pickup`` and add a new script called ``Health_Pickup.gd``. Add the following:
-
-::
-
-    extends Spatial
-
-    export (int, "full size", "small") var kit_size = 0 setget kit_size_change
-
-    # 0 = full size pickup, 1 = small pickup
-    const HEALTH_AMOUNTS = [70, 30]
-
-    const RESPAWN_TIME = 20
-    var respawn_timer = 0
-
-    var is_ready = false
-
-    func _ready():
-
-        $Holder/Health_Pickup_Trigger.connect("body_entered", self, "trigger_body_entered")
-
-        is_ready = true
-
-        kit_size_change_values(0, false)
-        kit_size_change_values(1, false)
-        kit_size_change_values(kit_size, true)
-
-
-    func _physics_process(delta):
-        if respawn_timer > 0:
-            respawn_timer -= delta
-
-            if respawn_timer <= 0:
-                kit_size_change_values(kit_size, true)
-
-
-    func kit_size_change(value):
-        if is_ready:
-            kit_size_change_values(kit_size, false)
-            kit_size = value
-            kit_size_change_values(kit_size, true)
-        else:
-            kit_size = value
-
-
-    func kit_size_change_values(size, enable):
-        if size == 0:
-            $Holder/Health_Pickup_Trigger/Shape_Kit.disabled = !enable
-            $Holder/Health_Kit.visible = enable
-        elif size == 1:
-            $Holder/Health_Pickup_Trigger/Shape_Kit_Small.disabled = !enable
-            $Holder/Health_Kit_Small.visible = enable
-
-
-    func trigger_body_entered(body):
-        if body.has_method("add_health"):
-            body.add_health(HEALTH_AMOUNTS[kit_size])
-            respawn_timer = RESPAWN_TIME
-            kit_size_change_values(kit_size, false)
-
-Let's go over what this script is doing, starting with its class variables:
-
-* ``kit_size``: The size of the health pickup. Notice how we're using a ``setget`` function to tell if it's changed.
-* ``HEALTH_AMMOUNTS``: The amount of health each pickup in each size contains.
-* ``RESPAWN_TIME``: The amount of time, in seconds, it takes for the health pickup to respawn
-* ``respawn_timer``: A variable used to track how long the health pickup has been waiting to respawn.
-* ``is_ready``: A variable to track whether the ``_ready`` function has been called or not.
-
-We're using ``is_ready`` because ``setget`` functions are called before ``_ready``; we need to ignore the
-first kit_size_change call, because we cannot access child nodes until ``_ready`` is called. If we did not ignore the
-first ``setget`` call, we would get several errors in the debugger.
-
-Also, notice how we are using an exported variable. This is so we can change the size of the health pickups in the editor. This makes it so
-we do not have to make two scenes for the two sizes, since we can easily change sizes in the editor using the exported variable.
-
-.. tip:: See :ref:`doc_GDScript` and scroll down to the Exports section for a list of export hints you can use.
-
-______
-
-Let's look at ``_ready``:
-
-Firstly, we connect the ``body_entered`` signal from the ``Health_Pickup_Trigger`` to the ``trigger_body_entered`` function. This makes it so any
-body that enters the :ref:`Area <class_Area>` triggers the ``trigger_body_entered`` function.
-
-Next, we set ``is_ready`` to ``true`` so we can use the ``setget`` function.
-
-Then we hide all the possible kits and their collision shapes using ``kit_size_change_values``. The first argument is the size of the kit, while the second argument
-is whether to enable or disable the collision shape and mesh at that size.
-
-Then we make only the kit size we selected visible, calling ``kit_size_change_values`` and passing in ``kit_size`` and ``true``, so the size at ``kit_size`` is enabled.
-
-______
-
-Next let's look at ``kit_size_change``.
-
-The first thing we do is check to see if ``is_ready`` is ``true``.
-
-If ``is_ready`` is ``true``, we then make whatever kit already assigned to ``kit_size`` disabled using ``kit_size_change_values``, passing in ``kit_size`` and ``false``.
-
-Then we assign ``kit_size`` to the new value passed in, ``value``. Then we call ``kit_size_change_values`` passing in ``kit_size`` again, but this time
-with the second argument as ``true`` so we enable it. Because we changed ``kit_size`` to the passed in value, this will make whatever kit size was passed in visible.
-
-If ``is_ready`` is not ``true``, we simply assign ``kit_size`` to the passed in ``value``.
-
-______
-
-Now let's look at ``kit_size_change_values``.
-
-The first thing we do is check to see which size was passed in. Based on which size we want to enable/disable, we want to get different nodes.
-
-We get the collision shape for the node corresponding to ``size`` and disable it based on the ``enabled`` passed in argument/variable.
-
-.. note:: Why are we using ``!enable`` instead of ``enable``? This is so when we say we want to enable the node, we can pass in ``true``, but since
-          :ref:`CollisionShape <class_CollisionShape>` uses disabled instead of enabled, we need to flip it. By flipping it, we can enable the collision shape
-          and make the mesh visible when ``true`` is passed in.
-
-We then get the correct :ref:`Spatial <class_Spatial>` node holding the mesh and set its visibility to ``enable``.
-
-This function may be a little confusing; try to think of it like this: We're enabling/disabling the proper nodes for ``size`` using ``enabled``. This is so we cannot pick up
-health for a size that is not visible, and so only the mesh for the proper size will be visible.
-
-______
-
-Finally, let's look at ``trigger_body_entered``.
-
-The first thing we do is check whether or not the body that has just entered has a method/function called ``add_health``. If it does, we then
-call ``add_health`` and pass in the health provided by the current kit size.
-
-Then we set ``respawn_timer`` to ``RESPAWN_TIME`` so the player has to wait before the player can get health again. Finally, call ``kit_size_change_values``,
-passing in ``kit_size`` and ``false`` so the kit at ``kit_size`` is invisible until it has waited long enough to respawn.
-
-_______
-
-The last thing we need to do before the player can use this health pickup is add a few things to ``Player.gd``.
-
-Open up ``Player.gd`` and add the following class variable:
-
-::
-
-    const MAX_HEALTH = 150
-
-* ``MAX_HEALTH``: The maximum amount of health a player can have.
-
-Now we need to add the ``add_health`` function to the player. Add the following to ``Player.gd``:
-
-::
-
-    func add_health(additional_health):
-        health += additional_health
-        health = clamp(health, 0, MAX_HEALTH)
-
-Let's quickly go over what this does.
-
-We first add ``additional_health`` to the player's current health. We then clamp the health so that it cannot take on a value higher than ``MAX_HEALTH``, nor a value lower
-than ``0``.
-
-_______
-
-With that done, the player can now collect health! Go place a few ``Health_Pickup`` scenes around and give it a try. You can change the size of the health pickup in the editor
-when a ``Health_Pickup`` instanced scene is selected, from a convenient drop down.
-
-Adding the ammo pickups
------------------------
-
-While adding health is good and all, we can't reap the rewards from adding it since nothing can (currently) damage us.
-Let's add some ammo pickups next!
-
-Open up ``Ammo_Pickup.tscn``. Notice how it's structured exactly the same as ``Health_Pickup.tscn``, but with the meshes and trigger collision shapes changed slightly to account
-for the difference in mesh sizes.
-
-Select ``Ammo_Pickup`` and add a new script called ``Ammo_Pickup.gd``. Add the following:
-
-::
-
-    extends Spatial
-
-    export (int, "full size", "small") var kit_size = 0 setget kit_size_change
-
-    # 0 = full size pickup, 1 = small pickup
-    const AMMO_AMOUNTS = [4, 1]
-
-    const RESPAWN_TIME = 20
-    var respawn_timer = 0
-
-    var is_ready = false
-
-    func _ready():
-
-        $Holder/Ammo_Pickup_Trigger.connect("body_entered", self, "trigger_body_entered")
-
-        is_ready = true
-
-        kit_size_change_values(0, false)
-        kit_size_change_values(1, false)
-
-        kit_size_change_values(kit_size, true)
-
-
-    func _physics_process(delta):
-        if respawn_timer > 0:
-            respawn_timer -= delta
-
-            if respawn_timer <= 0:
-                kit_size_change_values(kit_size, true)
-
-
-    func kit_size_change(value):
-        if is_ready:
-            kit_size_change_values(kit_size, false)
-            kit_size = value
-
-            kit_size_change_values(kit_size, true)
-        else:
-            kit_size = value
-
-
-    func kit_size_change_values(size, enable):
-        if size == 0:
-            $Holder/Ammo_Pickup_Trigger/Shape_Kit.disabled = !enable
-            $Holder/Ammo_Kit.visible = enable
-        elif size == 1:
-            $Holder/Ammo_Pickup_Trigger/Shape_Kit_Small.disabled = !enable
-            $Holder/Ammo_Kit_Small.visible = enable
-
-
-    func trigger_body_entered(body):
-        if body.has_method("add_ammo"):
-            body.add_ammo(AMMO_AMOUNTS[kit_size])
-            respawn_timer = RESPAWN_TIME
-            kit_size_change_values(kit_size, false)
-
-You may have noticed this code looks almost exactly the same as the health pickup. That's because it largely is the same! Only a few things
-have been changed, and that's what we're going to go over.
-
-Firstly, notice the change to ``AMMO_AMOUNTS`` from ``HEALTH_AMMOUNTS``. ``AMMO_AMOUNTS`` will be how many ammo clips/magazines the pickup adds to the current weapon.
-(Unlike in the case of ``HEALTH_AMMOUNTS``, which has stood for how many health points would be awarded, we add an entire clip to the current weapon instead of the raw ammo amount)
-
-The only other thing to notice is in ``trigger_body_entered``. We're checking for the existence of and calling a function called ``add_ammo`` instead of ``add_health``.
-
-Other than those two small changes, everything else is the same as the health pickup!
-
-_______
-
-All we need to do to make the ammo pickups work is add a new function to the player. Open ``Player.gd`` and add the following function:
-
-::
-
-    func add_ammo(additional_ammo):
-        if (current_weapon_name != "UNARMED"):
-            if (weapons[current_weapon_name].CAN_REFILL == true):
-                weapons[current_weapon_name].spare_ammo += weapons[current_weapon_name].AMMO_IN_MAG * additional_ammo
-
-Let's go over what this function does.
-
-The first thing we check is whether the player is ``UNARMED``. Because ``UNARMED`` does not have a node/script, we want to make sure the player is not
-``UNARMED`` before trying to get the node/script attached to ``current_weapon_name``.
-
-Next, we check to see if the current weapon can be refilled. If the current weapon can, we add a full clip/magazine worth of ammo to the weapon by
-multiplying the current weapon's ``AMMO_IN_MAG`` value by however many ammo clips we're adding (``additional_ammo``).
-
-_______
-
-With that done, you should now be able to get additional ammo! Go place some ammo pickups in one/both/all of the scenes and give it a try!
-
-.. note:: Notice how we're not limiting the amount of ammo you can carry. To limit the amount of ammo each weapon can carry, you need to add an additional variable to
-          each weapon's script, and then clamp the weapon's ``spare_ammo`` variable after adding ammo in ``add_ammo``.
-
-Adding breakable targets
-------------------------
-
-Before we end this part, let's add some targets.
-
-Open up ``Target.tscn`` and take a look at the scenes in the scene tree.
-
-Firstly, notice how we're not using a :ref:`RigidBody <class_RigidBody>` node, but a :ref:`StaticBody <class_StaticBody>` one.
-The reason behind this is our non-broken targets will not be moving anywhere; using a :ref:`RigidBody <class_RigidBody>` would be more hassle than
-it's worth since all it has to do is stay still.
-
-.. tip:: We also save a tiny bit of performance using a :ref:`StaticBody <class_StaticBody>` over a :ref:`RigidBody <class_RigidBody>`.
-
-The other thing to note is we have a node called ``Broken_Target_Holder``. This node is going to hold a spawned/instanced scene called
-``Broken_Target.tscn``. Open up ``Broken_Target.tscn``.
-
-Notice how the target is broken up into five pieces, each a :ref:`RigidBody <class_RigidBody>` node. We're going to spawn/instance this scene when the target takes too much damage
-and needs to be destroyed. Then, we're going to hide the non-broken target, so it looks like the target shattered rather than a shattered target was
-spawned/instanced.
-
-While you still have ``Broken_Target.tscn`` open, attach ``RigidBody_hit_test.gd`` to all of the :ref:`RigidBody <class_RigidBody>` nodes. This will make
-it so the player can shoot at the broken pieces and they will react to the bullets.
-
-Alright, now switch back to ``Target.tscn``, select the ``Target`` :ref:`StaticBody <class_StaticBody>` node and create a new script called ``Target.gd``.
-
-Add the following code to ``Target.gd``:
-
-::
-
-    extends StaticBody
-
-    const TARGET_HEALTH = 40
-    var current_health = 40
-
-    var broken_target_holder
-
-    # The collision shape for the target.
-    # NOTE: this is for the whole target, not the pieces of the target.
-    var target_collision_shape
-
-    const TARGET_RESPAWN_TIME = 14
-    var target_respawn_timer = 0
-
-    export (PackedScene) var destroyed_target
-
-    func _ready():
-        broken_target_holder = get_parent().get_node("Broken_Target_Holder")
-        target_collision_shape = $Collision_Shape
-
-
-    func _physics_process(delta):
-        if target_respawn_timer > 0:
-            target_respawn_timer -= delta
-
-            if target_respawn_timer <= 0:
-
-                for child in broken_target_holder.get_children():
-                    child.queue_free()
-
-                target_collision_shape.disabled = false
-                visible = true
-                current_health = TARGET_HEALTH
-
-
-    func bullet_hit(damage, bullet_transform):
-        current_health -= damage
-
-        if current_health <= 0:
-            var clone = destroyed_target.instance()
-            broken_target_holder.add_child(clone)
-
-            for rigid in clone.get_children():
-                if rigid is RigidBody:
-                    var center_in_rigid_space = broken_target_holder.global_transform.origin - rigid.global_transform.origin
-                    var direction = (rigid.transform.origin - center_in_rigid_space).normalized()
-                    # Apply the impulse with some additional force (I find 12 works nicely).
-                    rigid.apply_impulse(center_in_rigid_space, direction * 12 * damage)
-
-            target_respawn_timer = TARGET_RESPAWN_TIME
-
-            target_collision_shape.disabled = true
-            visible = false
-
-Let's go over what this script does, starting with the class variables:
-
-* ``TARGET_HEALTH``: The amount of damage needed to break a fully healed target.
-* ``current_health``: The amount of health this target currently has.
-* ``broken_target_holder``: A variable to hold the ``Broken_Target_Holder`` node so we can use it easily.
-* ``target_collision_shape``: A variable to hold the :ref:`CollisionShape <class_CollisionShape>` for the non-broken target.
-* ``TARGET_RESPAWN_TIME``: The length of time, in seconds, it takes for a target to respawn.
-* ``target_respawn_timer``: A variable to track how long a target has been broken.
-* ``destroyed_target``: A :ref:`PackedScene <class_PackedScene>` to hold the broken target scene.
-
-Notice how we're using an exported variable (a :ref:`PackedScene <class_PackedScene>`) to get the broken target scene instead of
-using ``preload``. By using an exported variable, we can choose the scene from the editor, and if we need to use a different scene,
-it's as easy as selecting a different scene in the editor; we don't need to go to the code to change the scene we're using.
-
-______
-
-Let's look at ``_ready``.
-
-The first thing we do is get the broken target holder and assign it to ``broken_target_holder``. Notice how we're using ``get_parent().get_node()`` here, instead
-of ``$``. If you wanted to use ``$``, then you'd need to change ``get_parent().get_node()`` to ``$"../Broken_Target_Holder"``.
-
-.. note:: At the time of when this was written, I did not realize you can use ``$"../NodeName"`` to get the parent nodes using ``$``, which is why ``get_parent().get_node()``
-          is used instead.
-
-Next, we get the collision shape and assign it to ``target_collision_shape``. The reason we need the collision shape is because even when the mesh is invisible, the
-collision shape will still exist in the physics world. This makes it so the player could interact with a non-broken target even though it's invisible, which is
-not what we want. To get around this, we will disable/enable the collision shape as we make the mesh visible/invisible.
-
-______
-
-Next let's look at ``_physics_process``.
-
-We're only going to be using ``_physics_process`` for respawning, and so the first thing we do is check to see if ``target_respawn_timer`` is greater than ``0``.
-
-If it is, we then subtract ``delta`` from it.
-
-Then we check to see if ``target_respawn_timer`` is ``0`` or less. The reason behind this is since we just removed ``delta`` from ``target_respawn_timer``, if it's
-``0`` or less, then the target just got here, effectively allowing us to do whatever we need to do when the timer is finished.
-
-In this case, we want to respawn the target.
-
-The first thing we do is remove all children in the broken target holder. We do this by iterating over all of the children in ``broken_target_holder`` and free them using ``queue_free``.
-
-Next, we enable the collision shape by setting its ``disabled`` boolean to ``false``.
-
-Then we make the target, and all of its children nodes, visible again.
-
-Finally, we reset the target's health (``current_health``) to ``TARGET_HEALTH``.
-
-______
-
-Finally, let's look at ``bullet_hit``.
-
-The first thing we do is subtract however much damage the bullet does from the target's health.
-
-Next we check to see if the target is at ``0`` health or lower. If it is, the target has just died and we need to spawn a broken target.
-
-We first instance a new destroyed target scene, and assign it to a new variable, a ``clone``.
-
-Next we add the ``clone`` as a child of the broken target holder.
-
-For bonus effect, we want to make all the target pieces explode outwards. To do this, we iterate over all the children in ``clone``.
-
-For each child, we first check to see if it's a :ref:`RigidBody <class_RigidBody>` node. If it is, we then calculate the center position of the target relative
-to the child node. Then we figure out which direction the child node is relative to the center. Using those calculated variables, we push the child from the calculated center,
-in the direction away from the center, using the damage of the bullet as the force.
-
-.. note:: We multiply the damage by ``12`` so it has a more dramatic effect. You can change this to a higher or lower value depending on how explosively you want
-          your targets to shatter.
-
-Next, we set the target's respawn timer. We set the timer to ``TARGET_RESPAWN_TIME``, so it takes ``TARGET_RESPAWN_TIME`` in seconds until it is respawned.
-
-Then we disable the non-broken target's collision shape, and set the target's visibility to ``false``.
-
-______
-
-.. warning:: Make sure to set the exported ``destroyed_target`` value for ``Target.tscn`` in the editor! Otherwise the targets will not be destroyed
-             and you will get an error!
-
-With that done, go place some ``Target.tscn`` instances around in one/both/all of the levels. You should find they explode into five pieces after they've taken enough
-damage. After a little while, they'll respawn into a whole target again.
-
-Final notes
------------
-
-.. image:: img/PartFourFinished.png
-
-Now you can use a joypad, change weapons with the mouse's scroll wheel, replenish your health and ammo, and break targets with your weapons.
-
-In the next part, :ref:`doc_fps_tutorial_part_five`, we're going to add grenades to our player, give our player the ability to grab and throw objects, and
-add turrets!
-
-.. warning:: If you ever get lost, be sure to read over the code again!
-
-             You can download the finished project for this part here: :download:`Godot_FPS_Part_4.zip <files/Godot_FPS_Part_4.zip>`
-

+ 0 - 852
tutorials/3d/fps_tutorial/part_one.rst

@@ -1,852 +0,0 @@
-.. _doc_fps_tutorial_part_one:
-
-Part 1
-======
-
-Tutorial introduction
----------------------
-
-.. image:: img/FinishedTutorialPicture.png
-
-This tutorial series will show you how to make a single player FPS game.
-
-Throughout the course of this tutorial series, we will cover how:
-
-- To make a first person character that can move, sprint, and jump.
-- To make a simple animation state machine for handling animation transitions.
-- To add three weapons to the first person character, each using a different way to handle bullet collisions:
-- - A knife (using an :ref:`Area <class_Area>`)
-- - A pistol (Bullet scenes)
-- - A rifle (using a :ref:`Raycast <class_Raycast>`)
-- To add two different types of grenades to the first person character:
-- - A normal grenade
-- - A sticky grenade
-- To add the ability to grab and throw :ref:`RigidBody <class_RigidBody>` nodes
-- To add joypad input for the player
-- To add ammo and reloading for all weapons that consume ammo.
-- To add ammo and health pick ups
-- - In two sizes: big and small
-- To add an automatic turret
-- - That can fire using bullet objects or a :ref:`Raycast <class_Raycast>`
-- To add targets that break when they've taken enough damage
-- To add sounds that play when the guns fire.
-- To add a simple main menu:
-- - With an options menu for changing how the game runs
-- - With a level select screen
-- To add a universal pause menu we can access anywhere
-
-.. note:: While this tutorial can be completed by beginners, it is highly
-          advised to complete :ref:`doc_your_first_game`,
-          if you are new to Godot and/or game development **before** going through
-          this tutorial series.
-
-          Remember: Making 3D games is much harder than making 2D games. If you do not know
-          how to make 2D games, you will likely struggle making 3D games.
-
-          This tutorial assumes you have experience working with the Godot editor,
-          basic programming experience in GDScript, and basic experience in game development.
-
-You can find the start assets for this tutorial here: :download:`Godot_FPS_Starter.zip <files/Godot_FPS_Starter.zip>`
-
-The provided starter assets contain an animated 3D model, a bunch of 3D models for making levels,
-and a few scenes already configured for this tutorial.
-
-All assets provided (unless otherwise noted) were originally created by TwistedTwigleg, with changes/additions by the Godot community.
-All original assets provided for this tutorial are released under the ``MIT`` license.
-
-Feel free to use these assets however you want! All original assets belong to the Godot community, with the other assets belonging to those listed below:
-
-.. note:: The skybox is created by **StumpyStrust** on OpenGameArt. The skybox used is
-          licensed under ``CC0``.
-
-          The font used is **Titillium-Regular**, and is licensed under the ``SIL Open Font License, Version 1.1``.
-
-.. tip:: You can find the finished project for each part at the bottom of each part's page
-
-Part overview
--------------
-
-In this part we will be making a first person player that can move around
-the environment.
-
-.. image:: img/PartOneFinished.png
-
-By the end of this part, you will have a working first-person character who can move around the game environment,
-sprint, look around with a mouse based first person camera, jump into the air, and turn a flash light on and off.
-
-Getting everything ready
-------------------------
-
-Launch Godot and open up the project included in the starter assets.
-
-.. note:: While these assets are not necessarily required to use the scripts provided in this tutorial,
-          they will make the tutorial much easier to follow, as there are several pre-setup scenes we
-          will be using throughout the tutorial series.
-
-First, open the project settings and go to the "Input Map" tab. You'll find several
-actions have already been defined. We will be using these actions for our player.
-Feel free to change the keys bound to these actions if you want.
-
-_________
-
-Let's take a second to see what we have in the starter assets.
-
-Included in the starter assets are several scenes. For example, in ``res://`` we have 14 scenes, most of which we will be visiting as
-we go through this tutorial series.
-
-For now let's open up ``Player.tscn``.
-
-.. note:: There are a bunch of scenes and a few textures in the ``Assets`` folder. You can look at these if you want,
-          but we will not be exploring through ``Assets`` in this tutorial series. ``Assets`` contains all the models used
-          for each of the levels, as well as some textures and materials.
-
-Making the FPS movement logic
------------------------------
-
-Once you have ``Player.tscn`` open, let's take a quick look at how it is set up:
-
-.. image:: img/PlayerSceneTree.png
-
-First, notice how the player's collision shapes are set up. Using a vertical pointing
-capsule as the collision shape for the player is fairly common in most first person games.
-
-We are adding a small square to the 'feet' of the player so the player does not
-feel like they are balancing on a single point.
-
-We do want the 'feet' slightly higher than the bottom of the capsule so we can roll over slight edges.
-Where to place the 'feet' is dependent on your levels and how you want your player to feel.
-
-.. note:: Many times the player will notice the collision shape being circular when
-          they walk to an edge and slide off. We are adding the small square at the
-          bottom of the capsule to reduce sliding on, and around, edges.
-
-Another thing to notice is how many nodes are children of ``Rotation_Helper``. This is because
-``Rotation_Helper`` contains all the nodes we want to rotate on the ``X`` axis (up and down).
-The reason behind this is so we can rotate ``Player`` on the ``Y`` axis, and ``Rotation_helper`` on
-the ``X`` axis.
-
-.. note:: Had we not used ``Rotation_helper``, we would've likely had cases of rotating on
-          both the ``X`` and ``Y`` axes simultaneously, potentially further degenerating into a state of
-          rotation on all three axes in some cases.
-
-          See :ref:`using transforms <doc_using_transforms>` for more information
-
-_________
-
-Attach a new script to the ``Player`` node and call it ``Player.gd``.
-
-Let's program our player by adding the ability to move around, look around with the mouse, and jump.
-Add the following code to ``Player.gd``:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    extends KinematicBody
-
-    const GRAVITY = -24.8
-    var vel = Vector3()
-    const MAX_SPEED = 20
-    const JUMP_SPEED = 18
-    const ACCEL = 4.5
-
-    var dir = Vector3()
-
-    const DEACCEL= 16
-    const MAX_SLOPE_ANGLE = 40
-
-    var camera
-    var rotation_helper
-
-    var MOUSE_SENSITIVITY = 0.05
-
-    func _ready():
-        camera = $Rotation_Helper/Camera
-        rotation_helper = $Rotation_Helper
-
-        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-
-    func _physics_process(delta):
-        process_input(delta)
-        process_movement(delta)
-
-    func process_input(delta):
-
-        # ----------------------------------
-        # Walking
-        dir = Vector3()
-        var cam_xform = camera.get_global_transform()
-
-        var input_movement_vector = Vector2()
-
-        if Input.is_action_pressed("movement_forward"):
-            input_movement_vector.y += 1
-        if Input.is_action_pressed("movement_backward"):
-            input_movement_vector.y -= 1
-        if Input.is_action_pressed("movement_left"):
-            input_movement_vector.x -= 1
-        if Input.is_action_pressed("movement_right"):
-            input_movement_vector.x += 1
-
-        input_movement_vector = input_movement_vector.normalized()
-
-        # Basis vectors are already normalized.
-        dir += -cam_xform.basis.z * input_movement_vector.y
-        dir += cam_xform.basis.x * input_movement_vector.x
-        # ----------------------------------
-
-        # ----------------------------------
-        # Jumping
-        if is_on_floor():
-            if Input.is_action_just_pressed("movement_jump"):
-                vel.y = JUMP_SPEED
-        # ----------------------------------
-
-        # ----------------------------------
-        # Capturing/Freeing the cursor
-        if Input.is_action_just_pressed("ui_cancel"):
-            if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE:
-                Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-            else:
-                Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
-        # ----------------------------------
-
-    func process_movement(delta):
-        dir.y = 0
-        dir = dir.normalized()
-
-        vel.y += delta * GRAVITY
-
-        var hvel = vel
-        hvel.y = 0
-
-        var target = dir
-        target *= MAX_SPEED
-
-        var accel
-        if dir.dot(hvel) > 0:
-            accel = ACCEL
-        else:
-            accel = DEACCEL
-
-        hvel = hvel.linear_interpolate(target, accel * delta)
-        vel.x = hvel.x
-        vel.z = hvel.z
-        vel = move_and_slide(vel, Vector3(0, 1, 0), 0.05, 4, deg2rad(MAX_SLOPE_ANGLE))
-
-    func _input(event):
-        if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
-            rotation_helper.rotate_x(deg2rad(event.relative.y * MOUSE_SENSITIVITY))
-            self.rotate_y(deg2rad(event.relative.x * MOUSE_SENSITIVITY * -1))
-
-            var camera_rot = rotation_helper.rotation_degrees
-            camera_rot.x = clamp(camera_rot.x, -70, 70)
-            rotation_helper.rotation_degrees = camera_rot
-
- .. code-tab:: csharp
-
-    using Godot;
-    using System;
-
-    public class Player : KinematicBody
-    {
-        [Export]
-        public float Gravity = -24.8f;
-        [Export]
-        public float MaxSpeed = 20.0f;
-        [Export]
-        public float JumpSpeed = 18.0f;
-        [Export]
-        public float Accel = 4.5f;
-        [Export]
-        public float Deaccel = 16.0f;
-        [Export]
-        public float MaxSlopeAngle = 40.0f;
-        [Export]
-        public float MouseSensitivity = 0.05f;
-
-        private Vector3 _vel = new Vector3();
-        private Vector3 _dir = new Vector3();
-
-        private Camera _camera;
-        private Spatial _rotationHelper;
-
-        // Called when the node enters the scene tree for the first time.
-        public override void _Ready()
-        {
-            _camera = GetNode<Camera>("Rotation_Helper/Camera");
-            _rotationHelper = GetNode<Spatial>("Rotation_Helper");
-
-            Input.SetMouseMode(Input.MouseMode.Captured);
-        }
-
-        public override void _PhysicsProcess(float delta)
-        {
-            ProcessInput(delta);
-            ProcessMovement(delta);
-        }
-
-        private void ProcessInput(float delta)
-        {
-            //  -------------------------------------------------------------------
-            //  Walking
-            _dir = new Vector3();
-            Transform camXform = _camera.GlobalTransform;
-
-            Vector2 inputMovementVector = new Vector2();
-
-            if (Input.IsActionPressed("movement_forward"))
-                inputMovementVector.y += 1;
-            if (Input.IsActionPressed("movement_backward"))
-                inputMovementVector.y -= 1;
-            if (Input.IsActionPressed("movement_left"))
-                inputMovementVector.x -= 1;
-            if (Input.IsActionPressed("movement_right"))
-                inputMovementVector.x += 1;
-
-            inputMovementVector = inputMovementVector.Normalized();
-
-            // Basis vectors are already normalized.
-            _dir += -camXform.basis.z * inputMovementVector.y;
-            _dir += camXform.basis.x * inputMovementVector.x;
-            //  -------------------------------------------------------------------
-
-            //  -------------------------------------------------------------------
-            //  Jumping
-            if (IsOnFloor())
-            {
-                if (Input.IsActionJustPressed("movement_jump"))
-                    _vel.y = JumpSpeed;
-            }
-            //  -------------------------------------------------------------------
-
-            //  -------------------------------------------------------------------
-            //  Capturing/Freeing the cursor
-            if (Input.IsActionJustPressed("ui_cancel"))
-            {
-                if (Input.GetMouseMode() == Input.MouseMode.Visible)
-                    Input.SetMouseMode(Input.MouseMode.Captured);
-                else
-                    Input.SetMouseMode(Input.MouseMode.Visible);
-            }
-            //  -------------------------------------------------------------------
-        }
-
-        private void ProcessMovement(float delta)
-        {
-            _dir.y = 0;
-            _dir = _dir.Normalized();
-
-            _vel.y += delta * Gravity;
-
-            Vector3 hvel = _vel;
-            hvel.y = 0;
-
-            Vector3 target = _dir;
-
-            target *= MaxSpeed;
-
-            float accel;
-            if (_dir.Dot(hvel) > 0)
-                accel = Accel;
-            else
-                accel = Deaccel;
-
-            hvel = hvel.LinearInterpolate(target, accel * delta);
-            _vel.x = hvel.x;
-            _vel.z = hvel.z;
-            _vel = MoveAndSlide(_vel, new Vector3(0, 1, 0), false, 4, Mathf.Deg2Rad(MaxSlopeAngle));
-        }
-
-        public override void _Input(InputEvent @event)
-        {
-            if (@event is InputEventMouseMotion && Input.GetMouseMode() == Input.MouseMode.Captured)
-            {
-                InputEventMouseMotion mouseEvent = @event as InputEventMouseMotion;
-                _rotationHelper.RotateX(Mathf.Deg2Rad(mouseEvent.Relative.y * MouseSensitivity));
-                RotateY(Mathf.Deg2Rad(-mouseEvent.Relative.x * MouseSensitivity));
-
-                Vector3 cameraRot = _rotationHelper.RotationDegrees;
-                cameraRot.x = Mathf.Clamp(cameraRot.x, -70, 70);
-                _rotationHelper.RotationDegrees = cameraRot;
-            }
-        }
-    }
-
-This is a lot of code, so let's break it down function by function:
-
-.. tip:: While copy and pasting code is ill advised, as you can learn a lot from manually typing the code in, you can
-         copy and paste the code from this page directly into the script editor.
-
-         If you do this, all the code copied will be using spaces instead of tabs.
-
-         To convert the spaces to tabs in the script editor, click the "edit" menu and select "Convert Indent To Tabs".
-         This will convert all the spaces into tabs. You can select "Convert Indent To Spaces" to convert tabs back into spaces.
-
-_________
-
-First, we define some class variables to dictate how our player will move about the world.
-
-.. note:: Throughout this tutorial, **variables defined outside functions will be
-          referred to as "class variables"**. This is because we can access any of these
-          variables from any place in the script.
-
-Let's go through each of the class variables:
-
-- ``GRAVITY``: How strong gravity pulls us down.
-- ``vel``: Our :ref:`KinematicBody <class_KinematicBody>`'s velocity.
-- ``MAX_SPEED``: The fastest speed we can reach. Once we hit this speed, we will not go any faster.
-- ``JUMP_SPEED``: How high we can jump.
-- ``ACCEL``: How quickly we accelerate. The higher the value, the sooner we get to max speed.
-- ``DEACCEL``: How quickly we are going to decelerate. The higher the value, the sooner we will come to a complete stop.
-- ``MAX_SLOPE_ANGLE``: The steepest angle our :ref:`KinematicBody <class_KinematicBody>` will consider as a 'floor'.
-- ``camera``: The :ref:`Camera <class_Camera>` node.
-- ``rotation_helper``: A :ref:`Spatial <class_Spatial>` node holding everything we want to rotate on the X axis (up and down).
-- ``MOUSE_SENSITIVITY``: How sensitive the mouse is. I find a value of ``0.05`` works well for my mouse, but you may need to change it based on how sensitive your mouse is.
-
-You can tweak many of these variables to get different results. For example, by lowering ``GRAVITY`` and/or
-increasing ``JUMP_SPEED`` you can get a more 'floaty' feeling character.
-Feel free to experiment!
-
-.. note:: You may have noticed that ``MOUSE_SENSITIVITY`` is written in all caps like the other constants, but ``MOUSE_SENSITIVITY`` is not a constant.
-
-          The reason behind this is we want to treat it like a constant variable (a variable that cannot change) throughout our script, but we want to be
-          able to change the value later when we add customizable settings. So, in an effort to remind ourselves to treat it like a constant, it's named in all caps.
-
-_________
-
-Now let's look at the ``_ready`` function:
-
-First we get the ``camera`` and ``rotation_helper`` nodes and store them into their variables.
-
-Then we need to set the mouse mode to captured, so the mouse cannot leave the game window.
-
-This will hide the mouse and keep it at the center of the screen. We do this for two reasons:
-The first reason being we do not want the player to see their mouse cursor as they play.
-
-The second reason is because we do not want the cursor to leave the game window. If the cursor leaves
-the game window there could be instances where the player clicks outside the window, and then the game
-would lose focus. To assure neither of these issues happens, we capture the mouse cursor.
-
-.. note:: See :ref:`Input documentation <class_Input>` for the various mouse modes. We will only be using
-          ``MOUSE_MODE_CAPTURED`` and ``MOUSE_MODE_VISIBLE`` in this tutorial series.
-
-_________
-
-Next let's take a look at ``_physics_process``:
-
-All we're doing in ``_physics_process`` is calling two functions: ``process_input`` and ``process_movement``.
-
-``process_input`` will be where we store all the code relating to player input. We want to call it first, before
-anything else, so we have fresh player input to work with.
-
-``process_movement`` is where we'll send all the data necessary to the :ref:`KinematicBody <class_KinematicBody>`
-so it can move through the game world.
-
-_________
-
-Let's look at ``process_input`` next:
-
-First we set ``dir`` to an empty :ref:`Vector3 <class_Vector3>`.
-
-``dir`` will be used for storing the direction the player intends to move towards. Because we do not
-want the player's previous input to effect the player beyond a single ``process_movement`` call, we reset ``dir``.
-
-Next we get the camera's global transform and store it as well, into the ``cam_xform`` variable.
-
-The reason we need the camera's global transform is so we can use its directional vectors.
-Many have found directional vectors confusing, so let's take a second to explain how they work:
-
-_________
-
-World space can be defined as: The space in which all objects are placed in, relative to a constant origin point.
-Every object, no matter if it is 2D or 3D, has a position in world space.
-
-To put it another way: world space is the space in a universe where every object's position, rotation, and scale
-can be measured by a single, known, fixed point called the origin.
-
-In Godot, the origin is at position ``(0, 0, 0)`` with a rotation of ``(0, 0, 0)`` and a scale of ``(1, 1, 1)``.
-
-.. note:: When you open up the Godot editor and select a :ref:`Spatial <class_Spatial>` based node, a gizmo pops up.
-          Each of the arrows points using world space directions by default.
-
-If you want to move using the world space directional vectors, you'd do something like this:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    if Input.is_action_pressed("movement_forward"):
-        node.translate(Vector3(0, 0, 1))
-    if Input.is_action_pressed("movement_backward"):
-        node.translate(Vector3(0, 0, -1))
-    if Input.is_action_pressed("movement_left"):
-        node.translate(Vector3(1, 0, 0))
-    if Input.is_action_pressed("movement_right"):
-        node.translate(Vector3(-1, 0, 0))
-
- .. code-tab:: csharp
-
-    if (Input.IsActionPressed("movement_forward"))
-        node.Translate(new Vector3(0, 0, 1));
-    if (Input.IsActionPressed("movement_backward"))
-        node.Translate(new Vector3(0, 0, -1));
-    if (Input.IsActionPressed("movement_left"))
-        node.Translate(new Vector3(1, 0, 0));
-    if (Input.IsActionPressed("movement_right"))
-        node.Translate(new Vector3(-1, 0, 0));
-
-.. note:: Notice how we do not need to do any calculations to get world space directional vectors.
-          We can define a few :ref:`Vector3 <class_Vector3>` variables and input the values pointing in each direction.
-
-Here is what world space looks like in 2D:
-
-.. note:: The following images are just examples. Each arrow/rectangle represents a directional vector
-
-.. image:: img/WorldSpaceExample.png
-
-And here is what it looks like for 3D:
-
-.. image:: img/WorldSpaceExample_3D.png
-
-Notice how in both examples, the rotation of the node does not change the directional arrows.
-This is because world space is a constant. No matter how you translate, rotate, or scale an object, world
-space will *always point in the same direction*.
-
-Local space is different, because it takes the rotation of the object into account.
-
-Local space can be defined as follows:
-The space in which an object's position is the origin of the universe. Because the position
-of the origin can be at ``N`` many locations, the values derived from local space change
-with the position of the origin.
-
-.. note:: This question from Game Development Stack Exchange has a much better explanation of world space and local space.
-
-          https://gamedev.stackexchange.com/questions/65783/what-are-world-space-and-eye-space-in-game-development
-          (Local space and eye space are essentially the same thing in this context)
-
-To get a :ref:`Spatial <class_Spatial>` node's local space, we need to get its :ref:`Transform <class_Transform>`, so then we
-can get the :ref:`Basis <class_Basis>` from the :ref:`Transform <class_Transform>`.
-
-Each :ref:`Basis <class_Basis>` has three vectors: ``X``, ``Y``, and ``Z``.
-Each of those vectors point towards each of the local space vectors coming from that object.
-
-To use the :ref:`Spatial <class_Spatial>` node's local directional vectors, we use this code:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    if Input.is_action_pressed("movement_forward"):
-        node.translate(node.global_transform.basis.z.normalized())
-    if Input.is_action_pressed("movement_backward"):
-        node.translate(-node.global_transform.basis.z.normalized())
-    if Input.is_action_pressed("movement_left"):
-        node.translate(node.global_transform.basis.x.normalized())
-    if Input.is_action_pressed("movement_right"):
-        node.translate(-node.global_transform.basis.x.normalized())
-
- .. code-tab:: csharp
-
-    if (Input.IsActionPressed("movement_forward"))
-        node.Translate(node.GlobalTransform.basis.z.Normalized());
-    if (Input.IsActionPressed("movement_backward"))
-        node.Translate(-node.GlobalTransform.basis.z.Normalized());
-    if (Input.IsActionPressed("movement_left"))
-        node.Translate(node.GlobalTransform.basis.x.Normalized());
-    if (Input.IsActionPressed("movement_right"))
-        node.Translate(-node.GlobalTransform.basis.x.Normalized());
-
-Here is what local space looks like in 2D:
-
-.. image:: img/LocalSpaceExample.png
-
-And here is what it looks like for 3D:
-
-.. image:: img/LocalSpaceExample_3D.png
-
-Here is what the :ref:`Spatial <class_Spatial>` gizmo shows when you are using local space mode.
-Notice how the arrows follow the rotation of the object on the left, which looks exactly
-the same as the 3D example for local space.
-
-.. note:: You can change between local and world space modes by pressing :kbd:`T` or the little cube button
-          when you have a :ref:`Spatial <class_Spatial>` based node selected.
-
-.. image:: img/LocalSpaceExampleGizmo.png
-
-Local vectors are confusing even for more experienced game developers, so do not worry if this all doesn't make a
-lot of sense. The key thing to remember about local vectors is that we are using local coordinates to get direction
-from the object's point of view, as opposed to using world vectors, which give direction from the world's point of view.
-
-_________
-
-Okay, back to ``process_input``:
-
-Next we make a new variable called ``input_movement_vector`` and assign it to an empty :ref:`Vector2 <class_Vector2>`.
-We will use this to make a virtual axis of sorts, to map the player's input to movement.
-
-.. note:: This may seem overkill for just the keyboard, but this will make sense later when we add joypad input.
-
-Based on which directional movement action is pressed, we add to or subtract from ``input_movement_vector``.
-
-After we've checked each of the directional movement actions, we normalize ``input_movement_vector``. This makes it where ``input_movement_vector``'s values
-are within a ``1`` radius unit circle.
-
-Next we add the camera's local ``Z`` vector times ``input_movement_vector.y`` to ``dir``. This is so when the player presses forward or backwards, we add the camera's
-local ``Z`` axis so the player moves forward or backwards in relation to the camera.
-
-.. note:: Because the camera is rotated by ``-180`` degrees, we have to flip the ``Z`` directional vector.
-          Normally forward would be the positive Z axis, so using ``basis.z.normalized()`` would work,
-          but we are using ``-basis.z.normalized()`` because our camera's Z axis faces backwards in relation
-          to the rest of the player.
-
-We do the same thing for the camera's local ``X`` vector, and instead of using ``input_movement_vector.y`` we instead use ``input_movement_vector.x``.
-This makes it where the player moves left/right in relation to the camera when the player presses left/right.
-
-Next we check if the player is on the floor using :ref:`KinematicBody <class_KinematicBody>`'s ``is_on_floor`` function. If it is, then we
-check to see if the "movement_jump" action has just been pressed. If it has, then we set the player's ``Y`` velocity to
-``JUMP_SPEED``.
-
-Because we're setting the Y velocity, the player will jump into the air.
-
-Then we check for the ``ui_cancel`` action. This is so we can free/capture the mouse cursor when the ``escape`` button
-is pressed. We do this because otherwise we'd have no way to free the cursor, meaning it would be stuck until you terminate the
-runtime.
-
-To free/capture the cursor, we check to see if the mouse is visible (freed) or not. If it is, we capture it, and if it's not, we make it visible (free it).
-
-That's all we're doing right now for ``process_input``. We'll come back several times to this function as we add more complexities to our player.
-
-_________
-
-Now let's look at ``process_movement``:
-
-First we ensure that ``dir`` does not have any movement on the ``Y`` axis by setting its ``Y`` value to zero.
-
-Next we normalize ``dir`` to ensure we're within a ``1`` radius unit circle. This makes it where we're moving at a constant speed regardless
-of whether the player is moving straight or diagonally. If we did not normalize, the player would move faster on the diagonal than when going straight.
-
-Next we add gravity to the player by adding ``GRAVITY * delta`` to the player's ``Y`` velocity.
-
-After that we assign the player's velocity to a new variable (called ``hvel``) and remove any movement on the ``Y`` axis.
-
-Next we set a new variable (``target``) to the player's direction vector.
-Then we multiply that by the player's max speed so we know how far the player will move in the direction provided by ``dir``.
-
-After that we make a new variable for acceleration, named ``accel``.
-
-We then take the dot product of ``hvel`` to see if the player is moving according to ``hvel``. Remember, ``hvel`` does not have any
-``Y`` velocity, meaning we are only checking if the player is moving forwards, backwards, left, or right.
-
-
-If the player is moving according to ``hvel``, then we set ``accel`` to the ``ACCEL`` constant so the player will accelerate, otherwise we set ``accel`` to
-our ``DEACCEL`` constant so the player will decelerate.
-
-Then we interpolate the horizontal velocity, set the player's ``X`` and ``Z`` velocity to the interpolated horizontal velocity,
-and call ``move_and_slide`` to let the :ref:`KinematicBody <class_KinematicBody>` handle moving the player through the physics world.
-
-.. tip:: All the code in ``process_movement`` is exactly the same as the movement code from the Kinematic Character demo!
-
-_________
-
-The final function we have is the ``_input`` function, and thankfully it's fairly short:
-
-First we make sure that the event we are dealing with is an :ref:`InputEventMouseMotion <class_InputEventMouseMotion>` event.
-We also want to check if the cursor is captured, as we do not want to rotate if it is not.
-
-.. note:: See :ref:`Mouse and input coordinates <doc_mouse_and_input_coordinates>` for a list of
-         possible input events.
-
-If the event is indeed a mouse motion event and the cursor is captured, we rotate
-based on the relative mouse motion provided by :ref:`InputEventMouseMotion <class_InputEventMouseMotion>`.
-
-First we rotate the ``rotation_helper`` node on the ``X`` axis, using the relative mouse motion's
-``Y`` value, provided by :ref:`InputEventMouseMotion <class_InputEventMouseMotion>`.
-
-Then we rotate the entire :ref:`KinematicBody <class_KinematicBody>` on the ``Y`` axis by the relative mouse motion's ``X`` value.
-
-.. tip:: Godot converts relative mouse motion into a :ref:`Vector2 <class_Vector2>` where mouse movement going
-         up and down is ``1`` and ``-1`` respectively. Right and Left movement is
-         ``1`` and ``-1`` respectively.
-
-         Because of how we are rotating the player, we multiply the relative mouse motion's
-         ``X`` value by ``-1`` so mouse motion going left and right rotates the player left and right
-         in the same direction.
-
-Finally, we clamp the ``rotation_helper``'s ``X`` rotation to be between ``-70`` and ``70``
-degrees so the player cannot rotate themselves upside down.
-
-.. tip:: See :ref:`using transforms <doc_using_transforms>` for more information on rotating transforms.
-
-_________
-
-To test the code, open up the scene named ``Testing_Area.tscn``, if it's not already opened up. We will be using
-this scene as we go through the next few tutorial parts, so be sure to keep it open in one of your scene tabs.
-
-Go ahead and test your code either by pressing :kbd:`F6` with ``Testing_Area.tscn`` as the open tab, by pressing the
-play button in the top right corner, or by pressing :kbd:`F5`.
-You should now be able to walk around, jump in the air, and look around using the mouse.
-
-
-Giving the player a flash light and the option to sprint
---------------------------------------------------------
-
-Before we get to making the weapons work, there are a couple more things we should add.
-
-Many FPS games have an option to sprint and a flashlight. We can easily add these to our player,
-so let's do that!
-
-First we need a few more class variables in our player script:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    const MAX_SPRINT_SPEED = 30
-    const SPRINT_ACCEL = 18
-    var is_sprinting = false
-
-    var flashlight
-
- .. code-tab:: csharp
-
-    [Export]
-    public float MaxSprintSpeed = 30.0f;
-    [Export]
-    public float SprintAccel = 18.0f;
-    private bool _isSprinting = false;
-
-    private SpotLight _flashlight;
-
-All the sprinting variables work exactly the same as the non sprinting variables with
-similar names.
-
-``is_sprinting`` is a boolean to track whether the player is currently sprinting, and ``flashlight`` is a variable
-we will be using to hold the player's flash light node.
-
-Now we need to add a few lines of code, starting in ``_ready``. Add the following to ``_ready``:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    flashlight = $Rotation_Helper/Flashlight
-
- .. code-tab:: csharp
-
-    _flashlight = GetNode<SpotLight>("Rotation_Helper/Flashlight");
-
-This gets the ``Flashlight`` node and assigns it to the ``flashlight`` variable.
-
-_________
-
-Now we need to change some of the code in ``process_input``. Add the following somewhere in ``process_input``:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    # ----------------------------------
-    # Sprinting
-    if Input.is_action_pressed("movement_sprint"):
-        is_sprinting = true
-    else:
-        is_sprinting = false
-    # ----------------------------------
-
-    # ----------------------------------
-    # Turning the flashlight on/off
-    if Input.is_action_just_pressed("flashlight"):
-        if flashlight.is_visible_in_tree():
-            flashlight.hide()
-        else:
-            flashlight.show()
-    # ----------------------------------
-
- .. code-tab:: csharp
-
-    //  -------------------------------------------------------------------
-    //  Sprinting
-    if (Input.IsActionPressed("movement_sprint"))
-        _isSprinting = true;
-    else
-        _isSprinting = false;
-    //  -------------------------------------------------------------------
-
-    //  -------------------------------------------------------------------
-    //  Turning the flashlight on/off
-    if (Input.IsActionJustPressed("flashlight"))
-    {
-        if (_flashlight.IsVisibleInTree())
-            _flashlight.Hide();
-        else
-            _flashlight.Show();
-    }
-
-Let's go over the additions:
-
-We set ``is_sprinting`` to ``true`` when the player is holding down the ``movement_sprint`` action, and ``false``
-when the ``movement_sprint`` action is released. In ``process_movement`` we'll add the code that makes the player faster when
-they sprint. Here in ``process_input`` we are just going to change the ``is_sprinting`` variable.
-
-We do something similar to freeing/capturing the cursor for handling the flashlight. We first check to see if the ``flashlight`` action
-was just pressed. If it was, we then check to see if ``flashlight`` is visible in the scene tree. If it is, then we hide it, and if it's not, we show it.
-
-_________
-
-Now we need to change a couple things in ``process_movement``. First, replace ``target *= MAX_SPEED`` with the following:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    if is_sprinting:
-        target *= MAX_SPRINT_SPEED
-    else:
-        target *= MAX_SPEED
-
- .. code-tab:: csharp
-
-    if (_isSprinting)
-        target *= MaxSprintSpeed;
-    else
-        target *= MaxSpeed;
-
-Now instead of always multiplying ``target`` by ``MAX_SPEED``, we first check to see if the player is sprinting or not.
-If the player is sprinting, we instead multiply ``target`` by ``MAX_SPRINT_SPEED``.
-
-Now all that's left is to change the acceleration when sprinting. Change ``accel = ACCEL`` to the following:
-
-.. tabs::
- .. code-tab:: gdscript GDScript
-
-    if is_sprinting:
-        accel = SPRINT_ACCEL
-    else:
-        accel = ACCEL
-
- .. code-tab:: csharp
-
-    if (_isSprinting)
-        accel = SprintAccel;
-    else
-        accel = Accel;
-
-Now, when the player is sprinting, we'll use ``SPRINT_ACCEL`` instead of ``ACCEL``, which will accelerate the player faster.
-
-_________
-
-You should now be able to sprint if you press :kbd:`Shift`, and can toggle the flash light on and off by pressing :kbd:`F`!
-
-Go try it out! You can change the sprint-related class variables to make the player faster or slower when sprinting!
-
-Final notes
------------
-
-.. image:: img/PartOneFinished.png
-
-Whew! That was a lot of work. Now you have a fully working first person character!
-
-In :ref:`doc_fps_tutorial_part_two` we will add some guns to our player character.
-
-.. note:: At this point we've recreated the Kinematic character demo from first person perspective with sprinting and a flash light!
-
-.. tip:: Currently the player script would be at an ideal state for making all sorts of
-         first person games. For example: Horror games, platformer games, adventure games, and more!
-
-.. warning:: If you ever get lost, be sure to read over the code again!
-
-             You can download the finished project for this part here: :download:`Godot_FPS_Part_1.zip <files/Godot_FPS_Part_1.zip>`

+ 0 - 1041
tutorials/3d/fps_tutorial/part_six.rst

@@ -1,1041 +0,0 @@
-.. _doc_fps_tutorial_part_six:
-
-Part 6
-======
-
-Part overview
--------------
-
-In this part, we're going to add a main menu and pause menu,
-add a respawn system for the player, and change/move the sound system so we can use it from any script.
-
-This is the last part of the FPS tutorial; by the end of this, you will have a solid base to build amazing FPS games with Godot!
-
-.. image:: img/FinishedTutorialPicture.png
-
-.. note:: You are assumed to have finished :ref:`doc_fps_tutorial_part_five` before moving on to this part of the tutorial.
-          The finished project from :ref:`doc_fps_tutorial_part_five` will be the starting project for part 6
-
-Let's get started!
-
-Adding the main menu
---------------------
-
-Firstly, open up ``Main_Menu.tscn`` and take a look at how the scene is set up.
-
-The main menu is broken up into three different panels, each representing a different
-'screen' of our main menu.
-
-.. note:: The ``Background_Animation`` node is just so the background of the menu is a bit more interesting than a solid color.
-          It's a camera looking around the skybox, nothing fancy.
-
-Feel free to expand all the nodes and see how they're set up. Remember to keep only ``Start_Menu`` visible
-when you're done, as that's the screen we want to show first when we enter the main menu.
-
-Select ``Main_Menu`` (the root node) and create a new script called ``Main_Menu.gd``. Add the following:
-
-::
-
-    extends Control
-
-    var start_menu
-    var level_select_menu
-    var options_menu
-
-    export (String, FILE) var testing_area_scene
-    export (String, FILE) var space_level_scene
-    export (String, FILE) var ruins_level_scene
-
-    func _ready():
-        start_menu = $Start_Menu
-        level_select_menu = $Level_Select_Menu
-        options_menu = $Options_Menu
-
-        $Start_Menu/Button_Start.connect("pressed", self, "start_menu_button_pressed", ["start"])
-        $Start_Menu/Button_Open_Godot.connect("pressed", self, "start_menu_button_pressed", ["open_godot"])
-        $Start_Menu/Button_Options.connect("pressed", self, "start_menu_button_pressed", ["options"])
-        $Start_Menu/Button_Quit.connect("pressed", self, "start_menu_button_pressed", ["quit"])
-
-        $Level_Select_Menu/Button_Back.connect("pressed", self, "level_select_menu_button_pressed", ["back"])
-        $Level_Select_Menu/Button_Level_Testing_Area.connect("pressed", self, "level_select_menu_button_pressed", ["testing_scene"])
-        $Level_Select_Menu/Button_Level_Space.connect("pressed", self, "level_select_menu_button_pressed", ["space_level"])
-        $Level_Select_Menu/Button_Level_Ruins.connect("pressed", self, "level_select_menu_button_pressed", ["ruins_level"])
-
-        $Options_Menu/Button_Back.connect("pressed", self, "options_menu_button_pressed", ["back"])
-        $Options_Menu/Button_Fullscreen.connect("pressed", self, "options_menu_button_pressed", ["fullscreen"])
-        $Options_Menu/Check_Button_VSync.connect("pressed", self, "options_menu_button_pressed", ["vsync"])
-        $Options_Menu/Check_Button_Debug.connect("pressed", self, "options_menu_button_pressed", ["debug"])
-
-        Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
-
-        var globals = get_node("/root/Globals")
-        $Options_Menu/HSlider_Mouse_Sensitivity.value = globals.mouse_sensitivity
-        $Options_Menu/HSlider_Joypad_Sensitivity.value = globals.joypad_sensitivity
-
-
-    func start_menu_button_pressed(button_name):
-        if button_name == "start":
-            level_select_menu.visible = true
-            start_menu.visible = false
-        elif button_name == "open_godot":
-            OS.shell_open("https://godotengine.org/")
-        elif button_name == "options":
-            options_menu.visible = true
-            start_menu.visible = false
-        elif button_name == "quit":
-            get_tree().quit()
-
-
-    func level_select_menu_button_pressed(button_name):
-        if button_name == "back":
-            start_menu.visible = true
-            level_select_menu.visible = false
-        elif button_name == "testing_scene":
-            set_mouse_and_joypad_sensitivity()
-            get_node("/root/Globals").load_new_scene(testing_area_scene)
-        elif button_name == "space_level":
-            set_mouse_and_joypad_sensitivity()
-            get_node("/root/Globals").load_new_scene(space_level_scene)
-        elif button_name == "ruins_level":
-            set_mouse_and_joypad_sensitivity()
-            get_node("/root/Globals").load_new_scene(ruins_level_scene)
-
-
-    func options_menu_button_pressed(button_name):
-        if button_name == "back":
-            start_menu.visible = true
-            options_menu.visible = false
-        elif button_name == "fullscreen":
-            OS.window_fullscreen = !OS.window_fullscreen
-        elif button_name == "vsync":
-            OS.vsync_enabled = $Options_Menu/Check_Button_VSync.pressed
-        elif button_name == "debug":
-            pass
-
-
-    func set_mouse_and_joypad_sensitivity():
-        var globals = get_node("/root/Globals")
-        globals.mouse_sensitivity = $Options_Menu/HSlider_Mouse_Sensitivity.value
-        globals.joypad_sensitivity = $Options_Menu/HSlider_Joypad_Sensitivity.value
-
-
-Most of the code here relates to making UIs, which is outside of the purpose of this tutorial series.
-**We're only going to look at the UI related code briefly.**
-
-.. tip:: See :ref:`doc_ui_main_menu` and the tutorials following for better ways to make GUIs and UIs!
-
-Let's look at the class variables first.
-
-* ``start_menu``: A variable to hold the ``Start_Menu`` :ref:`Panel <class_Panel>`.
-* ``level_select_menu``: A variable to hold the ``Level_Select_Menu`` :ref:`Panel <class_Panel>`.
-* ``options_menu``: A variable to hold the ``Options_Menu`` :ref:`Panel <class_Panel>`.
-* ``testing_area_scene``: The path to the ``Testing_Area.tscn`` file, so we can change to it from this scene.
-* ``space_level_scene``: The path to the ``Space_Level.tscn`` file, so we can change to it from this scene.
-* ``ruins_level_scene``: The path to the ``Ruins_Level.tscn`` file, so we can change to it from this scene.
-
-.. warning:: You'll have to set the paths to the correct files in the editor before testing this script! Otherwise it will not work!
-
-______
-
-Now let's go over ``_ready``
-
-Firstly, we get all the :ref:`Panel <class_Panel>` nodes and assign them to the proper variables.
-
-Next, we connect all the buttons ``pressed`` signals to their respective ``[panel_name_here]_button_pressed`` functions.
-
-We then set the mouse mode to ``MOUSE_MODE_VISIBLE`` to ensure whenever the player returns to this scene, the mouse will be visible.
-
-Then we get a singleton, called ``Globals``. We then set the values for the :ref:`HSlider <class_HSlider>` nodes so their values line up with the mouse and joypad sensitivity
-in the singleton.
-
-.. note:: We have not made the ``Globals`` singleton yet, so don't worry! We're going to make it soon!
-
-______
-
-In ``start_menu_button_pressed``, we check to see which button is pressed.
-
-Based on the button pressed, we either change the currently visible panel, quit the application, or open the Godot website.
-
-______
-
-In ``level_select_menu_button_pressed``, we check to see which button is pressed.
-
-If the ``back`` button has been pressed, we change the currently visible panels to return to the main menu.
-
-If one of the scene changing buttons is pressed, we fist call ``set_mouse_and_joypad_sensitivity`` so the singleton (``Globals.gd``) has the values from the :ref:`HSlider
-<class_HSlider>` nodes.
-Then, we tell the singleton to change nodes using its ``load_new_scene`` function, passing in the file path of the scene the player has selected.
-
-.. note:: Don't worry about the singleton, we'll get there soon!
-
-______
-
-In ``options_menu_button_pressed``, we check to see which button is pressed.
-
-If the ``back`` button has been pressed, we change the currently visible panels to return to the main menu.
-
-If the ``fullscreen`` button is pressed, we toggle the :ref:`OS <class_OS>`'s full screen mode by setting it to the flipped version of its current value.
-
-If the ``vsync`` button is pressed, we set the :ref:`OS <class_OS>`'s Vsync based on the state of the Vsync check button.
-
-______
-
-Finally, lets take a look at ``set_mouse_and_joypad_sensitivity``.
-
-Firstly, we get the ``Globals`` singleton and assign it to a local variable.
-
-We then set the ``mouse_sensitivity`` and ``joypad_sensitivity`` variables to the values in their respective :ref:`HSlider <class_HSlider>` node counterparts.
-
-Making the ``Globals`` singleton
---------------------------------
-
-Now, for all this to work, we need to create the ``Globals`` singleton. Make a new script in the ``Script`` tab and call it ``Globals.gd``.
-
-.. note:: To make the ``Globals`` singleton, go to the ``Script`` tab in the editor, then click ``New`` and a ``Create Script`` box will appear, leave everything unchanged except for the ``Path`` where you need to insert the script's name ``Globals.gd``.
-
-Add the following to ``Globals.gd``.
-
-::
-
-    extends Node
-
-    var mouse_sensitivity = 0.08
-    var joypad_sensitivity = 2
-
-    func _ready():
-        pass
-
-    func load_new_scene(new_scene_path):
-        get_tree().change_scene(new_scene_path)
-
-As you can see, it's quite small and simple. As this part progresses, we will
-keep adding more complex logic to ``Globals.gd``, but for now, all it is doing is holding two class variables, and abstract defining how we change scenes.
-
-* ``mouse_sensitivity``: The current sensitivity for our mouse, so we can load it in ``Player.gd``.
-* ``joypad_sensitivity``: The current sensitivity for our joypad, so we can load it in ``Player.gd``.
-
-Right now, all we will be using ``Globals.gd`` for is a way to carry variables across scenes. Because the sensitivities of our mouse and joypad are
-stored in ``Globals.gd``, any changes we make in one scene (like in ``Options_Menu``) will affect the sensitivity for the player.
-
-All we're doing in ``load_new_scene`` is calling :ref:`SceneTree <class_SceneTree>`'s ``change_scene`` function, passing in the scene path given in ``load_new_scene``.
-
-That's all the code needed for ``Globals.gd`` right now! Before we can test the main menu, we first need to set ``Globals.gd`` as an autoload script.
-
-Open up the ``Project Settings`` and click the ``AutoLoad`` tab.
-
-.. image:: img/AutoloadAddSingleton.png
-
-Then select the path to ``Globals.gd`` in the ``Path`` field by clicking the button (``..``) beside it. Make sure the name in the ``Node Name`` field is ``Globals``. If you
-have everything like in the picture above, then press ``Add``!
-
-This will make ``Globals.gd`` a singleton/autoload script, which will allow us to access it from any script, in any scene.
-
-.. tip:: For more information on singleton/autoload scripts, see :ref:`doc_singletons_autoload`.
-
-Now that ``Globals.gd`` is a singleton/autoload script, you can test the main menu!
-
-You may want to change the main scene from ``Testing_Area.tscn`` to ``Main_Menu.tscn`` so when we export the game the player will start at the main menu. You can do this
-through the ``Project Settings``, under the ``General`` tab. Then in the ``Application`` category, click the ``Run`` subcategory and you can change the main scene by changing
-the value in ``Main Scene``.
-
-.. warning:: You'll have to set the paths to the correct files in ``Main_Menu`` in the editor before testing the main menu!
-             Otherwise you will not be able to change scenes from the level select menu/screen.
-
-Adding the debug menu
----------------------
-
-Now, let's add a simple debugging scene so we can track things like FPS (Frames Per Second) in-game. Open up ``Debug_Display.tscn``.
-
-You can see it's a :ref:`Panel <class_Panel>` positioned in the top right corner of the screen. It has three :ref:`Labels <class_Label>`,
-one for displaying the FPS at which the game is running, one for showing on what OS the game is running, and a label for showing with which Godot version the game is running.
-
-Let's add the code needed to fill these :ref:`Labels <class_Label>`. Select ``Debug_Display`` and create a new script called ``Debug_Display.gd``. Add the following:
-
-::
-
-    extends Control
-
-    func _ready():
-        $OS_Label.text = "OS: " + OS.get_name()
-        $Engine_Label.text = "Godot version: " + Engine.get_version_info()["string"]
-
-    func _process(delta):
-        $FPS_Label.text = "FPS: " + str(Engine.get_frames_per_second())
-
-Let's go over what this script does.
-
-______
-
-In ``_ready``, we set the ``OS_Label``'s text to the name provided by :ref:`OS <class_OS>` using the ``get_name`` function. This will return the
-name of the OS (or Operating System) for which Godot was compiled. For example, when you are running Windows, it will return ``Windows``, while when you
-are running Linux, it will return ``X11``.
-
-Then, we set the ``Engine_Label``'s text to the version info provided by ``Engine.get_version_info``. ``Engine.get_version_info`` returns a dictionary full
-of useful information about the version of Godot which is currently running. We only care about the string version, for this label at least, so we get the string
-and assign that as the ``text`` in ``Engine_Label``. See :ref:`Engine <class_Engine>` for more information on the values ``get_version_info`` returns.
-
-In ``_process``, we set the text of the ``FPS_Label`` to ``Engine.get_frames_per_second``, but because ``get_frames_per_second`` returns an integer, we have to cast
-it to a string using ``str`` before we can add it to the :ref:`Label <class_Label>`.
-
-______
-
-Now let's jump back to ``Main_Menu.gd`` and change the following in ``options_menu_button_pressed``:
-
-::
-
-    elif button_name == "debug":
-        pass
-
-to this instead:
-
-::
-
-    elif button_name == "debug":
-        get_node("/root/Globals").set_debug_display($Options_Menu/Check_Button_Debug.pressed)
-
-This will call a new function called ``set_debug_display`` in our singleton, so let's add that next!
-
-______
-
-Open up ``Globals.gd`` and add the following class variables:
-
-::
-
-    # ------------------------------------
-    # All the GUI/UI-related variables
-
-    var canvas_layer = null
-
-    const DEBUG_DISPLAY_SCENE = preload("res://Debug_Display.tscn")
-    var debug_display = null
-
-    # ------------------------------------
-
-* ``canvas_layer``: A canvas layer so the GUI/UI created in ``Globals.gd`` is always drawn on top.
-* ``DEBUG_DISPLAY``: The debug display scene we worked on earlier.
-* ``debug_display``: A variable to hold the debug display when/if there is one.
-
-Now that we have the class variables defined, we need to add a few lines to ``_ready`` so ``Globals.gd`` will have a canvas layer to use (which we will store in ``canvas_layer``).
-Change ``_ready`` to the following:
-
-::
-
-    func _ready():
-        canvas_layer = CanvasLayer.new()
-        add_child(canvas_layer)
-
-Now in ``_ready``, we create a new canvas layer, assign it to ``canvas_layer`` and add it as a child.
-Because ``Globals.gd`` is an autoload/singleton, Godot will make a :ref:`Node <class_Node>` when the game is launched, and it will have ``Globals.gd`` attached to it.
-Since Godot makes a :ref:`Node <class_Node>`, we can treat ``Globals.gd`` like any other node with regard to adding/removing children nodes.
-
-The reason we're adding a :ref:`CanvasLayer <class_CanvasLayer>` is so all our GUI and UI nodes we instance/spawn in ``Globals.gd``
-are always drawn on top of everything else.
-
-When adding nodes to a singleton/autoload, you have to be careful not to lose reference to any of the child nodes.
-This is because nodes will not be freed/destroyed when you change the active scene, meaning you can run into memory problems if you are
-instancing/spawning lots of nodes and you are not freeing them.
-
-______
-
-Now we need to add ``set_debug_display`` to ``Globals.gd``:
-
-::
-
-    func set_debug_display(display_on):
-        if display_on == false:
-            if debug_display != null:
-                debug_display.queue_free()
-                debug_display = null
-        else:
-            if debug_display == null:
-                debug_display = DEBUG_DISPLAY_SCENE.instance()
-                canvas_layer.add_child(debug_display)
-
-Let's go over what's happening.
-
-First we check to see if ``Globals.gd`` is trying to turn on the debug display, or turn it off.
-
-If ``Globals.gd`` is turning off the display, we then check to see if ``debug_display`` is not equal to ``null``. If ``debug_display`` is not equal to ``null``, then ``Globals.gd``
-must have a debug display currently active. If ``Globals.gd`` has a debug display active, we free it using ``queue_free`` and then assign ``debug_display`` to ``null``.
-
-If ``Globals.gd`` is turning on the display, we then check to make sure ``Globals.gd`` do not already have a debug display active.
-We do this by making sure ``debug_display`` is equal to ``null``.
-If ``debug_display`` is ``null``, we instance a new ``DEBUG_DISPLAY_SCENE``, and add it as a child of ``canvas_layer``.
-
-______
-
-With that done, we can now toggle the debug display on and off by switching the :ref:`CheckButton <class_CheckButton>` in the ``Options_Menu`` panel. Go give it a try!
-
-Notice how the debug display stays even when you change scenes from the ``Main_Menu.tscn`` to another scene (like ``Testing_Area.tscn``). This is the beauty of
-instancing/spawning nodes in a singleton/autoload and adding them as children to the singleton/autoload. Any of the nodes added as children of the singleton/autoload will
-stay for as long as the game is running, without any additional work on our part!
-
-Adding a pause menu
--------------------
-
-Let's add a pause menu so we can return to the main menu when we press the ``ui_cancel`` action.
-
-Open up ``Pause_Popup.tscn``.
-
-Notice how the root node in ``Pause_Popup`` is a :ref:`WindowDialog <class_WindowDialog>`; :ref:`WindowDialog <class_WindowDialog>` inherits from
-:ref:`Popup <class_Popup>`, which means :ref:`WindowDialog <class_WindowDialog>` can act like a popup.
-
-Select ``Pause_Popup`` and scroll down all the way till you get to the ``Pause`` menu in the inspector. Notice how the pause mode is set to
-``process`` instead of ``inherit`` like it is normally set by default. This makes it so it will continue to process even when the game is paused,
-which we need in order to interact with the UI elements.
-
-Now that we've looked at how ``Pause_Popup.tscn`` is set up, let's write the code to make it work. Normally, we'd attach a script to the root node of
-the scene, ``Pause_Popup`` in this case, but since we'll need to receive a couple of signals in ``Globals.gd``, we'll write all the code for
-the popup there.
-
-Open up ``Globals.gd`` and add the following class variables:
-
-::
-
-    const MAIN_MENU_PATH = "res://Main_Menu.tscn"
-    const POPUP_SCENE = preload("res://Pause_Popup.tscn")
-    var popup = null
-
-* ``MAIN_MENU_PATH``: The path to the main menu scene.
-* ``POPUP_SCENE``: The pop up scene we looked at earlier.
-* ``popup``: A variable to hold the pop up scene.
-
-Now we need to add ``_process`` to ``Globals.gd`` so it can respond when the ``ui_cancel`` action is pressed.
-Add the following to ``_process``:
-
-::
-
-    func _process(delta):
-        if Input.is_action_just_pressed("ui_cancel"):
-            if popup == null:
-                popup = POPUP_SCENE.instance()
-
-                popup.get_node("Button_quit").connect("pressed", self, "popup_quit")
-                popup.connect("popup_hide", self, "popup_closed")
-                popup.get_node("Button_resume").connect("pressed", self, "popup_closed")
-
-                canvas_layer.add_child(popup)
-                popup.popup_centered()
-
-                Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
-
-                get_tree().paused = true
-
-Let's go over what's happening here.
-
-______
-
-Firstly, we check to see if the ``ui_cancel`` action is pressed. Then, we check to make sure ``Globals.gd`` does not already
-have a ``popup`` open by checking to see if ``popup`` is equal to ``null``.
-
-If ``Globals.gd`` do not have a pop-up open, we instance ``POPUP_SCENE`` and assign it to ``popup``.
-
-We then get the quit button and assign its ``pressed`` signal to ``popup_quit``, which we will be adding shortly.
-
-Next, we assign both the ``popup_hide`` signal from the :ref:`WindowDialog <class_WindowDialog>` and the ``pressed`` signal from the resume button
-to ``popup_closed``, which we will be adding shortly.
-
-Then, we add ``popup`` as a child of ``canvas_layer`` so it's drawn on top. We then tell ``popup`` to pop up at the center of the screen using ``popup_centered``.
-
-Next, we make sure the mouse mode is ``MOUSE_MODE_VISIBLE`` so the player can interact with the pop-up. If we did not do this, the player would not be able to
-interact with the pop up in any scene where the mouse mode is ``MOUSE_MODE_CAPTURED``.
-
-Finally, we pause the entire :ref:`SceneTree <class_SceneTree>`.
-
-.. note:: For more information on pausing in Godot, see :ref:`doc_pausing_games`
-
-______
-
-Now, we need to add the functions to which we've connected the signals. Let's add ``popup_closed`` first.
-
-Add the following to ``Globals.gd``:
-
-::
-
-    func popup_closed():
-        get_tree().paused = false
-
-        if popup != null:
-            popup.queue_free()
-            popup = null
-
-``popup_closed`` will resume the game and destroy the pop-up if there is one.
-
-``popup_quit`` is similar, but we're also making sure the mouse is visible and changing scenes to the title screen.
-
-Add the following to ``Globals.gd``:
-
-::
-
-    func popup_quit():
-        get_tree().paused = false
-
-        Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
-
-        if popup != null:
-            popup.queue_free()
-            popup = null
-
-        load_new_scene(MAIN_MENU_PATH)
-
-``popup_quit`` will resume the game, set the mouse mode to ``MOUSE_MODE_VISIBLE`` to ensure the mouse is visible in the main menu, destroy
-the pop-up if there is one, and change scenes to the main menu.
-
-______
-
-Before we're ready to test the pop-up, we should change one thing in ``Player.gd``.
-
-Open up ``Player.gd`` and in ``process_input``, change the code for capturing/freeing the cursor to the following:
-
-Instead of:
-
-::
-
-    # Capturing/Freeing cursor
-    if Input.is_action_just_pressed("ui_cancel"):
-        if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE:
-            Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-        else:
-            Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
-
-You will leave only:
-
-::
-
-    # Capturing/Freeing cursor
-    if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE:
-        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-
-Now, instead of capturing/freeing the mouse, we check whether the current mouse mode is ``MOUSE_MODE_VISIBLE``. If it is, we set it back to
-``MOUSE_MODE_CAPTURED``.
-
-Because the pop-up makes the mouse mode ``MOUSE_MODE_VISIBLE`` whenever you pause, we no longer have to worry about freeing and capturing the cursor in ``Player.gd``.
-
-______
-
-Now the pause menu pop-up is finished. You can now pause at any point in the game and return to the main menu!
-
-Starting the respawn system
----------------------------
-
-Since the player can lose all their health, it would be ideal if the player died and respawned too, so let's add that next!
-
-Firstly, open up ``Player.tscn`` and expand ``HUD``. Notice how there is a :ref:`ColorRect <class_ColorRect>` called ``Death_Screen``.
-When the player dies, we're going to make ``Death_Screen`` visible, and show them how long they have to wait before the player is able to respawn.
-
-Open up ``Player.gd`` and add the following class variables:
-
-::
-
-    const RESPAWN_TIME = 4
-    var dead_time = 0
-    var is_dead = false
-
-    var globals
-
-* ``RESPAWN_TIME``: The amount of time (in seconds) it takes to respawn.
-* ``dead_time``: A variable to track how long the player has been dead.
-* ``is_dead``: A variable to track whether or not the player is currently dead.
-* ``globals``: A variable to hold the ``Globals.gd`` singleton.
-
-______
-
-We now need to add a couple lines to ``_ready``, so we can use ``Globals.gd`` in ``Player.gd``. Add the following to ``_ready``:
-
-::
-
-    globals = get_node("/root/Globals")
-    global_transform.origin = globals.get_respawn_position()
-
-
-Now we're getting the ``Globals.gd`` singleton and assigning it to ``globals``. We also set the player's global position
-by setting the origin in the player's global :ref:`Transform <class_Transform>` to the position returned by ``globals.get_respawn_position``.
-
-.. note:: Don't worry, we will be adding ``get_respawn_position`` further below!
-
-______
-
-Next, we need to make a few changes to ``_physics_process``. Change ``_physics_process`` to the following:
-
-::
-
-    func _physics_process(delta):
-
-        if !is_dead:
-            process_input(delta)
-            process_view_input(delta)
-            process_movement(delta)
-
-        if (grabbed_object == null):
-            process_changing_weapons(delta)
-            process_reloading(delta)
-
-        process_UI(delta)
-        process_respawn(delta)
-
-Now the player will not be processing input or movement input when the player is dead. We are also now calling ``process_respawn``.
-
-.. note:: The ``if !is_dead:`` expression is equivalent and works in the same way as the expression ``if is_dead == false:``. And by removing the ``!`` sign from the expression we obtain the opposite expression ``if is_dead == true:``. It is just a shorter way of writing the same code functionality.
-
-We have not made ``process_respawn`` yet, so let's change that.
-
-______
-
-Let's add ``process_respawn``. Add the following to ``Player.gd``:
-
-::
-
-    func process_respawn(delta):
-
-        # If we've just died
-        if health <= 0 and !is_dead:
-            $Body_CollisionShape.disabled = true
-            $Feet_CollisionShape.disabled = true
-
-            changing_weapon = true
-            changing_weapon_name = "UNARMED"
-
-            $HUD/Death_Screen.visible = true
-
-            $HUD/Panel.visible = false
-            $HUD/Crosshair.visible = false
-
-            dead_time = RESPAWN_TIME
-            is_dead = true
-
-            if grabbed_object != null:
-                grabbed_object.mode = RigidBody.MODE_RIGID
-                grabbed_object.apply_impulse(Vector3(0, 0, 0), -camera.global_transform.basis.z.normalized() * OBJECT_THROW_FORCE / 2)
-
-                grabbed_object.collision_layer = 1
-                grabbed_object.collision_mask = 1
-
-                grabbed_object = null
-
-        if is_dead:
-            dead_time -= delta
-
-            var dead_time_pretty = str(dead_time).left(3)
-            $HUD/Death_Screen/Label.text = "You died\n" + dead_time_pretty + " seconds till respawn"
-
-            if dead_time <= 0:
-                global_transform.origin = globals.get_respawn_position()
-
-                $Body_CollisionShape.disabled = false
-                $Feet_CollisionShape.disabled = false
-
-                $HUD/Death_Screen.visible = false
-
-                $HUD/Panel.visible = true
-                $HUD/Crosshair.visible = true
-
-                for weapon in weapons:
-                    var weapon_node = weapons[weapon]
-                    if weapon_node != null:
-                        weapon_node.reset_weapon()
-
-                health = 100
-                grenade_amounts = {"Grenade":2, "Sticky Grenade":2}
-                current_grenade = "Grenade"
-
-                is_dead = false
-
-Let's go through what this function is doing.
-
-______
-
-Firstly, we check whether the player has just died by checking if ``health`` is less than or equal to ``0`` and ``is_dead`` is ``false``.
-
-If the player has just died, we disable the collision shapes for the player. We do this to make sure the player is not blocking anything with their dead body.
-
-Next, we set ``changing_weapon`` to ``true`` and set ``changing_weapon_name`` to ``UNARMED``. This is so, if the player is using a weapon, it is put away
-when they dies.
-
-We then make the ``Death_Screen`` :ref:`ColorRect <class_ColorRect>` visible so the player gets a nice grey overlay over everything when they have died.
-We then make the rest of the UI, the ``Panel`` and ``Crosshair`` nodes, invisible.
-
-Next, we set ``dead_time`` to ``RESPAWN_TIME`` so we can start counting down how long the player has been dead. We also set ``is_dead`` to ``true`` so we know the player has died.
-
-If the player is holding an object when they died, we need to throw it. We first check whether the player is holding an object or not.
-If the player is holding a object, we throw it using the same code as the throwing code we added in :ref:`doc_fps_tutorial_part_five`.
-
-.. note:: The ``\n`` combination from the expression ``You have died\n`` is a command used to display the text following after it on a new line below. This is always useful when you want to nicely group displayed text in multiple lines so it looks better and is more readable by the players of your games.
-
-______
-
-Then we check whether the player is dead. If so, we then remove ``delta`` from ``dead_time``.
-
-We then make a new variable called ``dead_time_pretty``, where we convert ``dead_time`` to a string, using only the first three characters starting from the left. This gives
-the player a nice looking string showing how much time the player has left to wait before the player can respawn.
-
-We then change the :ref:`Label <class_Label>` in ``Death_Screen`` to show how much time the player has left.
-
-Next we check to see if the player has waited long enough and can respawn. We do this by checking to see if ``dead_time`` is ``0`` or less.
-
-If the player has waited long enough to respawn, we set the player's position to a new respawn position provided by ``get_respawn_position``.
-
-We then enable both of the player's collision shapes so the player can collide again with the environment.
-
-Next, we make the ``Death_Screen`` invisible and make the rest of the UI, the ``Panel`` and ``Crosshair`` nodes, visible again.
-
-We then go through each weapon and call its ``reset_weapon`` function, which we will add soon.
-
-Then, we reset ``health`` to ``100``, ``grenade_amounts`` to its default values, and change ``current_grenade`` to ``Grenade``.
-This effectively resets these variables to their default values.
-
-Finally, we set ``is_dead`` to ``false``.
-
-______
-
-Before we leave ``Player.gd``, we need to add one quick thing to ``_input``. Add the following at the beginning of ``_input``:
-
-::
-
-    if is_dead:
-        return
-
-Now, when the player is dead, they cannot look around with the mouse.
-
-Finishing the respawn system
-----------------------------
-
-Firstly, let's open ``Weapon_Pistol.gd`` and add the ``reset_weapon`` function. Add the following:
-
-::
-
-    func reset_weapon():
-        ammo_in_weapon = 10
-        spare_ammo = 20
-
-Now, when we call ``reset_weapon``, the ammo in the pistol and the ammo in the spares will be reset to their default values.
-
-Now let's add ``reset_weapon`` in ``Weapon_Rifle.gd``:
-
-::
-
-    func reset_weapon():
-        ammo_in_weapon = 50
-        spare_ammo = 100
-
-And add the following to ``Weapon_Knife.gd``:
-
-::
-
-    func reset_weapon():
-        ammo_in_weapon = 1
-        spare_ammo = 1
-
-Now all the weapons will reset when the player dies.
-
-______
-
-Now we need to add a few things to ``Globals.gd``. Firstly, add the following class variable:
-
-::
-
-    var respawn_points = null
-
-* ``respawn_points``: A variable to hold all the respawn points in a level
-
-Because we're getting a random spawn point each time, we need to randomize the number generator. Add the following to ``_ready``:
-
-::
-
-    randomize()
-
-``randomize`` will get us a new random seed so we get a (relatively) random string of numbers when we use any of the random functions.
-
-Now let's add ``get_respawn_position`` to ``Globals.gd``:
-
-::
-
-    func get_respawn_position():
-        if respawn_points == null:
-            return Vector3(0, 0, 0)
-        else:
-            var respawn_point = rand_range(0, respawn_points.size() - 1)
-            return respawn_points[respawn_point].global_transform.origin
-
-Let's go over what this function does.
-
-______
-
-Firstly, we check if ``Globals.gd`` has any ``respawn_points`` by checking whether ``respawn_points`` is ``null`` or not.
-
-If ``respawn_points`` is ``null``, we return a position of empty :ref:`Vector 3 <class_Vector3>` with the position ``(0, 0, 0)``.
-
-If ``respawn_points`` is not ``null``, we then get a random number between ``0`` and the number of elements we have in ``respawn_points``, minus ``1`` since
-most programming languages, including ``GDScript``, start counting from ``0`` when you are accessing elements in a list.
-
-We then return the position of the :ref:`Spatial <class_Spatial>` node at ``respawn_point`` position in ``respawn_points``.
-
-______
-
-Before we are done with ``Globals.gd``, we need to add the following to ``load_new_scene``:
-
-::
-
-    respawn_points = null
-
-We set ``respawn_points`` to ``null`` so when/if the player gets to a level with no respawn points, we do not respawn the player
-at the respawn points that were in the level prior.
-
-______
-
-Now all we need is a way to set the respawn points. Open up ``Ruins_Level.tscn`` and select ``Spawn_Points``. Add a new script called
-``Respawn_Point_Setter.gd`` and attach it to ``Spawn_Points``. Add the following to ``Respawn_Point_Setter.gd``:
-
-::
-
-    extends Spatial
-
-    func _ready():
-        var globals = get_node("/root/Globals")
-        globals.respawn_points = get_children()
-
-Now, when a node with ``Respawn_Point_Setter.gd`` has its ``_ready`` function called, all the children
-nodes of the node with ``Respawn_Point_Setter.gd``, ``Spawn_Points`` in the case of ``Ruins_Level.tscn``, will be added
-to ``respawn_points`` in ``Globals.gd``.
-
-.. warning:: Any node with ``Respawn_Point_Setter.gd`` has to be above the player in the :ref:`SceneTree <class_SceneTree>` so the respawn points are set
-             before the player needs them in the player's ``_ready`` function.
-
-______
-
-Now, when the player dies, they will respawn after waiting ``4`` seconds!
-
-.. note:: No spawn points are already set up for any of the levels besides ``Ruins_Level.tscn``!
-          Adding spawn points to ``Space_Level.tscn`` is left as an exercise for the reader.
-
-Writing a sound system we can use anywhere
-------------------------------------------
-
-Finally, let's make a sound system so we can play sounds from anywhere, without having to use the player.
-
-Firstly, open up ``SimpleAudioPlayer.gd`` and change it to the following:
-
-::
-
-    extends Spatial
-
-    var audio_node = null
-    var should_loop = false
-    var globals = null
-
-    func _ready():
-        audio_node = $Audio_Stream_Player
-        audio_node.connect("finished", self, "sound_finished")
-        audio_node.stop()
-
-        globals = get_node("/root/Globals")
-
-
-    func play_sound(audio_stream, position=null):
-        if audio_stream == null:
-            print ("No audio stream passed; cannot play sound")
-            globals.created_audio.remove(globals.created_audio.find(self))
-            queue_free()
-            return
-
-        audio_node.stream = audio_stream
-
-        # If you are using an AudioStreamPlayer3D, then uncomment these lines to set the position.
-        #if audio_node is AudioStreamPlayer3D:
-        #    if position != null:
-        #        audio_node.global_transform.origin = position
-
-        audio_node.play(0.0)
-
-
-    func sound_finished():
-        if should_loop:
-            audio_node.play(0.0)
-        else:
-            globals.created_audio.remove(globals.created_audio.find(self))
-            audio_node.stop()
-            queue_free()
-
-
-There are several changes from the old version, first and foremost being we are no longer storing the sound files in ``SimpleAudioPlayer.gd`` anymore.
-This is much better for performance since we're no longer loading each audio clip when we create a sound, but instead we are forcing an audio stream to be passed
-in to ``play_sound``.
-
-Another change is we have a new class variable called ``should_loop``. Instead of just destroying the audio player every time it's finished, we instead want to check and see if the audio player is set to loop or not. This allows us to have audio like looping background music without having to spawn a new audio player with the music when the old one is finished.
-
-Finally, instead of being instanced/spawned in ``Player.gd``, the audio player is instead going to be spawned in ``Globals.gd`` so we can create sounds from any scene.
-Now the audio player stores ``Globals.gd`` singleton so when the audio player is destroyed, we can also remove it from a list in ``Globals.gd``.
-
-Let's go over the changes.
-
-______
-
-For the class variables, we removed all the ``audio_[insert name here]`` variables since we will instead have these passed in from ``Globals.gd``.
-
-We also added two new class variables, ``should_loop`` and ``globals``. We'll use ``should_loop`` to tell whether the audio player should loop when the sound has
-finished, and ``globals`` will hold the ``Globals.gd`` singleton.
-
-The only change in ``_ready`` is now audio player is getting the ``Globals.gd`` singleton and assigning it to ``globals``.
-
-``play_sound`` now expects an audio stream, named ``audio_stream``, to be passed in, instead of ``sound_name``. Instead of checking the
-sound name and setting the stream for the audio player, we instead check to make sure an audio stream was passed in. If an audio stream was not passed
-in, we print an error message, remove the audio player from a list in the ``Globals.gd`` singleton called ``created_audio``, and then free the audio player.
-
-Finally, in ``sound_finished`` we first check to see if the audio player is supposed to loop or not using ``should_loop``. If the audio player is supposed to loop,
-we play the sound again from the start, at position ``0.0``. If the audio player is not supposed to loop, we remove the audio player from a list in the ``Globals.gd`` singleton
-called ``created_audio``, and then free the audio player.
-
-______
-
-Now that we've finished our changes to ``SimpleAudioPlayer.gd``, we now need to turn our attention to ``Globals.gd``. First, add the following class variables:
-
-::
-
-    # All the audio files.
-
-    # You will need to provide your own sound files.
-    var audio_clips = {
-        "Pistol_shot": null, #preload("res://path_to_your_audio_here!")
-        "Rifle_shot": null, #preload("res://path_to_your_audio_here!")
-        "Gun_cock": null, #preload("res://path_to_your_audio_here!")
-    }
-
-    const SIMPLE_AUDIO_PLAYER_SCENE = preload("res://Simple_Audio_Player.tscn")
-    var created_audio = []
-
-Let's go over these global variables.
-
-* ``audio_clips``: A dictionary holding all the audio clips ``Globals.gd`` can play.
-* ``SIMPLE_AUDIO_PLAYER_SCENE``: The simple audio player scene.
-* ``created_audio``: A list to hold all the simple audio players ``Globals.gd`` has created.
-
-.. note:: If you want to add additional audio, you need to add it to ``audio_clips``. No audio files are provided in this tutorial,
-          so you will have to provide your own.
-
-          One site I'd recommend is **GameSounds.xyz**.
-          I'm using the Gamemaster audio gun sound pack included in the Sonniss' GDC Game Audio bundle for 2017.
-          The tracks I've used (with some minor editing) are as follows:
-
-          * gun_revolver_pistol_shot_04,
-          * gun_semi_auto_rifle_cock_02,
-          * gun_submachine_auto_shot_00_automatic_preview_01
-
-______
-
-Now we need to add a new function called ``play_sound`` to ``Globals.gd``:
-
-::
-
-    func play_sound(sound_name, loop_sound=false, sound_position=null):
-        if audio_clips.has(sound_name):
-            var new_audio = SIMPLE_AUDIO_PLAYER_SCENE.instance()
-            new_audio.should_loop = loop_sound
-
-            add_child(new_audio)
-            created_audio.append(new_audio)
-
-            new_audio.play_sound(audio_clips[sound_name], sound_position)
-
-        else:
-            print ("ERROR: cannot play sound that does not exist in audio_clips!")
-
-Let's go over what this function does.
-
-Firstly, we check whether ``Globals.gd`` has an audio clip with the name ``sound_name`` in ``audio_clips``. If it does not, we print an error message.
-
-If ``Globals.gd`` has an audio clip with the name ``sound_name``, we then instance/spawn a new ``SIMPLE_AUDIO_PLAYER_SCENE`` and assign it to ``new_audio``.
-
-We then set ``should_loop``, and add ``new_audio`` as a child of ``Globals.gd``.
-
-.. note:: Remember, we have to be careful adding nodes to a singleton, since these nodes will not be destroyed when changing scenes.
-
-We add the ``new_audio`` into the ``created_audio`` list to hold all created audios.
-
-We then call ``play_sound``, passing in the audio clip associated with ``sound_name`` and the sound position.
-
-______
-
-Before we leave ``Globals.gd``, we need to add a few lines of code to ``load_new_scene`` so when the player changes scenes, all the audio is destroyed.
-
-Add the following to ``load_new_scene``:
-
-::
-
-    for sound in created_audio:
-        if (sound != null):
-            sound.queue_free()
-    created_audio.clear()
-
-Now, before ``Globals.gd`` changes scenes, it goes through each simple audio player in ``created_sounds`` and frees/destroys them. Once ``Globals.gd`` has gone through
-all the sounds in ``created_audio``, we clear ``created_audio`` so it no longer holds any references to any (now freed/destroyed) simple audio players.
-
-______
-
-Let's change ``create_sound`` in ``Player.gd`` to use this new system. First, remove ``simple_audio_player`` from ``Player.gd``'s class variables since we will
-no longer be directly instancing/spawning sounds in ``Player.gd``.
-
-Now, change ``create_sound`` to the following:
-
-::
-
-    func create_sound(sound_name, position=null):
-        globals.play_sound(sound_name, false, position)
-
-Now, whenever ``create_sound`` is called, we simply call ``play_sound`` in ``Globals.gd``, passing in all the arguments received.
-
-______
-
-Now all the sounds in our FPS can be played from anywhere. All we have to do is get the ``Globals.gd`` singleton, and call ``play_sound``, pass in the name of the sound
-we want to play, whether we want it to loop or not, and the position from which to play the sound.
-
-For example, if you want to play an explosion sound when the grenade explodes you'd need to add a new sound to ``audio_clips`` in ``Globals.gd``,
-get the ``Globals.gd`` singleton, and then you just need to add something like
-``globals.play_sound("explosion", false, global_transform.origin)`` in the grenades
-``_process`` function, right after the grenade damages all the bodies within its blast radius.
-
-Final notes
------------
-
-.. image:: img/FinishedTutorialPicture.png
-
-Now you have a fully working single player FPS!
-
-At this point, you have a good base to build more complicated FPS games.
-
-.. warning:: If you ever get lost, be sure to read over the code again!
-
-             You can download the finished project for the entire tutorial here: :download:`Godot_FPS_Part_6.zip <files/Godot_FPS_Finished.zip>`
-
-.. note:: The finished project source files contain the same code, just written in a different order.
-          This is because the finished project source files are what the tutorial is based on.
-
-          The finished project code was written in the order that features were created, not necessarily
-          in a order that is ideal for learning.
-
-          Other than that, the source is exactly the same, just with helpful comments explaining what
-          each part does.
-
-.. tip:: The finished project source is hosted on GitHub as well: https://github.com/TwistedTwigleg/Godot_FPS_Tutorial
-
-         **Please note that the code in GitHub may or may not be in sync with the tutorial in the documentation**.
-
-         The code in the documentation is likely better managed and/or more up to date.
-         If you are unsure of which to use, use the project(s) provided in the documentation, as they are maintained by the Godot community.
-
-You can download all the ``.blend`` files used in this tutorial here: :download:`Godot_FPS_BlenderFiles.zip <files/Godot_FPS_BlenderFiles.zip>`
-
-All assets provided in the started assets (unless otherwise noted) were **originally created by TwistedTwigleg, with changes/additions by the Godot community.**
-All original assets provided for this tutorial are released under the ``MIT`` license.
-
-Feel free to use these assets however you want! All original assets belong to the Godot community, with the other assets belonging to those listed below:
-
-The skybox is created by **StumpyStrust** and can be found at OpenGameArt.org. https://opengameart.org/content/space-skyboxes-0
-. The skybox is licensed under the ``CC0`` license.
-
-The font used is **Titillium-Regular**, and is licensed under the ``SIL Open Font License, Version 1.1``.
-
-The skybox was converted to a 360 equirectangular image using this tool: https://www.360toolkit.co/convert-cubemap-to-spherical-equirectangular.html
-
-While no sounds are provided, you can find many game ready sounds at https://gamesounds.xyz/
-
-.. warning:: **OpenGameArt.org, 360toolkit.co, the creator(s) of Titillium-Regular, StumpyStrust, and GameSounds.xyz are in no way involved in this tutorial.**
-

+ 0 - 697
tutorials/3d/fps_tutorial/part_three.rst

@@ -1,697 +0,0 @@
-.. _doc_fps_tutorial_part_three:
-
-Part 3
-======
-
-Part overview
--------------
-
-In this part, we will be limiting the player's weapons by giving them ammo. We will also
-be giving the player the ability to reload, and we will be adding sounds when the
-weapons fire.
-
-.. image:: img/PartThreeFinished.png
-
-.. note:: You are assumed to have finished :ref:`doc_fps_tutorial_part_two` before moving on to this part of the tutorial.
-          The finished project from :ref:`doc_fps_tutorial_part_two` will be the starting project for part 3
-
-Let's get started!
-
-
-Changing levels
----------------
-
-Now that we have a fully working FPS, let's move to a more FPS-like level.
-
-Open up ``Space_Level.tscn`` (``assets/Space_Level_Objects/Space_Level.tscn``)
-and/or ``Ruins_Level.tscn`` (``assets/Ruin_Level_Objects/Ruins_Level.tscn``).
-
-``Space_Level.tscn`` and ``Ruins_Level.tscn`` are complete custom FPS levels
-created for the purpose of this tutorial. Press ``Play Current Scene`` button,
-or :kbd:`F6` on keyboard, and give each a try.
-
-.. warning:: ``Space_Level.tscn`` is more graphically demanding of the GPU than ``Ruins_Level.tscn``. If your computer is struggling to render
-          ``Space_Level.tscn``, try using ``Ruins_Level.tscn`` instead.
-
-.. note::
-
-    Due to Godot updates since this tutorial was published, if you are using Godot 3.2 or later, you may need to apply the following changes to the Space Level and Ruins Level scenes:
-
-    - Open ``res://assets/Space_Level_Objects/Space_Level.tscn``.
-    - In the Scene tree dock, select the **Floor_and_Celing** node. In the Inspector dock, if the Mesh Library field under GridMap is ``[empty]``, set it to ``Space_Level_Mesh_Lib.tres`` by dragging the file ``res://assets/Space_Level_Objects/Space_Level_Mesh_Lib.tres`` from the FileSystem dock to that field.
-    - Do the same for the **Walls** node.
-    
-    - Open ``res://assets/Ruin_Level_Objects/Ruins_Level.tscn``.
-    - In the Scene tree dock, select the **Floor** node. In the Inspector dock, if the Mesh Library field under GridMap is ``[empty]``, set it to ``Ruin_Level_Mesh_Lib.tres`` by dragging the file ``res://assets/Ruin_Level_Objects/Ruin_Level_Mesh_Lib.tres`` from the FileSystem dock into that field.
-    - Do the same for the **Walls** node.
-
-You might have noticed there are several :ref:`RigidBody <class_RigidBody>` nodes placed throughout the level.
-We can place ``RigidBody_hit_test.gd`` on them and then they will react to being hit with bullets, so let's do that!
-
-Follow the instructions below for either (or both) of the scenes you want to use
-
-.. tabs::
- .. code-tab:: gdscript Space_Level.tscn
-
-    Expand "Other_Objects" and then expand "Physics_Objects".
-
-    Expand one of the "Barrel_Group" nodes and then select "Barrel_Rigid_Body" and open it using
-    the "Open in Editor" button.
-    This will bring you to the "Barrel_Rigid_Body" scene. From there, select the root node and
-    scroll the inspector down to the bottom.
-    Select the drop down arrow under the "Node" tab, and then select "Load". Navigate to
-    "RigidBody_hit_test.gd" and select "Open".
-
-    Return back to "Space_Level.tscn".
-
-    Expand one of the "Box_Group" nodes and then select "Crate_Rigid_Body" and open it using the
-    "Open in Editor" button.
-    This will bring you to the "Crate_Rigid_Body" scene. From there, select the root node and
-    scroll the inspector down to the bottom.
-    Select the drop down arrow under the "Node" tab, and then select "Load". Navigate to
-    "RigidBody_hit_test.gd" and select "Open".
-
-    Return to "Space_Level.tscn".
-
-
- .. code-tab:: gdscript Ruins_Level.tscn
-
-    Expand "Misc_Objects" and then expand "Physics_Objects".
-
-    Select all the "Stone_Cube" RigidBodies and then in the inspector scroll down to the bottom.
-    Select the drop down arrow under the "Node" tab, and then select "Load". Navigate to
-    "RigidBody_hit_test.gd" and select "Open".
-
-    Return to "Ruins_Level.tscn".
-
-Now you can fire at all the rigid bodies in either level and they will react to bullets hitting them!
-
-Adding ammo
------------
-
-Now that the player has working guns, let's give them a limited amount of ammo.
-
-Firstly, we need to define a few variables in each of our weapon scripts.
-
-Open up ``Weapon_Pistol.gd`` and add the following class variables:
-
-::
-
-    var ammo_in_weapon = 10
-    var spare_ammo = 20
-    const AMMO_IN_MAG = 10
-
-* ``ammo_in_weapon``: The amount of ammo currently in the pistol
-* ``spare_ammo``: The amount of ammo we have left in reserve for the pistol
-* ``AMMO_IN_MAG``: The amount of ammo in a fully reloaded weapon/magazine
-
-Now all we need to do is add a single line of code to ``fire_weapon``.
-
-Add the following right under ``Clone.BULLET_DAMAGE = DAMAGE``: ``ammo_in_weapon -= 1``
-
-This will remove one from ``ammo_in_weapon`` every time the player fires. Notice we're not checking to see
-if the player has enough ammo or not in ``fire_weapon``. Instead, we're going to check to see if the player has enough ammo in ``Player.gd``.
-
-_______
-
-Now we need to add ammo for both the rifle and the knife.
-
-.. note:: You may be wondering why we are adding ammo for the knife given it does not consume any ammunition.
-          The reason we want to add ammo to the knife is so we have a consistent interface for all our weapons.
-
-          If we did not add ammo variables for the knife, we would have to add checks for the knife. By adding the ammo
-          variables to the knife, we don't need to worry about whether or not all our weapons have the same variables.
-
-Add the following class variables to ``Weapon_Rifle.gd``:
-
-::
-
-    var ammo_in_weapon = 50
-    var spare_ammo = 100
-    const AMMO_IN_MAG = 50
-
-And then add the following to ``fire_weapon``: ``ammo_in_weapon -= 1``. Make sure that ``ammo_in_weapon -= 1`` is outside of the ``if ray.is_colliding()`` check so
-the player loses ammo regardless of whether the player hit something or not.
-
-Now all that's left is the knife. Add the following to ``Weapon_Knife.gd``:
-
-::
-
-    var ammo_in_weapon = 1
-    var spare_ammo = 1
-    const AMMO_IN_MAG = 1
-
-Because the knife does not consume ammo, that is all we need to add.
-
-_______
-
-Now we need to change one thing in ``Player.gd``, that is to say,
-
-how we're firing the weapons in ``process_input``. Change the code for firing weapons to the following:
-
-::
-
-    # ----------------------------------
-    # Firing the weapons
-    if Input.is_action_pressed("fire"):
-        if changing_weapon == false:
-            var current_weapon = weapons[current_weapon_name]
-            if current_weapon != null:
-                if current_weapon.ammo_in_weapon > 0:
-                    if animation_manager.current_state == current_weapon.IDLE_ANIM_NAME:
-                        animation_manager.set_animation(current_weapon.FIRE_ANIM_NAME)
-    # ----------------------------------
-
-Now the weapons have a limited amount of ammo, and will stop firing when the player runs out.
-
-_______
-
-Ideally, we'd like to let the player be able to see how much ammo is left. Let's make a new function called ``process_UI``.
-
-First, add ``process_UI(delta)`` to ``_physics_process``.
-
-Now add the following to ``Player.gd``:
-
-::
-
-    func process_UI(delta):
-        if current_weapon_name == "UNARMED" or current_weapon_name == "KNIFE":
-            UI_status_label.text = "HEALTH: " + str(health)
-        else:
-            var current_weapon = weapons[current_weapon_name]
-            UI_status_label.text = "HEALTH: " + str(health) + \
-                    "\nAMMO: " + str(current_weapon.ammo_in_weapon) + "/" + str(current_weapon.spare_ammo)
-
-Let's go over what's happening:
-
-Firstly, we check to see if the current weapon is either ``UNARMED`` or ``KNIFE``. If it is, we
-change the ``UI_status_label``'s text to only show the player's health since ``UNARMED`` and ``KNIFE`` do not consume ammo.
-
-If the player is using a weapon that consumes ammo, we first get the weapon node.
-
-Then we change ``UI_status_label``'s text to show the player's health, along with how much ammo the player has in the weapon
-and how much spare ammo the player has for that weapon.
-
-
-Now we can see how much ammo the player has through the HUD.
-
-Adding reloading to the weapons
--------------------------------
-
-Now that the player can run out of ammo, we need a way to let the player fill them back up. Let's add reloading next!
-
-For reloading, we need to add a few more variables and a function to every weapon.
-
-Open up ``Weapon_Pistol.gd`` and add the following class variables:
-
-::
-
-    const CAN_RELOAD = true
-    const CAN_REFILL = true
-
-    const RELOADING_ANIM_NAME = "Pistol_reload"
-
-* ``CAN_RELOAD``: A boolean to track whether this weapon has the ability to reload
-* ``CAN_REFILL``: A boolean to track whether we can refill this weapon's spare ammo. We will not be using ``CAN_REFILL`` in this part, but we will in the next part!
-* ``RELOADING_ANIM_NAME``: The name of the reloading animation for this weapon.
-
-Now we need to add a function for handling reloading. Add the following function to ``Weapon_Pistol.gd``:
-
-::
-
-    func reload_weapon():
-        var can_reload = false
-
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            can_reload = true
-
-        if spare_ammo <= 0 or ammo_in_weapon == AMMO_IN_MAG:
-            can_reload = false
-
-        if can_reload == true:
-            var ammo_needed = AMMO_IN_MAG - ammo_in_weapon
-
-            if spare_ammo >= ammo_needed:
-                spare_ammo -= ammo_needed
-                ammo_in_weapon = AMMO_IN_MAG
-            else:
-                ammo_in_weapon += spare_ammo
-                spare_ammo = 0
-
-            player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)
-
-            return true
-
-        return false
-
-Let's go over what's happening:
-
-First we define a variable to see whether or not this weapon can reload.
-
-Then we check to see if the player is in this weapon's idle animation state because we only want to be able to reload when the player is not
-firing, equipping, or unequipping.
-
-Next we check to see if the player has spare ammo, and if the ammo already in the weapon is equal to a fully reloaded weapon.
-This way we can ensure the player cannot reload when the player has no ammo or when the weapon is already full of ammo.
-
-If we can still reload, then we calculate the amount of ammo needed to reload the weapon.
-
-If the player has enough ammo to fill the weapon, we remove the ammo needed from ``spare_ammo`` and then set ``ammo_in_weapon`` to a full weapon/magazine.
-
-If the player does not have enough ammo, we add all the ammo left in ``spare_ammo``, and then set ``spare_ammo`` to ``0``.
-
-Next we play the reloading animation for this weapon, and then return ``true``.
-
-If the player could not reload, we return ``false``.
-
-_______
-
-Now we need to add reloading to the rifle. Open up ``Weapon_Rifle.gd`` and add the following class variables:
-
-::
-
-    const CAN_RELOAD = true
-    const CAN_REFILL = true
-
-    const RELOADING_ANIM_NAME = "Rifle_reload"
-
-These variables are exactly the same as the pistol, just with ``RELOADING_ANIM_NAME`` changed to the rifle's reloading animation.
-
-Now we need to add ``reload_weapon`` to ``Weapon_Rifle.gd``:
-
-::
-
-    func reload_weapon():
-        var can_reload = false
-
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            can_reload = true
-
-        if spare_ammo <= 0 or ammo_in_weapon == AMMO_IN_MAG:
-            can_reload = false
-
-        if can_reload == true:
-            var ammo_needed = AMMO_IN_MAG - ammo_in_weapon
-
-            if spare_ammo >= ammo_needed:
-                spare_ammo -= ammo_needed
-                ammo_in_weapon = AMMO_IN_MAG
-            else:
-                ammo_in_weapon += spare_ammo
-                spare_ammo = 0
-
-            player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)
-
-            return true
-
-        return false
-
-This code is exactly the same as the one for the pistol.
-
-_______
-
-The last bit we need to do for the weapons is add 'reloading' to the knife. Add the following class variables to ``Weapon_Knife.gd``:
-
-::
-
-    const CAN_RELOAD = false
-    const CAN_REFILL = false
-
-    const RELOADING_ANIM_NAME = ""
-
-Since we both cannot reload or refill a knife, we set both constants to ``false``. We also define ``RELOADING_ANIM_NAME`` as an empty string, since the knife
-has no reloading animation.
-
-Now we need to add ``reloading_weapon``:
-
-::
-
-    func reload_weapon():
-        return false
-
-Since we cannot reload a knife, we always return ``false``.
-
-Adding reloading to the player
-------------------------------
-
-Now we need to add a few things to ``Player.gd``. First we need to define a new class variable:
-
-::
-
-    var reloading_weapon = false
-
-* ``reloading_weapon``: A variable to track whether or not the player is currently trying to reload.
-
-
-Next we need to add another function call to ``_physics_process``.
-
-Add ``process_reloading(delta)`` to ``_physics_process``. Now ``_physics_process`` should look something like this:
-
-::
-
-    func _physics_process(delta):
-        process_input(delta)
-        process_movement(delta)
-        process_changing_weapons(delta)
-        process_reloading(delta)
-        process_UI(delta)
-
-Now we need to add ``process_reloading``. Add the following function to ``Player.gd``:
-
-::
-
-    func process_reloading(delta):
-        if reloading_weapon == true:
-            var current_weapon = weapons[current_weapon_name]
-            if current_weapon != null:
-                current_weapon.reload_weapon()
-            reloading_weapon = false
-
-Let's go over what's happening here.
-
-Firstly, we check to make sure the player is trying to reload.
-
-If the player is trying to reload, we then get the current weapon. If the current weapon does not equal ``null``, we call its ``reload_weapon`` function.
-
-.. note:: If the current weapon is equal to ``null``, then the current weapon is ``UNARMED``.
-
-Finally, we set ``reloading_weapon`` to ``false`` because, regardless of whether the player successfully reloaded, we've tried reloading
-and no longer need to keep trying.
-
-_______
-
-Before we can let the player reload, we need to change a few things in ``process_input``.
-
-The first thing we need to change is in the code for changing weapons. We need to add an additional check (``if reloading_weapon == false:``) to see if the player is reloading:
-
-::
-
-    if changing_weapon == false:
-        # New line of code here!
-        if reloading_weapon == false:
-            if WEAPON_NUMBER_TO_NAME[weapon_change_number] != current_weapon_name:
-                changing_weapon_name = WEAPON_NUMBER_TO_NAME[weapon_change_number]
-                changing_weapon = true
-
-This makes it so the player cannot change weapons if the player is reloading.
-
-Now we need to add the code to trigger a reload when the player pushes the ``reload`` action. Add the following code to ``process_input``:
-
-::
-
-    # ----------------------------------
-    # Reloading
-    if reloading_weapon == false:
-        if changing_weapon == false:
-            if Input.is_action_just_pressed("reload"):
-                var current_weapon = weapons[current_weapon_name]
-                if current_weapon != null:
-                    if current_weapon.CAN_RELOAD == true:
-                        var current_anim_state = animation_manager.current_state
-                        var is_reloading = false
-                        for weapon in weapons:
-                            var weapon_node = weapons[weapon]
-                            if weapon_node != null:
-                                if current_anim_state == weapon_node.RELOADING_ANIM_NAME:
-                                    is_reloading = true
-                        if is_reloading == false:
-                            reloading_weapon = true
-    # ----------------------------------
-
-Let's go over what's happening here.
-
-First we make sure the player is not reloading already, nor is the player trying to change weapons.
-
-Then we check to see if the ``reload`` action has been pressed.
-
-If the player has pressed ``reload``, we then get the current weapon and check to make sure it is not ``null``. Then we check to see whether the
-weapon can reload or not using its ``CAN_RELOAD`` constant.
-
-If the weapon can reload, we then get the current animation state, and make a variable for tracking whether the player is already reloading or not.
-
-We then go through every weapon to make sure the player is not already playing that weapon's reloading animation.
-
-If the player is not reloading any weapon, we set ``reloading_weapon`` to ``true``.
-
-_______
-
-One thing I like to add is where the weapon will reload itself if you try to fire it and it's out of ammo.
-
-We also need to add an additional if check (``is_reloading_weapon == false:``) so the player cannot fire the current weapon while
-reloading.
-
-Let's change our firing code in ``process_input`` so it reloads when trying to fire an empty weapon:
-
-::
-
-    # ----------------------------------
-    # Firing the weapons
-    if Input.is_action_pressed("fire"):
-        if reloading_weapon == false:
-            if changing_weapon == false:
-                var current_weapon = weapons[current_weapon_name]
-                if current_weapon != null:
-                    if current_weapon.ammo_in_weapon > 0:
-                        if animation_manager.current_state == current_weapon.IDLE_ANIM_NAME:
-                            animation_manager.set_animation(current_weapon.FIRE_ANIM_NAME)
-                    else:
-                        reloading_weapon = true
-    # ----------------------------------
-
-Now we check to make sure the player is not reloading before we fire the weapon, and when we have ``0`` or less ammo in the current weapon,
-we set ``reloading_weapon`` to ``true`` if the player tries to fire.
-
-This will make it so the player will try to reload when attempting to fire an empty weapon.
-
-_______
-
-With that done, the player can now reload! Give it a try! Now you can fire all the spare ammo for each weapon.
-
-Adding sounds
--------------
-
-Finally, let's add some sounds that accompany the player firing, reloading and changing weapons.
-
-.. tip:: There are no game sounds provided in this tutorial (for legal reasons).
-         https://gamesounds.xyz/ is a collection of **"royalty free or public domain music and sounds suitable for games"**.
-         I used Gamemaster's Gun Sound Pack, which can be found in the Sonniss.com GDC 2017 Game Audio Bundle.
-
-Open up ``Simple_Audio_Player.tscn``. It is simply a :ref:`Spatial <class_Spatial>` with an :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` as its child.
-
-.. note:: The reason this is called a 'simple' audio player is because we are not taking performance into account
-          and because the code is designed to provide sound in the simplest way possible.
-
-If you want to use 3D audio, so it sounds like it's coming from a location in 3D space, right click
-the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` and select "Change type".
-
-This will open the node browser. Navigate to :ref:`AudioStreamPlayer3D <class_AudioStreamPlayer3D>` and select "change".
-In the source for this tutorial, we will be using :ref:`AudioStreamPlayer <class_AudioStreamPlayer>`, but you can optionally
-use :ref:`AudioStreamPlayer3D <class_AudioStreamPlayer3D>` if you desire, and the code provided below will work regardless of which
-one you chose.
-
-Create a new script and call it ``Simple_Audio_Player.gd``. Attach it to the :ref:`Spatial <class_Spatial>` in ``Simple_Audio_Player.tscn``
-and insert the following code:
-
-::
-
-    extends Spatial
-
-    # All of the audio files.
-    # You will need to provide your own sound files.
-    var audio_pistol_shot = preload("res://path_to_your_audio_here")
-    var audio_gun_cock = preload("res://path_to_your_audio_here")
-    var audio_rifle_shot = preload("res://path_to_your_audio_here")
-
-    var audio_node = null
-
-    func _ready():
-        audio_node = $Audio_Stream_Player
-        audio_node.connect("finished", self, "destroy_self")
-        audio_node.stop()
-
-
-    func play_sound(sound_name, position=null):
-
-        if audio_pistol_shot == null or audio_rifle_shot == null or audio_gun_cock == null:
-            print ("Audio not set!")
-            queue_free()
-            return
-
-        if sound_name == "Pistol_shot":
-            audio_node.stream = audio_pistol_shot
-        elif sound_name == "Rifle_shot":
-            audio_node.stream = audio_rifle_shot
-        elif sound_name == "Gun_cock":
-            audio_node.stream = audio_gun_cock
-        else:
-            print ("UNKNOWN STREAM")
-            queue_free()
-            return
-
-        # If you are using an AudioStreamPlayer3D, then uncomment these lines to set the position.
-        #if audio_node is AudioStreamPlayer3D:
-        #    if position != null:
-        #        audio_node.global_transform.origin = position
-
-        audio_node.play()
-
-
-    func destroy_self():
-        audio_node.stop()
-        queue_free()
-
-
-.. tip:: By setting ``position`` to ``null`` by default in ``play_sound``, we are making it an optional argument,
-         meaning ``position`` doesn't necessarily have to be passed in to call ``play_sound``.
-
-Let's go over what's happening here:
-
-_________
-
-In ``_ready``, we get the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` and connect its ``finished`` signal to the ``destroy_self`` function.
-It doesn't matter if it's an :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` or :ref:`AudioStreamPlayer3D <class_AudioStreamPlayer3D>` node,
-as they both have the finished signal. To make sure it is not playing any sounds, we call ``stop`` on the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>`.
-
-.. warning:: Make sure your sound files are **not** set to loop! If it is set to loop,
-             the sounds will continue to play infinitely and the script will not work!
-
-The ``play_sound`` function is what we will be calling from ``Player.gd``. We check if the sound
-is one of the three possible sounds, and if it is one of the three sounds we set the audio stream in :ref:`AudioStreamPlayer <class_AudioStreamPlayer>`
-to the correct sound.
-
-If it is an unknown sound, we print an error message to the console and free the audio player.
-
-If you are using an :ref:`AudioStreamPlayer3D <class_AudioStreamPlayer3D>`, remove the ``#`` to set the position of
-the audio player node so it plays at the correct position.
-
-Finally, we tell the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` to play.
-
-When the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` is finished playing the sound, it will call ``destroy_self`` because
-we connected the ``finished`` signal in ``_ready``. We stop the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` and free the audio player
-to save on resources.
-
-.. note:: This system is extremely simple and has some major flaws:
-
-          One flaw is we have to pass in a string value to play a sound. While it is relatively simple
-          to remember the names of the three sounds, it can be increasingly complex when you have more sounds.
-          Ideally, we'd place these sounds in some sort of container with exposed variables so we do not have
-          to remember the name(s) of each sound effect we want to play.
-
-          Another flaw is we cannot play looping sounds effects, nor background music, easily with this system.
-          Because we cannot play looping sounds, certain effects, like footstep sounds, are harder to accomplish
-          because we then have to keep track of whether or not there is a sound effect and whether or not we
-          need to continue playing it.
-
-          One of the biggest flaws with this system is we can only play sounds from ``Player.gd``.
-          Ideally we'd like to be able to play sounds from any script at any time.
-
-_________
-
-With that done, let's open up ``Player.gd`` again.
-First we need to load the ``Simple_Audio_Player.tscn``. Place the following code in the class variables section of the script:
-
-::
-
-    var simple_audio_player = preload("res://Simple_Audio_Player.tscn")
-
-Now we need to instance the simple audio player when we need it, and then call its
-``play_sound`` function and pass the name of the sound we want to play. To make the process simpler,
-let's create a ``create_sound`` function in ``Player.gd``:
-
-::
-
-    func create_sound(sound_name, position=null):
-        var audio_clone = simple_audio_player.instance()
-        var scene_root = get_tree().root.get_children()[0]
-        scene_root.add_child(audio_clone)
-        audio_clone.play_sound(sound_name, position)
-
-Let's walk through what this function does:
-
-_________
-
-The first line instances the ``Simple_Audio_Player.tscn`` scene and assigns it to a variable
-named ``audio_clone``.
-
-The second line gets the scene root, and this has a large (though safe) assumption.
-
-We first get this node's :ref:`SceneTree <class_SceneTree>`,
-and then access the root node, which in this case is the :ref:`Viewport <class_Viewport>` this entire game is running under.
-Then we get the first child of the :ref:`Viewport <class_Viewport>`, which in our case happens to be the root node in
-``Test_Area.tscn`` or any of the other provided levels. **We are making a huge assumption that the first child of the root node
-is the root scene that the player is under, which may not always be the case**.
-
-If this doesn't make sense to you, don't worry too much about it. The second line of code only does not work
-reliably if you have multiple scenes loaded as children of the root node at a time, which will rarely happen for most projects and will not be happening in this tutorial series.
-This is only potentially a issue depending on how you handle scene loading.
-
-The third line adds our newly created ``Simple_Audio_Player`` scene to be a child of the scene root. This
-works exactly the same as when we are spawning bullets.
-
-Finally, we call the ``play_sound`` function and pass in the arguments passed in to ``create_sound``. This will call
-``Simple_Audio_Player.gd``'s ``play_sound`` function with the passed in arguments.
-
-_________
-
-Now all that is left is playing the sounds when we want to. Let's add sound to the pistol first!
-
-Open up ``Weapon_Pistol.gd``.
-
-Now, we want to make a noise when the player fires the pistol, so add the following to the end of the ``fire_weapon`` function:
-
-::
-
-    player_node.create_sound("Pistol_shot", self.global_transform.origin)
-
-Now when the player fires the pistol, we'll play the ``Pistol_shot`` sound.
-
-To make a sound when the player reloads, we need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
-``reload_weapon`` function:
-
-::
-
-    player_node.create_sound("Gun_cock", player_node.camera.global_transform.origin)
-
-Now when the player reloads, we'll play the ``Gun_cock`` sound.
-
-_________
-
-Now let's add sounds to the rifle.
-Open up ``Weapon_Rifle.gd``.
-
-To play sounds when the rifle is fired, add the following to the end of the ``fire_weapon`` function:
-
-::
-
-    player_node.create_sound("Rifle_shot", ray.global_transform.origin)
-
-Now when the player fires the rifle, we'll play the ``Rifle_shot`` sound.
-
-To make a sound when the player reloads, we need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
-``reload_weapon`` function:
-
-::
-
-    player_node.create_sound("Gun_cock", player_node.camera.global_transform.origin)
-
-Now when the player reloads, we'll play the ``Gun_cock`` sound.
-
-Final notes
------------
-
-.. image:: img/PartThreeFinished.png
-
-Now you have weapons with limited ammo that play sounds when you fire them!
-
-At this point, we have all the basics of an FPS game working.
-There are still a few things that would be nice to add, and we're going to add them in the next three parts!
-
-For example, right now we have no way to add ammo to our spares, so we'll eventually run out. Also, we don't
-have anything to shoot at outside of the :ref:`RigidBody <class_RigidBody>` nodes.
-
-In :ref:`doc_fps_tutorial_part_four` we'll add some targets to shoot at, along with some health and ammo pick ups!
-We're also going to add joypad support, so we can play with wired Xbox 360 controllers!
-
-.. warning:: If you ever get lost, be sure to read over the code again!
-
-             You can download the finished project for this part here: :download:`Godot_FPS_Part_3.zip <files/Godot_FPS_Part_3.zip>`

+ 0 - 1239
tutorials/3d/fps_tutorial/part_two.rst

@@ -1,1239 +0,0 @@
-.. _doc_fps_tutorial_part_two:
-
-Part 2
-======
-
-Part overview
--------------
-
-In this part we will be giving our player weapons to play with.
-
-.. image:: img/PartTwoFinished.png
-
-By the end of this part, you will have a player that can fire a pistol,
-rifle, and attack using a knife. The player will also now have animations with transitions,
-and the weapons will interact with objects in the environment.
-
-.. note:: You are assumed to have finished :ref:`doc_fps_tutorial_part_one` before moving on to this part of the tutorial.
-          The finished project from :ref:`doc_fps_tutorial_part_one` will be the starting project for part 2
-
-Let's get started!
-
-Making a system to handle animations
-------------------------------------
-
-First we need a way to handle changing animations. Open up ``Player.tscn`` and select the :ref:`AnimationPlayer <class_AnimationPlayer>`
-Node (``Player`` -> ``Rotation_Helper`` -> ``Model`` -> ``Animation_Player``).
-
-Create a new script called ``AnimationPlayer_Manager.gd`` and attach that to the :ref:`AnimationPlayer <class_AnimationPlayer>`.
-
-Add the following code to ``AnimationPlayer_Manager.gd``:
-
-::
-
-    extends AnimationPlayer
-
-    # Structure -> Animation name :[Connecting Animation states]
-    var states = {
-        "Idle_unarmed":["Knife_equip", "Pistol_equip", "Rifle_equip", "Idle_unarmed"],
-
-        "Pistol_equip":["Pistol_idle"],
-        "Pistol_fire":["Pistol_idle"],
-        "Pistol_idle":["Pistol_fire", "Pistol_reload", "Pistol_unequip", "Pistol_idle"],
-        "Pistol_reload":["Pistol_idle"],
-        "Pistol_unequip":["Idle_unarmed"],
-
-        "Rifle_equip":["Rifle_idle"],
-        "Rifle_fire":["Rifle_idle"],
-        "Rifle_idle":["Rifle_fire", "Rifle_reload", "Rifle_unequip", "Rifle_idle"],
-        "Rifle_reload":["Rifle_idle"],
-        "Rifle_unequip":["Idle_unarmed"],
-
-        "Knife_equip":["Knife_idle"],
-        "Knife_fire":["Knife_idle"],
-        "Knife_idle":["Knife_fire", "Knife_unequip", "Knife_idle"],
-        "Knife_unequip":["Idle_unarmed"],
-    }
-
-    var animation_speeds = {
-        "Idle_unarmed":1,
-
-        "Pistol_equip":1.4,
-        "Pistol_fire":1.8,
-        "Pistol_idle":1,
-        "Pistol_reload":1,
-        "Pistol_unequip":1.4,
-
-        "Rifle_equip":2,
-        "Rifle_fire":6,
-        "Rifle_idle":1,
-        "Rifle_reload":1.45,
-        "Rifle_unequip":2,
-
-        "Knife_equip":1,
-        "Knife_fire":1.35,
-        "Knife_idle":1,
-        "Knife_unequip":1,
-    }
-
-    var current_state = null
-    var callback_function = null
-
-    func _ready():
-        set_animation("Idle_unarmed")
-        connect("animation_finished", self, "animation_ended")
-
-    func set_animation(animation_name):
-        if animation_name == current_state:
-            print ("AnimationPlayer_Manager.gd -- WARNING: animation is already ", animation_name)
-            return true
-
-
-        if has_animation(animation_name):
-            if current_state != null:
-                var possible_animations = states[current_state]
-                if animation_name in possible_animations:
-                    current_state = animation_name
-                    play(animation_name, -1, animation_speeds[animation_name])
-                    return true
-                else:
-                    print ("AnimationPlayer_Manager.gd -- WARNING: Cannot change to ", animation_name, " from ", current_state)
-                    return false
-            else:
-                current_state = animation_name
-                play(animation_name, -1, animation_speeds[animation_name])
-                return true
-        return false
-
-
-    func animation_ended(anim_name):
-
-        # UNARMED transitions
-        if current_state == "Idle_unarmed":
-            pass
-        # KNIFE transitions
-        elif current_state == "Knife_equip":
-            set_animation("Knife_idle")
-        elif current_state == "Knife_idle":
-            pass
-        elif current_state == "Knife_fire":
-            set_animation("Knife_idle")
-        elif current_state == "Knife_unequip":
-            set_animation("Idle_unarmed")
-        # PISTOL transitions
-        elif current_state == "Pistol_equip":
-            set_animation("Pistol_idle")
-        elif current_state == "Pistol_idle":
-            pass
-        elif current_state == "Pistol_fire":
-            set_animation("Pistol_idle")
-        elif current_state == "Pistol_unequip":
-            set_animation("Idle_unarmed")
-        elif current_state == "Pistol_reload":
-            set_animation("Pistol_idle")
-        # RIFLE transitions
-        elif current_state == "Rifle_equip":
-            set_animation("Rifle_idle")
-        elif current_state == "Rifle_idle":
-            pass
-        elif current_state == "Rifle_fire":
-            set_animation("Rifle_idle")
-        elif current_state == "Rifle_unequip":
-            set_animation("Idle_unarmed")
-        elif current_state == "Rifle_reload":
-            set_animation("Rifle_idle")
-
-    func animation_callback():
-        if callback_function == null:
-            print ("AnimationPlayer_Manager.gd -- WARNING: No callback function for the animation to call!")
-        else:
-            callback_function.call_func()
-
-Lets go over what this script is doing:
-
-_________
-
-Lets start with this script's class variables:
-
-- ``states``: A dictionary for holding our animation states. (Further explanation below)
-- ``animation_speeds``: A dictionary for holding all the speeds at which we want to play our animations.
-- ``current_state``: A variable for holding the name of the animation state we are currently in.
-- ``callback_function``: A variable for holding the callback function. (Further explanation below)
-
-If you are familiar with state machines, then you may have noticed that ``states`` is structured
-like a basic state machine. Here is roughly how ``states`` is set up:
-
-``states`` is a dictionary with the key being the name of the current state, and the value being
-an array holding all the animations (states) we can transition to. For example, if we are currently in the
-``Idle_unarmed`` state, we can only transition to ``Knife_equip``, ``Pistol_equip``, ``Rifle_equip``, and
-``Idle_unarmed``.
-
-If we try to transition to a state that is not included in the possible transitions states for the state we are in,
-then we get a warning message and the animation does not change. We can also automatically
-transition from some states into others, as will be explained further below in ``animation_ended``.
-
-.. note:: For the sake of keeping this tutorial simple, we are not using a 'proper'
-          state machine. If you are interested to know more about state machines,
-          see the following articles:
-
-          - (Python example) https://dev.to/karn/building-a-simple-state-machine-in-python
-          - (C# example) https://www.codeproject.com/Articles/489136/UnderstandingplusandplusImplementingplusStateplusP
-          - (Wiki article) https://en.wikipedia.org/wiki/Finite-state_machine
-
-``animation_speeds`` is how fast each animation will play. Some of the animations are a little slow
-and in an effort to make everything look smooth, we need to play them at faster speeds.
-
-.. tip:: Notice that all of the firing animations are faster than their normal speed. Remember this for later!
-
-``current_state`` will hold the name of the animation state we are currently in.
-
-Finally, ``callback_function`` will be a :ref:`FuncRef <class_FuncRef>` passed in by the player for spawning bullets
-at the proper frame of animation. A :ref:`FuncRef <class_FuncRef>` allows us to pass in a function as an argument,
-effectively allowing us to call a function from another script, which is how we will use it later.
-
-_________
-
-Now let's look at ``_ready``.
-
-First we are setting our animation to ``Idle_unarmed`` using the ``set_animation`` function,
-so we for sure start in that animation.
-
-Next we connect the ``animation_finished`` signal to this script and assign it to call ``animation_ended``.
-This means whenever an animation is finished, ``animation_ended`` will be called.
-
-_________
-
-Let's look at ``set_animation`` next.
-
-``set_animation`` changes the animation to the animation named ``animation_name``
-*if* we can transition to it. In other words, if the animation state we are currently in
-has the passed in animation state name in ``states``, then we will change to that animation.
-
-Firstly, we check if the passed in animation name is the same name as the animation currently playing.
-If they are the same, then we write a warning to the console and return ``true``.
-
-Secondly, we see if :ref:`AnimationPlayer <class_AnimationPlayer>` has the animation with the name ``animation_name`` using ``has_animation``.
-If it does not, we return ``false``.
-
-Thirdly, we check whether ``current_state`` is set. If we have a state in ``current_state``, then we get all the possible states we can transition to.
-
-If the animation name is in the list of possible transitions, we set ``current_state`` to the passed in
-animation (``animation_name``), tell :ref:`AnimationPlayer <class_AnimationPlayer>` to play the animation with
-a blend time of ``-1`` at the speed set in ``animation_speeds`` and return ``true``.
-
-.. note:: Blend time is how long to blend/mix the two animations together.
-
-          By putting in a value of ``-1``, the new animation instantly plays, overriding whatever animation is already playing.
-
-          If you put in a value of ``1``, for one second the new animation will play with increasing strength, blending the two animations together for one second
-          before playing only the new animation. This leads to a smooth transition between animations, which looks great when you are changing from
-          a walking animation to a running animation.
-
-          We set the blend time to ``-1`` because we want to instantly change animations.
-
-_________
-
-Now let's look at ``animation_ended``.
-
-``animation_ended`` is the function that will be called by :ref:`AnimationPlayer <class_AnimationPlayer>` when it's done playing an animation.
-
-
-For certain animation states, we may need to transition into another state when it's finished. To handle this, we
-check for every possible animation state. If we need to, we will transition into another state.
-
-.. warning:: If you are using your own animated models, make sure that none of the animations are set
-             to loop. Looping animations do not send the ``animation_finished`` signal when they reach
-             the end of the animation and are about to loop again.
-
-.. note:: The transitions in ``animation_ended`` would ideally be part of the data in ``states``, but in
-          an effort to make the tutorial easier to understand, we'll hard code each state transition
-          in ``animation_ended``.
-
-_________
-
-Finally, there is ``animation_callback``. This function will be called by a call method track in our animations.
-If we have a :ref:`FuncRef <class_FuncRef>` assigned to ``callback_function``, then we call that passed in function. If we do not
-have a :ref:`FuncRef <class_FuncRef>` assigned to ``callback_function``, we print out a warning to the console.
-
-.. tip:: Try running ``Testing_Area.tscn`` to make sure there are no runtime issues. If the game runs but nothing
-         seems to have changed, then everything is working correctly.
-
-Getting the animations ready
-----------------------------
-
-Now that we have a working animation manager, we need to call it from our player script.
-Before that, though, we need to set some animation callback tracks in our firing animations.
-
-Open up ``Player.tscn`` if you don't have it open and navigate to the :ref:`AnimationPlayer <class_AnimationPlayer>` node
-(``Player`` -> ``Rotation_Helper`` -> ``Model`` -> ``Animation_Player``).
-
-We need to attach a call method track to three of our animations: The firing animation for the pistol, rifle, and knife.
-Let's start with the pistol. Click the animation drop down list and select "Pistol_fire".
-
-Now scroll down to the bottom of the list of animation tracks. The final item in the list should read
-``Armature/Skeleton:Left_UpperPointer``. Now above the list, click the "Add track" button, to the left of the time line
-
-.. image:: img/AnimationPlayerAddTrack.png
-
-This will bring up a window with a few choices. We want to add a call method track, so click the
-option that reads "Call Method Track". This will open a window showing the entire node tree. Navigate to the
-:ref:`AnimationPlayer <class_AnimationPlayer>` node, select it, and press OK.
-
-.. image:: img/AnimationPlayerCallFuncTrack.png
-
-Now at the bottom of list of animation tracks you will have a green track that reads "AnimationPlayer".
-Now we need to add the point where we want to call our callback function. Scrub the timeline until you
-reach the point where the muzzle starts to flash.
-
-.. note:: The timeline is the window where all the points in our animation are stored. Each of the little
-          points represents a point of animation data.
-
-          To actually preview the "Pistol_fire" animation, select the :ref:`Camera <class_Camera>` node
-          underneath Rotation Helper and check the "Preview" box underneath Perspective in the top-left corner.
-
-
-          Scrubbing the timeline means moving ourselves through the animation. So when we say "scrub the timeline
-          until you reach a point", what we mean is move through the animation window until you reach the point
-          on the timeline.
-
-          Also, the muzzle of a gun is the end point where the bullet comes out. The muzzle flash is the flash of
-          light that escapes the muzzle when a bullet is fired. The muzzle is also sometimes referred to as the
-          barrel of the gun.
-
-.. tip:: For finer control when scrubbing the timeline, press :kbd:`Ctrl` and scroll forward with the mouse wheel to zoom in.
-         Scrolling backwards will zoom out.
-
-         You can also change how the timeline scrubbing snaps by changing the value in ``Step (s)`` to a lower/higher value.
-
-Once you get to a point you like, right click on the row for "Animation Player" and press ``Insert Key``.
-In the empty name field, enter ``animation_callback`` and press :kbd:`Enter`.
-
-.. image:: img/AnimationPlayerInsertKey.png
-
-
-Now when we are playing this animation the call method track will be triggered at that specific point of the animation.
-
-_________
-
-Let's repeat the process for the rifle and knife firing animations!
-
-.. note:: Because the process is exactly the same as the pistol, the process is going to explained in a little less depth.
-          Follow the steps from above if you get lost! It is exactly the same, just on a different animation.
-
-Go to the "Rifle_fire" animation from the animation drop down. Add the call method track once you reach the bottom of the
-animation track list by clicking the "Add Track" button above the list. Find the point where the muzzle starts
-to flash and right click and press ``Insert Key`` to add a call method track point at that position on the track.
-
-Type "animation_callback" into the name field of the pop up which opened and press :kbd:`Enter`.
-
-Now we need to apply the callback method track to the knife animation. Select the "Knife_fire" animation and scroll to the bottom of the
-animation tracks. Click the "Add Track" button above the list and add a method track.
-Next find a point around the first third of the animation to place the animation callback method point at.
-
-.. note:: We will not actually be firing the knife, and the animation is a stabbing animation rather than a firing one.
-         For this tutorial we are reusing the gun firing logic for our knife, so the animation has been named in a style that
-         is consistent with the other animations.
-
-From there right click on the timeline and click "Insert Key". Put "animation_callback" into the name field and press :kbd:`Enter`.
-
-.. tip:: Be sure to save your work!
-
-With that done, we are almost ready to start adding the ability to fire to our player script! We need to set up one last scene:
-The scene for our bullet object.
-
-Creating the bullet scene
--------------------------
-
-There are several ways to handle a gun's bullets in video games. In this tutorial series,
-we will be exploring two of the more common ways: Objects, and raycasts.
-
-_________
-
-One of the two ways is using a bullet object. This will be an object that travels through the world and handles
-its own collision code. In this method we create/spawn a bullet object in the direction our gun is facing, and then
-it travels forward.
-
-There are several advantages to this method. The first being we do not have to store the bullets in our player. We can simply create the bullet
-and then move on, and the bullet itself will handle checking for collisions, sending the proper signal(s) to the object it collides with, and destroying itself.
-
-Another advantage is we can have more complex bullet movement. If we want to make the bullet fall ever so slightly as time goes on, we can make the bullet
-controlling script slowly push the bullet towards the ground. Using an object also makes the bullet take time to reach its target, it doesn't instantly
-hit whatever it's pointed at. This feels more realistic because nothing in real life moves instantly from one point to another.
-
-One of the huge disadvantages is performance. While having each bullet calculate their own paths and handle their own collision allows for a lot of flexibility,
-it comes at the cost of performance. With this method we are calculating every bullet's movement every step, and while this may not be a problem for a few dozen
-bullets, it can become a huge problem when you potentially have several hundred bullets.
-
-Despite the performance hit, many first person shooters include some form of object bullets. Rocket launchers are a prime example because in many
-first person shooters, rockets do not just instantly explode at their target position. You can also find bullets as objects many times with grenades
-because they generally bounce around the world before exploding.
-
-.. note:: While I cannot say for sure this is the case, these games *probably* use bullet objects in some form or another:
-          (These are entirely from my observations. **They may be entirely wrong**. I have never worked on **any** of the following games)
-
-          - Halo (Rocket launchers, fragmentation grenades, sniper rifles, brute shot, and more)
-          - Destiny (Rocket launchers, grenades, fusion rifles, sniper rifles, super moves, and more)
-          - Call of Duty (Rocket launchers, grenades, ballistic knives, crossbows, and more)
-          - Battlefield (Rocket launchers, grenades, claymores, mortars, and more)
-
-Another disadvantage with bullet objects is networking. Bullet objects have to sync the positions (at least) with all the clients that are connected
-to the server.
-
-While we are not implementing any form of networking (as that would be in its own entire tutorial series), it is a consideration
-to keep in mind when creating your first person shooter, especially if you plan on adding some form of networking in the future.
-
-_________
-
-The other way of handling bullet collisions we will be looking at is raycasting.
-
-This method is extremely common in guns that have fast moving bullets that rarely change trajectory over time.
-
-Instead of creating a bullet object and sending it through space, we instead send a ray starting from the barrel/muzzle of the gun forwards.
-We set the raycast's origin to the starting position of the bullet, and based on the length we can adjust how far the bullet 'travels' through space.
-
-.. note:: While I cannot say for sure this is the case, these games *probably* use raycasts in some form or another:
-          (These are entirely from my observations. **They may be entirely wrong**. I have never worked on **any** of the following games)
-
-          - Halo (Assault rifles, DMRs, battle rifles, covenant carbine, spartan laser, and more)
-          - Destiny (Auto rifles, pulse rifles, scout rifles, hand cannons, machine guns, and more)
-          - Call of Duty (Assault rifles, light machine guns, sub machine guns, pistols, and more)
-          - Battlefield (Assault rifles, SMGs, carbines, pistols, and more)
-
-One huge advantage of this method is that it's light on performance.
-Sending a couple hundred rays through space is *much* easier for the computer to calculate than sending a couple hundred
-bullet objects.
-
-Another advantage is we can instantly know if we've hit something or not exactly when we call for it. For networking this is important because we do not need
-to sync the bullet movements over the Internet, we only need to send whether or not the raycast hit.
-
-Raycasting does have some disadvantages, though. One major disadvantage is we cannot easily cast a ray in anything but a linear line.
-This means we can only fire in a straight line for however long our ray length is. You can create the illusion of bullet movement by casting
-multiple rays at different positions, but not only is this hard to implement in code, it is also heavier on performance.
-
-Another disadvantage is we cannot see the bullet. With bullet objects we can actually see the bullet travel through space if we attach a mesh
-to it, but because raycasts happen instantly, we do not have a decent way of showing the bullets. You could draw a line from the origin of the
-raycast to the point where the raycast collided, and that is one popular way of showing raycasts. Another way is simply not drawing the raycast
-at all, because theoretically the bullets move so fast our eyes could not see it anyway.
-
-_________
-
-Let's get the bullet object set up. This is what our pistol will create when the "Pistol_fire" animation callback function is called.
-
-
-Open up ``Bullet_Scene.tscn``. The scene contains :ref:`Spatial <class_Spatial>` node called bullet, with a :ref:`MeshInstance <class_MeshInstance>`
-and an :ref:`Area <class_Area>` with a :ref:`CollisionShape <class_CollisionShape>` children to it.
-
-
-Create a new script called ``Bullet_script.gd`` and attach it to the ``Bullet`` :ref:`Spatial <class_Spatial>`.
-
-We are going to move the entire bullet object at the root (``Bullet``). We will be using the :ref:`Area <class_Area>` to check whether or not we've collided with something
-
-.. note:: Why are we using an :ref:`Area <class_Area>` and not a :ref:`RigidBody <class_RigidBody>`? The main reason we're not using a :ref:`RigidBody <class_RigidBody>`
-          is because we do not want the bullet to interact with other :ref:`RigidBody <class_RigidBody>` nodes.
-          By using an :ref:`Area <class_Area>` we are ensuring that none of the other :ref:`RigidBody <class_RigidBody>` nodes, including other bullets, will be effected.
-
-          Another reason is simply because it is easier to detect collisions with an :ref:`Area <class_Area>`!
-
-Here's the script that will control our bullet:
-
-::
-
-    extends Spatial
-
-    var BULLET_SPEED = 70
-    var BULLET_DAMAGE = 15
-
-    const KILL_TIMER = 4
-    var timer = 0
-
-    var hit_something = false
-
-    func _ready():
-        $Area.connect("body_entered", self, "collided")
-
-
-    func _physics_process(delta):
-        var forward_dir = global_transform.basis.z.normalized()
-        global_translate(forward_dir * BULLET_SPEED * delta)
-
-        timer += delta
-        if timer >= KILL_TIMER:
-            queue_free()
-
-
-    func collided(body):
-        if hit_something == false:
-            if body.has_method("bullet_hit"):
-                body.bullet_hit(BULLET_DAMAGE, global_transform)
-
-        hit_something = true
-        queue_free()
-
-
-Let's go through the script:
-
-_________
-
-First we define a few class variables:
-
-- ``BULLET_SPEED``: The speed at which the bullet travels.
-- ``BULLET_DAMAGE``: The damage the bullet will cause to anything with which it collides.
-- ``KILL_TIMER``: How long the bullet can last without hitting anything.
-- ``timer``: A float for tracking how long the bullet has been alive.
-- ``hit_something``: A boolean for tracking whether or not we've hit something.
-
-With the exception of ``timer`` and ``hit_something``, all of these variables
-change how the bullet interacts with the world.
-
-.. note:: The reason we are using a kill timer is so we do not have a case where we
-          get a bullet travelling forever. By using a kill timer, we can ensure that
-          no bullets will travel forever and consume resources.
-
-.. tip:: As in :ref:`doc_fps_tutorial_part_one`, we have a couple all uppercase class variables. The reason behind this is the same
-         as the reason given in :ref:`doc_fps_tutorial_part_one`: We want to treat these variables like constants, but we want to be
-         able to change them. In this case we will later need to change the damage and speed of these bullets,
-         so we need them to be variables and not constants.
-
-_________
-
-In ``_ready`` we set the area's ``body_entered`` signal to ourself so that it calls
-the ``collided`` function when a body enters the area.
-
-_________
-
-``_physics_process`` gets the bullet's local ``Z`` axis. If you look at the scene
-in local mode, you will find that the bullet faces the positive local ``Z`` axis.
-
-Next we translate the entire bullet by that forward direction, multiplying in our speed and delta time.
-
-After that we add delta time to our timer and check whether the timer has reached a value as big or greater
-than our ``KILL_TIME`` constant. If it has, we use ``queue_free`` to free the bullet.
-
-_________
-
-In ``collided`` we check whether we've hit something yet.
-
-Remember that ``collided`` is only called when a body has entered the :ref:`Area <class_Area>` node.
-If the bullet has not already collided with something, we then proceed to check if the body the bullet has collided
-with has a function/method called ``bullet_hit``. If it does, we call it and pass in the bullet's damage and the bullet's global transform
-so we can get the bullet's rotation and position.
-
-.. note:: in ``collided``, the passed in body can be a :ref:`StaticBody <class_StaticBody>`,
-          :ref:`RigidBody <class_RigidBody>`, or :ref:`KinematicBody <class_KinematicBody>`
-
-We set the Bullet's ``hit_something`` variable to ``true`` because regardless of whether or not the body that
-the bullet collided with has the ``bullet_hit`` function/method, it has hit something and so we need to make sure the bullet does not hit anything else.
-
-Then we free the bullet using ``queue_free``.
-
-.. tip:: You may be wondering why we even have a ``hit_something`` variable if we
-         free the bullet using ``queue_free`` as soon as it hits something.
-
-         The reason we need to track whether we've hit something or not is because ``queue_free``
-         does not immediately free the node, so the bullet could collide with another body
-         before Godot has a chance to free it. By tracking whether the bullet has hit something,
-         we can make sure that the bullet will only hit one object.
-
-
-_________
-
-Before we start programming the player again, let's take a quick look at ``Player.tscn``.
-Open up ``Player.tscn`` again.
-
-Expand ``Rotation_Helper`` and notice how it has two nodes: ``Gun_Fire_Points`` and
-``Gun_Aim_Point``.
-
-``Gun_aim_point`` is the point that the bullets will be aiming at. Notice how it
-is lined up with the center of the screen and pulled a distance forward on the Z
-axis. ``Gun_aim_point`` will serve as the point where the bullets will for sure collide
-with as it goes along.
-
-.. note:: There is a invisible mesh instance for debugging purposes. The mesh is
-          a small sphere that visually shows at which target the bullets will be aiming.
-
-Open up ``Gun_Fire_Points`` and you'll find three more :ref:`Spatial <class_Spatial>` nodes, one for each
-weapon.
-
-Open up ``Rifle_Point`` and you'll find a :ref:`Raycast <class_Raycast>` node. This is where
-we will be sending the raycasts for our rifle's bullets.
-The length of the raycast will dictate how far our bullets will travel.
-
-We are using a :ref:`Raycast <class_Raycast>` node to handle the rifle's bullet because
-we want to fire lots of bullets quickly. If we use bullet objects, it is quite possible
-we could run into performance issues on older machines.
-
-.. note:: If you are wondering from where the positions of the points came, they
-          are the rough positions of the ends of each weapon. You can see this by
-          going to ``AnimationPlayer``, selecting one of the firing animations
-          and scrubbing through the timeline. The point for each weapon should mostly line
-          up with the end of each weapon.
-
-Open up ``Knife_Point`` and you'll find an :ref:`Area <class_Area>` node. We are using an :ref:`Area <class_Area>` for the knife
-because we only care for all the bodies close to us, and because our knife does
-not fire into space. If we were making a throwing knife, we would likely spawn a bullet
-object that looks like a knife.
-
-Finally, we have ``Pistol_Point``. This is the point where we will be creating/instancing
-our bullet objects. We do not need any additional nodes here, as the bullet handles all
-of its own collision detection.
-
-Now that we've seen how we will handle our other weapons, and where we will spawn the bullets,
-let's start working on making them work.
-
-.. note:: You can also look at the HUD nodes if you want. There is nothing fancy there and other
-         than using a single :ref:`Label <class_Label>`, we will not be touching any of those nodes.
-         Check :ref:`doc_design_interfaces_with_the_control_nodes` for a tutorial on using GUI nodes.
-
-
-Creating the first weapon
--------------------------
-
-Lets write the code for each of our weapons, starting with the pistol.
-
-Select ``Pistol_Point`` (``Player`` -> ``Rotation_Helper`` -> ``Gun_Fire_Points`` -> ``Pistol_Point``) and create a new script called ``Weapon_Pistol.gd``.
-
-Add the following code to ``Weapon_Pistol.gd``:
-
-::
-
-    extends Spatial
-
-    const DAMAGE = 15
-
-    const IDLE_ANIM_NAME = "Pistol_idle"
-    const FIRE_ANIM_NAME = "Pistol_fire"
-
-    var is_weapon_enabled = false
-
-    var bullet_scene = preload("Bullet_Scene.tscn")
-
-    var player_node = null
-
-    func _ready():
-        pass
-
-    func fire_weapon():
-        var clone = bullet_scene.instance()
-        var scene_root = get_tree().root.get_children()[0]
-        scene_root.add_child(clone)
-
-        clone.global_transform = self.global_transform
-        clone.scale = Vector3(4, 4, 4)
-        clone.BULLET_DAMAGE = DAMAGE
-
-    func equip_weapon():
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            is_weapon_enabled = true
-            return true
-
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            player_node.animation_manager.set_animation("Pistol_equip")
-
-        return false
-
-    func unequip_weapon():
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            if player_node.animation_manager.current_state != "Pistol_unequip":
-                player_node.animation_manager.set_animation("Pistol_unequip")
-
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            is_weapon_enabled = false
-            return true
-        else:
-            return false
-
-
-Let's go over how the script works.
-
-_________
-
-First we define some class variables we'll need in the script:
-
-* ``DAMAGE``: The amount of damage a single bullet does.
-* ``IDLE_ANIM_NAME``: The name of the pistol's idle animation.
-* ``FIRE_ANIM_NAME``: The name of the pistol's fire animation.
-* ``is_weapon_enabled``: A variable for checking whether this weapon is in use/enabled.
-* ``bullet_scene``: The bullet scene we worked on earlier.
-* ``player_node``: A variable to hold ``Player.gd``.
-
-The reason we define most of these variables is so we can use them in ``Player.gd``.
-
-Each of the weapons we'll make will have all these variables (minus ``bullet_scene``) so we have
-a consistent interface to interact with in ``Player.gd``. By using the same variables/functions in each
-weapon, we can interact with them without having to know which weapon we are using, which makes our code
-much more modular because we can add weapons without having to change much of the code in ``Player.gd`` and it will just work.
-
-We could write all the code in ``Player.gd``, but then ``Player.gd`` will get increasingly harder to manage as we add weapons.
-By using a modular design with a consistent interface, we can keep ``Player.gd`` nice and neat, while also making it easier to add/remove/modify weapons.
-
-_________
-
-In ``_ready`` we simply pass over it.
-
-There is one thing of note though, an assumption that we'll fill in ``Player.gd`` at some point.
-
-We are going to assume that ``Player.gd`` will pass themselves in before calling any of the functions in ``Weapon_Pistol.gd``.
-
-While this can lead to situations where the player does not pass themselves in (because we forget), we would have to have a long string
-of ``get_parent`` calls to traverse up the scene tree to retrieve the player. This does not look pretty (``get_parent().get_parent().get_parent()`` and so on)
-and it is relatively safe to assume we will remember to pass ourselves to each weapon in ``Player.gd``.
-
-_________
-
-Next let's look at ``fire_weapon``:
-
-The first thing we do is instance the bullet scene we made earlier.
-
-.. tip:: By instancing the scene, we are creating a new node holding all the node(s) in the scene we instanced, effectively cloning that scene.
-
-Then we add a ``clone`` to the first child node of the root of the scene we are currently in. By doing this, we're making it a child of the root node of the currently loaded scene.
-
-In other words, we are adding a ``clone`` as a child of the first node (whatever is at the top of the scene tree) in the currently loaded/opened scene.
-If the currently loaded/open scene is ``Testing_Area.tscn``, we'd be adding our ``clone`` as a child of ``Testing_Area``, the root node in that scene.
-
-.. warning:: As mentioned later below in the section on adding sounds, this method makes an assumption. This will be explained later
-             in the section on adding sounds in :ref:`doc_fps_tutorial_part_three`
-
-Next we set the global transform of the clone to the ``Pistol_Point``'s global transform. The reason we do this is so the bullet is spawned at the end of the pistol.
-
-You can see that ``Pistol_Point`` is positioned right at the end of the pistol by clicking the :ref:`AnimationPlayer <class_AnimationPlayer>` and
-scrolling through ``Pistol_fire``. You'll find the position is more or less at the end of the pistol when it fires.
-
-Next we scale it up by a factor of ``4`` because the bullet scene is a little too small by default.
-
-Then we set the bullet's damage (``BULLET_DAMAGE``) to the amount of damage a single pistol bullet does (``DAMAGE``).
-
-_________
-
-Now let's look at ``equip_weapon``:
-
-The first thing we do is check to see whether the animation manager is in the pistol's idle animation.
-If we are in the pistol's idle animation, we set ``is_weapon_enabled`` to ``true`` and return ``true`` because the pistol has successfully
-been equipped.
-
-Because we know our pistol's ``equip`` animation automatically transitions to the pistol's idle animation, if we are in the pistol's
-idle animation the pistol must have finished playing the equip animation.
-
-.. note:: We know these animations will transition because we wrote the code to make them transition in ``Animation_Manager.gd``
-
-Next we check to see if the player is in the ``Idle_unarmed`` animation state. Because all unequipping animations go to this state, and because any
-weapon can be equipped from this state, we change animations to ``Pistol_equip`` if the player is in the ``Idle_unarmed`` state.
-
-Since we know ``Pistol_equip`` will transition to ``Pistol_idle``, we do not need to do any more additional processing for equipping weapons,
-but since we were not able to equip the pistol yet, we return ``false``.
-
-_________
-
-Finally, let's look at ``unequip_weapon``:
-
-``unequip_weapon`` is similar to ``equip_weapon``, but instead we're checking things in reverse.
-
-First we check to see whether the player is in the idle animation state. Then we check to make sure the player is not in the ``Pistol_unequip`` animation.
-If the player is not in the ``Pistol_unequip`` animation, we want to play the ``pistol_unequip`` animation.
-
-.. note:: You may be wondering why we are checking to see whether the player is in the pistol's idle animation, and then making sure the player is not unequipping right after.
-          The reason behind the additional check is because we could (in rare cases) call ``unequip_weapon`` twice before we've had a chance to process ``set_animation``,
-          so we add this additional check to make sure the unequip animation plays.
-
-Next we check to see whether the player is in ``Idle_unarmed``, which is the animation state we will transition into from ``Pistol_unequip``. If the player is in ``Idle_unarmed``, then we set
-``is_weapon_enabled`` to ``false`` since we are no longer using this weapon, and return ``true`` because we have successfully unequipped the pistol.
-
-If the player is not in ``Idle_unarmed``, we return ``false`` because we have not yet successfully unequipped the pistol.
-
-Creating the other two weapons
-------------------------------
-
-Now that we have all the code we'll need for the pistol, let's add the code for the rifle and knife next.
-
-Select ``Rifle_Point`` (``Player`` -> ``Rotation_Helper`` -> ``Gun_Fire_Points`` -> ``Rifle_Point``) and create a new script called ``Weapon_Rifle.gd``,
-then add the following:
-
-::
-
-    extends Spatial
-
-    const DAMAGE = 4
-
-    const IDLE_ANIM_NAME = "Rifle_idle"
-    const FIRE_ANIM_NAME = "Rifle_fire"
-
-    var is_weapon_enabled = false
-
-    var player_node = null
-
-    func _ready():
-        pass
-
-    func fire_weapon():
-        var ray = $Ray_Cast
-        ray.force_raycast_update()
-
-        if ray.is_colliding():
-            var body = ray.get_collider()
-
-            if body == player_node:
-                pass
-            elif body.has_method("bullet_hit"):
-                body.bullet_hit(DAMAGE, ray.global_transform)
-
-    func equip_weapon():
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            is_weapon_enabled = true
-            return true
-
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            player_node.animation_manager.set_animation("Rifle_equip")
-
-        return false
-
-    func unequip_weapon():
-
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            if player_node.animation_manager.current_state != "Rifle_unequip":
-                player_node.animation_manager.set_animation("Rifle_unequip")
-
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            is_weapon_enabled = false
-            return true
-
-        return false
-
-Most of this is exactly the same as ``Weapon_Pistol.gd``, so we're only going to look at what's changed: ``fire_weapon``.
-
-The first thing we do is get the :ref:`Raycast <class_Raycast>` node, which is a child of ``Rifle_Point``.
-
-Next we force the :ref:`Raycast <class_Raycast>` to update using ``force_raycast_update``. This will force the :ref:`Raycast <class_Raycast>` to detect collisions when we call it, meaning
-we get a frame perfect collision check with the 3D physics world.
-
-Then we check to see if the :ref:`Raycast <class_Raycast>` collided with something.
-
-If the :ref:`Raycast <class_Raycast>` has collided with something, we first get the collision body it collided with. This can be a :ref:`StaticBody <class_StaticBody>`,
-:ref:`RigidBody <class_RigidBody>`, or a :ref:`KinematicBody <class_KinematicBody>`.
-
-Next we want to make sure the body we've collided with is not the player, since we (probably) do not want to give the player the ability to shoot themselves in the foot.
-
-If the body is not the player, we then check to see if it has a function/method called ``bullet_hit``. If it does, we call it and pass in the amount of
-damage this bullet does (``DAMAGE``), and the global transform of the :ref:`Raycast <class_Raycast>` so we can tell from which direction the bullet came.
-
-_________
-
-Now all we need to do is write the code for the knife.
-
-Select ``Knife_Point`` (``Player`` -> ``Rotation_Helper`` -> ``Gun_Fire_Points`` -> ``Knife_Point``) and create a new script called ``Weapon_Knife.gd``,
-then add the following:
-
-::
-
-    extends Spatial
-
-    const DAMAGE = 40
-
-    const IDLE_ANIM_NAME = "Knife_idle"
-    const FIRE_ANIM_NAME = "Knife_fire"
-
-    var is_weapon_enabled = false
-
-    var player_node = null
-
-    func _ready():
-        pass
-
-    func fire_weapon():
-        var area = $Area
-        var bodies = area.get_overlapping_bodies()
-
-        for body in bodies:
-            if body == player_node:
-                continue
-
-            if body.has_method("bullet_hit"):
-                body.bullet_hit(DAMAGE, area.global_transform)
-
-    func equip_weapon():
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            is_weapon_enabled = true
-            return true
-
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            player_node.animation_manager.set_animation("Knife_equip")
-
-        return false
-
-    func unequip_weapon():
-
-        if player_node.animation_manager.current_state == IDLE_ANIM_NAME:
-            player_node.animation_manager.set_animation("Knife_unequip")
-
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            is_weapon_enabled = false
-            return true
-
-        return false
-
-As with ``Weapon_Rifle.gd``, the only differences are in ``fire_weapon``, so let's look at that:
-
-The first thing we do is get the :ref:`Area <class_Area>` child node of ``Knife_Point``.
-
-Next we want to get all the collision bodies inside the :ref:`Area <class_Area>` using ``get_overlapping_bodies``. This will return a
-list of every body that touches the :ref:`Area <class_Area>`.
-
-We next want to go through each of those bodies.
-
-First we check to make sure the body is not the player, because we do not want to let the player be able to stab themselves. If the body is the player,
-we use ``continue`` so we jump and look at the next body in ``bodies``.
-
-If we have not jumped to the next body, we then check to see if the body has the ``bullet_hit`` function/method. If it does,
-we call it, passing in the amount of damage a single knife swipe does (``DAMAGE``) and the global transform of the :ref:`Area <class_Area>`.
-
-.. note:: While we could attempt to calculate a rough location for where the knife hit exactly, we
-          are not going to because using the :ref:`Area <class_Area>`'s position works well enough and the extra time
-          needed to calculate a rough position for each body is not worth the effort.
-
-Making the weapons work
------------------------
-
-Let's start making the weapons work in ``Player.gd``.
-
-First let's start by adding some class variables we'll need for the weapons:
-
-::
-
-    # Place before _ready
-    var animation_manager
-
-    var current_weapon_name = "UNARMED"
-    var weapons = {"UNARMED":null, "KNIFE":null, "PISTOL":null, "RIFLE":null}
-    const WEAPON_NUMBER_TO_NAME = {0:"UNARMED", 1:"KNIFE", 2:"PISTOL", 3:"RIFLE"}
-    const WEAPON_NAME_TO_NUMBER = {"UNARMED":0, "KNIFE":1, "PISTOL":2, "RIFLE":3}
-    var changing_weapon = false
-    var changing_weapon_name = "UNARMED"
-
-    var health = 100
-
-    var UI_status_label
-
-Let's go over what these new variables will do:
-
-- ``animation_manager``: This will hold the :ref:`AnimationPlayer <class_AnimationPlayer>` node and its script, which we wrote previously.
-- ``current_weapon_name``: The name of the weapon we are currently using. It has four possible values: ``UNARMED``, ``KNIFE``, ``PISTOL``, and ``RIFLE``.
-- ``weapons``: A dictionary that will hold all the weapon nodes.
-- ``WEAPON_NUMBER_TO_NAME``: A dictionary allowing us to convert from a weapon's number to its name. We'll use this for changing weapons.
-- ``WEAPON_NAME_TO_NUMBER``: A dictionary allowing us to convert from a weapon's name to its number. We'll use this for changing weapons.
-- ``changing_weapon``: A boolean to track whether or not we are changing guns/weapons.
-- ``changing_weapon_name``: The name of the weapon we want to change to.
-- ``health``: How much health our player has. In this part of the tutorial we will not be using it.
-- ``UI_status_label``: A label to show how much health we have, and how much ammo we have both in our gun and in reserve.
-
-_________
-
-Next we need to add a few things in ``_ready``. Here's the new ``_ready`` function:
-
-::
-
-    func _ready():
-        camera = $Rotation_Helper/Camera
-        rotation_helper = $Rotation_Helper
-
-        animation_manager = $Rotation_Helper/Model/Animation_Player
-        animation_manager.callback_function = funcref(self, "fire_bullet")
-
-        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-
-        weapons["KNIFE"] = $Rotation_Helper/Gun_Fire_Points/Knife_Point
-        weapons["PISTOL"] = $Rotation_Helper/Gun_Fire_Points/Pistol_Point
-        weapons["RIFLE"] = $Rotation_Helper/Gun_Fire_Points/Rifle_Point
-
-        var gun_aim_point_pos = $Rotation_Helper/Gun_Aim_Point.global_transform.origin
-
-        for weapon in weapons:
-            var weapon_node = weapons[weapon]
-            if weapon_node != null:
-                weapon_node.player_node = self
-                weapon_node.look_at(gun_aim_point_pos, Vector3(0, 1, 0))
-                weapon_node.rotate_object_local(Vector3(0, 1, 0), deg2rad(180))
-
-        current_weapon_name = "UNARMED"
-        changing_weapon_name = "UNARMED"
-
-        UI_status_label = $HUD/Panel/Gun_label
-        flashlight = $Rotation_Helper/Flashlight
-
-Let's go over what's changed.
-
-First we get the :ref:`AnimationPlayer <class_AnimationPlayer>` node and assign it to the ``animation_manager`` variable. Then we set the callback function
-to a :ref:`FuncRef <class_FuncRef>` that will call the player's ``fire_bullet`` function. Right now we haven't written the ``fire_bullet`` function,
-but we'll get there soon.
-
-Next we get all the weapon nodes and assign them to ``weapons``. This will allow us to access the weapon nodes only with their name
-(``KNIFE``, ``PISTOL``, or ``RIFLE``).
-
-We then get ``Gun_Aim_Point``'s global position so we can rotate the player's weapons to aim at it.
-
-Then we go through each weapon in ``weapons``.
-
-We first get the weapon node. If the weapon node is not ``null``, we then set its ``player_node`` variable to this script (``Player.gd``).
-Then we have it look at ``gun_aim_point_pos`` using the ``look_at`` function, and then rotate it by ``180`` degrees on the ``Y`` axis.
-
-.. note:: We rotate all of those weapon points by ``180`` degrees on their ``Y`` axis because our camera is pointing backwards.
-          If we did not rotate all of these weapon points by ``180`` degrees, all of the weapons would fire backwards.
-
-Then we set ``current_weapon_name`` and ``changing_weapon_name`` to ``UNARMED``.
-
-Finally, we get the UI :ref:`Label <class_Label>` from our HUD.
-
-_________
-
-Let's add a new function call to ``_physics_process`` so we can change weapons. Here's the new code:
-
-::
-
-    func _physics_process(delta):
-        process_input(delta)
-        process_movement(delta)
-        process_changing_weapons(delta)
-
-
-Now we will call ``process_changing_weapons``.
-
-_________
-
-Now let's add all the player input code for the weapons in ``process_input``. Add the following code:
-
-::
-
-    # ----------------------------------
-    # Changing weapons.
-    var weapon_change_number = WEAPON_NAME_TO_NUMBER[current_weapon_name]
-
-    if Input.is_key_pressed(KEY_1):
-        weapon_change_number = 0
-    if Input.is_key_pressed(KEY_2):
-        weapon_change_number = 1
-    if Input.is_key_pressed(KEY_3):
-        weapon_change_number = 2
-    if Input.is_key_pressed(KEY_4):
-        weapon_change_number = 3
-
-    if Input.is_action_just_pressed("shift_weapon_positive"):
-        weapon_change_number += 1
-    if Input.is_action_just_pressed("shift_weapon_negative"):
-        weapon_change_number -= 1
-
-    weapon_change_number = clamp(weapon_change_number, 0, WEAPON_NUMBER_TO_NAME.size() - 1)
-
-    if changing_weapon == false:
-        if WEAPON_NUMBER_TO_NAME[weapon_change_number] != current_weapon_name:
-            changing_weapon_name = WEAPON_NUMBER_TO_NAME[weapon_change_number]
-            changing_weapon = true
-    # ----------------------------------
-
-    # ----------------------------------
-    # Firing the weapons
-    if Input.is_action_pressed("fire"):
-        if changing_weapon == false:
-            var current_weapon = weapons[current_weapon_name]
-            if current_weapon != null:
-                if animation_manager.current_state == current_weapon.IDLE_ANIM_NAME:
-                    animation_manager.set_animation(current_weapon.FIRE_ANIM_NAME)
-    # ----------------------------------
-
-Let's go over the additions, starting with how we're changing weapons.
-
-First we get the current weapon's number and assign it to ``weapon_change_number``.
-
-Then we check to see if any of the number keys (keys 1-4) are pressed. If they are, we set
-``weapon_change_number`` to the value mapped at that key.
-
-.. note:: The reason key 1 is mapped to ``0`` is because the first element in a list is mapped to zero, not one. Most list/array accessors
-          in most programming languages start at ``0`` instead of ``1``. See https://en.wikipedia.org/wiki/Zero-based_numbering for more information.
-
-Next we check to see if ``shift_weapon_positive`` or ``shift_weapon_negative`` is pressed. If one of them is, we add/subtract ``1`` from
-``weapon_change_number``.
-
-Because the player may have shifted ``weapon_change_number`` outside of the number of weapons the player has, we clamp it so it cannot exceed the maximum number of weapons
-the player has and it ensures ``weapon_change_number`` is ``0`` or more.
-
-Then we check to make sure the player is not already changing weapons. If the player is not, we then check to see if the weapon the player wants to change to
-is a new weapon and not the weapon the player is currently using. If the weapon the player is wanting to change to is a new weapon, we then set ``changing_weapon_name`` to
-the weapon at ``weapon_change_number`` and set ``changing_weapon`` to ``true``.
-
-For firing the weapon we first check to see if the ``fire`` action is pressed.
-Then we check to make sure the player is not changing weapons.
-Next we get the weapon node for the current weapon.
-
-If the current weapon node does not equal ``null``, and the player is in its ``IDLE_ANIM_NAME`` state, we set the player's animation
-to the current weapon's ``FIRE_ANIM_NAME``.
-
-_________
-
-Let's add ``process_changing_weapons`` next.
-
-Add the following code:
-
-::
-
-    func process_changing_weapons(delta):
-        if changing_weapon == true:
-
-            var weapon_unequipped = false
-            var current_weapon = weapons[current_weapon_name]
-
-            if current_weapon == null:
-                weapon_unequipped = true
-            else:
-                if current_weapon.is_weapon_enabled == true:
-                    weapon_unequipped = current_weapon.unequip_weapon()
-                else:
-                    weapon_unequipped = true
-
-            if weapon_unequipped == true:
-
-                var weapon_equipped = false
-                var weapon_to_equip = weapons[changing_weapon_name]
-
-                if weapon_to_equip == null:
-                    weapon_equipped = true
-                else:
-                    if weapon_to_equip.is_weapon_enabled == false:
-                        weapon_equipped = weapon_to_equip.equip_weapon()
-                    else:
-                        weapon_equipped = true
-
-                if weapon_equipped == true:
-                    changing_weapon = false
-                    current_weapon_name = changing_weapon_name
-                    changing_weapon_name = ""
-
-Let's go over what's happening here:
-
-The first thing we do is make sure we've received input to change weapons. We do this by making sure ``changing_weapon`` is ``true``.
-
-Next we define a variable (``weapon_unequipped``) so we can check whether the current weapon has been successfully unequipped or not.
-
-Then we get the current weapon from ``weapons``.
-
-If the current weapon is not ``null``, then we need to check whether the weapon is enabled. If the weapon is enabled, we call its ``unequip_weapon`` function
-so it will start the unequip animation. If the weapon is not enabled, we set ``weapon_unequipped`` to ``true`` because the weapon has successfully been unequipped.
-
-If the current weapon is ``null``, then we can simply set ``weapon_unequipped`` to ``true``. The reason we do this check is because there is no weapon script/node for
-``UNARMED``, but there is also no animations for ``UNARMED``, so we can just start equipping the weapon the player wants to change to.
-
-If the player has successfully unequipped the current weapon (``weapon_unequipped == true``), we need to equip the new weapon.
-
-First we define a new variable (``weapon_equipped``) for tracking whether the player has successfully equipped the new weapon or not.
-
-Then we get the weapon the player wants to change to. If the weapon the player wants to change to is not ``null``, we then check to see whether it's enabled or not.
-If it is not enabled, we call its ``equip_weapon`` function so it starts to equip the weapon. If the weapon is enabled, we set ``weapon_equipped`` to ``true``.
-
-If the weapon the player wants to change to is ``null``, we simply set ``weapon_equipped`` to ``true`` because we do not have any node/script for ``UNARMED``,
-nor do we have any animations.
-
-Finally, we check to see whether the player has successfully equipped the new weapon. If (s)he has done so, we set ``changing_weapon`` to ``false`` because the player is no
-longer changing weapons.
-We also set ``current_weapon_name`` to ``changing_weapon_name`` since the current weapon has changed, and then we set ``changing_weapon_name`` to an empty string.
-
-_________
-
-Now, we need to add one more function to the player, and then the player is ready to start firing the weapons!
-
-We need to add ``fire_bullet``, which will be called by the :ref:`AnimationPlayer <class_AnimationPlayer>` at those
-points we set earlier in the :ref:`AnimationPlayer <class_AnimationPlayer>` function track:
-
-::
-
-    func fire_bullet():
-        if changing_weapon == true:
-            return
-
-        weapons[current_weapon_name].fire_weapon()
-
-
-Let's go over what this function does:
-
-First we check to see whether the player is changing weapons. If the player is changing weapons, we do not want shoot, so we ``return``.
-
-.. tip:: Calling ``return`` stops the rest of the function from being called. In this case, we are not returning a variable
-         because we are only interested in not running the rest of the code, and because we are not looking for a returned
-         variable either when we call this function.
-
-Then we tell the current weapon the player is using to fire by calling its ``fire_weapon`` function.
-
-.. tip:: Remember how we mentioned the speed of the animations for firing was faster than
-         the other animations? By changing the firing animation speeds, you can change how
-         fast the weapon fires bullets!
-
-_______
-
-Before we are ready to test our new weapons, we still have a bit of work to do.
-
-Creating some test subjects
----------------------------
-
-Create a new script by going to the scripting window, clicking "file", and selecting new.
-Name this script ``RigidBody_hit_test`` and make sure it extends :ref:`RigidBody <class_RigidBody>`.
-
-Now we need to add this code:
-
-::
-
-    extends RigidBody
-
-    const BASE_BULLET_BOOST = 9
-
-    func _ready():
-        pass
-
-    func bullet_hit(damage, bullet_global_trans):
-        var direction_vect = bullet_global_trans.basis.z.normalized() * BASE_BULLET_BOOST
-
-        apply_impulse((bullet_global_trans.origin - global_transform.origin).normalized(), direction_vect * damage)
-
-
-Let's go over how ``bullet_hit`` works:
-
-
-First we get the bullet's forward directional vector. This is so we can tell from which direction the bullet will hit the :ref:`RigidBody <class_RigidBody>`.
-We will use this to push the :ref:`RigidBody <class_RigidBody>` in the same direction as the bullet.
-
-.. note:: We need to boost the directional vector by ``BASE_BULLET_BOOST`` so the bullets pack a bit more of a punch
-          and move the :ref:`RigidBody <class_RigidBody>` nodes in a visible way. You can just set ``BASE_BULLET_BOOST`` to lower or higher values if you want
-          less or more of a reaction when the bullets collide with the :ref:`RigidBody <class_RigidBody>`.
-
-Then we apply an impulse using ``apply_impulse``.
-
-First, we need to calculate the position for the impulse.
-Because ``apply_impulse`` takes a vector relative to the :ref:`RigidBody <class_RigidBody>`, we need to calculate the distance from
-the :ref:`RigidBody <class_RigidBody>` to the bullet. We do this by subtracting the :ref:`RigidBody <class_RigidBody>`'s global origin/position from the bullet's global origin/position.
-This gets us the distance from the :ref:`RigidBody <class_RigidBody>` to the bullet. We normalize this vector so the size of the collider does not effect how much
-the bullets move the :ref:`RigidBody <class_RigidBody>`.
-
-Finally, we need to calculate the force for the impulse. For this, we use the direction the bullet is facing and multiply it by the bullet's damage.
-This gives a nice result and for stronger bullets, we get a stronger result.
-
-_______
-
-Now we need to attach this script to all of the :ref:`RigidBody <class_RigidBody>` nodes we want to affect.
-
-Open up ``Testing_Area.tscn`` and select all the cubes parented to the ``Cubes`` node.
-
-.. tip:: If you select the top cube, and then hold down :kbd:`Shift` and select the last cube, Godot will
-         select all the cubes in-between!
-
-Once you have all the cubes selected, scroll down in the inspector until you get to
-the "scripts" section. Click the drop down and select "Load". Open your newly created ``RigidBody_hit_test.gd`` script.
-
-Final notes
------------
-
-.. image:: img/PartTwoFinished.png
-
-That was a lot of code! But now, with all that done, you can go and give your weapons a test!
-
-You should now be able to fire as many bullets as you want at the cubes and
-they will move in response to the bullets colliding with them.
-
-In :ref:`doc_fps_tutorial_part_three`, we will add ammo to the weapons, as well as some sounds!
-
-.. warning:: If you ever get lost, be sure to read over the code again!
-
-             You can download the finished project for this part here: :download:`Godot_FPS_Part_2.zip <files/Godot_FPS_Part_2.zip>`