Forráskód Böngészése

FPS tutorial remaster (#1357)

* Started remastering first two parts of the FPS tutorial.

Now both parts follow a consistant coding style,
have up to date Zip files for every part.

* Finished the first draft for part 2, and did some edits to part 1.

* Finished writing the first draft for part 3. (Still needs editing)

I also added a blank page for part 5 and added it to the index.

* Updated and fixed a few things in Part 3

* Removed the old part 4 of the FPS tutorial and replaced it with a new part!
(Which would have been part 5 had part 4 not been removed)

* Added part 5 of the FPS tutorial.
Made a few changes to parts 4 and 1.
Added a template/overview of what to write in part 6.

* Finished part 6 of the FPS tutorial.
Now every part of the FPS tutorial is written out!

Made some minor edits to part 5.

* Added all of the zip files for the first three parts of the FPS tutorial.
Updated/Redid all of the pictures for the first three parts as well.
Fixed a few minor issues/inconsistencies in the written material.

* Added all of the zip files for the last three parts of the FPS tutorial.
Updated/Redid all of the pictures for the last three parts as well.
Fixed a few minor issues/inconsistencies in the written material.
Updated the blender files zip.

* Did some editing on parts 3 through 5 on the FPS tutorial.
TwistedTwigleg 7 éve
szülő
commit
e7e7e3c8ed

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/AutoloadAddSingleton.png


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


BIN
tutorials/3d/fps_tutorial/img/GithubDownloadZip.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


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

@@ -9,3 +9,5 @@ FPS tutorial
    part_two
    part_three
    part_four
+   part_five
+   part_six

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

@@ -0,0 +1,958 @@
+.. _doc_fps_tutorial_part_five:
+
+Part 5
+======
+
+Part Overview
+-------------
+
+In this part we're going to add grenades to our player, give our 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
+---------------
+
+First, let's give our player some grenades to play with. Open up ``Grenade.tscn``.
+
+There's a few things to note here, the first and foremost being that our 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 a :ref:`Area <class_Area>` node that will represent the blast radius of our 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 grenades explodes. One thing to note here is that we have ``One shot`` enabled. This is so we emit all of our particles at once. We're also emitting in 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 it's ``Process Material`` and ``Draw Passes``.
+
+Let's write the code needed for our 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, global_transform.origin)
+                
+                # 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 global 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 play 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 the length of time
+the 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 of the nodes we'll need and assign them to the proper global 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 it explodes. We'll be using code similar to the knife
+weapon in our player. We need the :ref:`Particles <class_Particles>` so we can emit them when we explode.
+
+After we get all of the nodes and assign them to their global variables, we then make sure the explosion particles are not emitting, and that they are set to
+emit in one shot.
+
+______
+
+Now let's look at ``_process``.
+
+First we check to see if the ``grenade_timer`` is less than ``GRENADE_TIMER``. If it is, we add ``delta`` and return. This is so we have to wait ``GRENADE_TIME`` seconds,
+allowing our :ref:`RigidBody <class_RigidBody>` to move around.
+
+If ``grenade_timer`` is at ``GRENADE_TIMER`` or higher, we then need to check if we just waited long enough and need 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 we've waited long enough and need to explode.
+
+If we've 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 our grenade.
+
+We then set the :ref:`RigidBody <class_RigidBody>`'s mode to ``MODE_STATIC`` so the grenade does not move.
+
+Then we get all of 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 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_time``.
+
+Next we check to see if ``explosion_wait_timer`` is more than or equal to ``EXPLOSTION_WAIT_TIME``. Because we just added ``delta``, this will only be called once.
+If ``explosion_wait_timer`` is more or equal to ``EXPLOSION_WAIT_TIME``, we've waited long enough to let the :ref:`Particles <class_Particles>` play and can free/destroy ourselves.
+
+______
+
+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'll be using ``Stick_Area`` to detect when we've collided with
+the environment and need 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, global_transform.origin)
+                
+                # 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.
+
+First, we have a few more global variables:
+
+* ``attached``: A variable for tracking whether or not we've attached to a :ref:`PhysicsBody <class_PhysicsBody>`.
+* ``attach_point``: A variable to hold a :ref:`Spatial <class_Spatial>` that will be at the position we collided at.
+* ``player_body``: The player's :ref:`KinematicBody <class_KinematicBody>`.
+
+These additions are so we can stick to any :ref:`PhysicsBody <class_PhysicsBody>` we happen to hit. We also now
+need the player's :ref:`KinematicBody <class_KinematicBody>` so we don't stick to the player that threw this grenade.
+
+______
+
+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``.
+
+First we make sure we're not colliding with ourself. Because our :ref:`Area <class_Area>` does not know it's attached to the grenade's :ref:`RigidBody <class_RigidBody>`,
+we need to make sure we're not going to stick to ourself. If we have collided with ourself, we just ignore it by returning.
+
+We then check to see if we have something assigned to ``player_body``, and if the body we collided with is the player that threw this grenade.
+If the body we've collided with is indeed ``player_body``, we just ignore it by returning.
+
+Next we check if we are attached already or not.
+
+If we are not attached, we then set ``attached`` to true so we know we've attached to something.
+
+We then make a new :ref:`Spatial <class_Spatial>` node, and make it a child of the body we collided with. We then set the :ref:`Spatial <class_Spatial>`'s position
+to our current position.
+
+.. note:: Because we've added the :ref:`Spatial <class_Spatial>` as a child of the body we've collided with, it will follow along with said body. We can then use this
+          :ref:`Spatial <class_Spatial>` to set our position, so we're always at the same position relative to the body we collided with.
+
+We then disable ``rigid_shape`` so we're not constantly moving whatever body we've 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 we are attached right at the top of ``_process``.
+
+If we are attached, we then make sure the attached point is not equal to ``null``.
+If the attached point is not equal to ``null``, we set our global position (using our 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 grenade, we check to see if we have an attached point. If we do, we also call ``queue_free`` on it, 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 our grenades.
+
+First, 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 the grenades are tossed at.
+
+Okay, now lets start making the grenades work with our player. Add the following global 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 we are currently carrying for each type of grenade.
+* ``current_grenade``: The name of the grenade type we're 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 we throw the grenade at.
+         
+Most of these variables are very similar to how we have out 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.
+
+First, we check to see if the ``change_grenade`` action has just been pressed. If it has, we then check to see which grenade we
+are currently using. Based on the name of the grenade we're 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 we have more than ``0`` grenades for the
+current grenade we have selected.
+
+If we have more than ``0`` grenades, we then remove one from the grenade amounts for the current grenade.
+Then, based on the grenade we're 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 we can use both types of grenades, but there's a few things we should probably add before we move on to adding the other things.
+
+We still need a way to see how many grenades we have left, and we should probably have a way to get more grenades when we pick up ammo.
+
+First, let's change some of the code in ``Player.gd`` so we can see how many grenades we have 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 we have left in our UI.
+
+While we're still in ``Player.gd``, let's add a function to add grenades. 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 just 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 you can carry, just 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're also checking to see if the body has the ``add_grenade`` function. If it does, we call it just like we call ``add_ammo``.
+
+You may have noticed we're using a new constant we haven't defined yet, ``GRENADE_AMOUNTS``. Let's add it! Add the following global variable
+to ``AmmoPickup.gd`` with the other global variables:
+
+::
+    
+    const GRENADE_AMOUNTS = [2, 0]
+    
+* ``GRENADE_AMOUNTS``: The amount of grenades each pick up in each size contains.
+
+Notice how the second element in ``GRENADE_AMOUNTS`` is ``0``. This is so the small ammo pick up does not give our player
+any additional grenades.
+
+______
+
+Now you should be able to throw grenades now! Go give it a try!
+
+
+Adding the ability to grab and throw RigidBody nodes to the player
+------------------------------------------------------------------
+
+Next let's give our player the ability to pick up and throw :ref:`RigidBody <class_RigidBody>` nodes.
+
+Open up ``Player.gd`` and add the following global 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 we throw the grabbed object at.
+* ``OBJECT_GRAB_DISTANCE``: The distance away from the camera we hold the grabbed object at.
+* ``OBJECT_GRAB_RAY_DISTANCE``: The distance the :ref:`Raycast <class_Raycast>` goes. This is our 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") 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:
+                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.
+
+First we check to see if the action pressed is the ``fire`` action, and that we are using the ``UNARMED`` weapon.
+This is because we only want to be able to pick up and throw objects when we're not using any weapons. This is just 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 our ray into the space state and see if we get a result. We add ourselves and the knife's :ref:`Area <class_Area>` as two exceptions so we cannot carry
+ourselves or the knife's collision area.
+
+Then we check to see if we got a result back. If we have, 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's not moved.
+
+Finally, we set its collision layer and collision mask to ``0``. This will make it have no collision layer or mask, which will means it will not be able to collide with anything.
+
+______
+
+If ``grabbed_object`` is not ``null``, then we need to throw the :ref:`RigidBody <class_RigidBody>` we're holding.
+
+We first set the :ref:`RigidBody <class_RigidBody>` we holding mode to ``MODE_RIGID``.
+
+.. note:: This is making a rather large assumption that the all 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 :ref:`RigidBody <class_RigidBody>`'s with different modes, you may need to store the mode of the :ref:`RigidBody <class_RigidBody>` you
+          have picked up into a global 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, at ``OBJECT_THROW_FORCE`` force.
+
+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 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>` before you change them to ``0``.
+
+Finally, we set ``grabbed_object`` to ``null`` since we have successfully thrown the held object.
+
+______
+
+The last thing we do is check to see whether or not ``grabbed_object`` is equal to ``null``, outside of the grabbing/throwing 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 we are 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 we're holding an object, we really don't
+want 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 we cannot change weapons or reload while holding an object.
+    
+Now you can grab and throw RigidBody nodes while in a ``UNARMED`` state! Go give it a try!
+
+Adding a turret
+---------------
+
+Next, let's make a turret to shoot our player!
+
+Open up ``Turret.tscn``. Expand ``Turret`` if it's not already expanded.
+
+Notice how our turret is broken up into several parts. We have a ``Base``, ``Head``, ``Vision_Area``, and a ``Smoke`` :ref:`Particles <class_Particles>`.
+
+Open up ``Base`` and you'll find it's just a :ref:`StaticBody <class_StaticBody>` and a mesh. Open up ``Head`` and you'll find there's 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 our 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 a :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 writting 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 == false:
+            
+            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
+        
+        else:
+            node_raycast.look_at(current_target.global_transform.origin + PLAYER_HEIGHT, 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
+        
+        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 global variables:
+
+* ``use_raycast``: A 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)
+
+Phew, that's quite a few global variables!
+
+______
+
+Let's go through ``_ready`` next.
+
+First 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 of the nodes and assign them to their respective variables.
+
+Next add some exceptions to the :ref:`Raycast <class_Raycast>` so the turret cannot hurt itself.
+
+Then we make both flash meshes invisible to start, since we're not going to be firing during ``_ready``.
+
+We then get the smoke particles node and assign it to the ``smoke_particles`` node. We also set ``emitting`` to ``false`` to assure it's
+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``.
+
+First we check to see if the turret is active. If the turret is active we want to process the firing code.
+
+Next we check to see if ``flash_timer`` is more 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 to see if we have a target or not. If we have a target, we make the turret head look at it, adding ``PLAYER_HEIGHT`` so we're not
+aiming at the player's feet.
+
+We then check to see if the turret's health is more than zero. If it is, we then check to see if there is ammo in the turret.
+
+If there is ammo in the turret, we then check to see if ``fire_timer`` is more than zero. If ``fire_timer`` is more than zero, we cannot fire and need to
+remove ``delta`` from ``fire_timer``. If ``fire_timer`` is equal to or less than zero, we want to fire a bullet, so we call the ``fire_bullet`` function.
+
+If there is not any ammo in the turret, we check to see if ``ammo_reload_timer`` is more than zero. If ``ammo_reload_timer`` is more than zero,
+we subtract ``delta`` from ``ammo_reload_timer``. If ``ammo_reload_timer`` is equal to or less than zero, we set ``ammo_in_turret`` to ``AMMO_IN_FULL_TURRET`` because
+we've waited long enough to refill the turret.
+
+Next we check to see if the turret's health is less than or equal to ``0``, outside of whether we're active or not. If the turret's health is zero or less, we then
+check to see if ``destroyed_timer`` is more than zero. If destroyed timer is more than zero, we just subtract ``delta`` from ``destroyed_timer``.
+
+If ``destyored_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``.
+
+First we check to see whether we're using a raycast or not.
+
+The code for the 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, assuring we'll hit the target. We then force the raycast to update so we get a frame
+perfect collision check. We then check if the raycast collided with anything. If the raycast has collided with something, we then check
+to see if the collided body has the ``bullet_hit`` function. If it does, we call it and pass in the damage a single raycast bullet does. We then remove
+``1`` from ``ammo_in_turret``.
+
+If we are 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 it's global transform to
+the barrel end, scale it up since it's too small, and set it's damage and speed using the turret's constant global variables. We then remove ``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
+to ``FLASH_TIME`` and ``FIRE_TIME`` respectively. We then check to see if we used the last bullet in the turret. If we have used the last bullet,
+we set ``ammo_reload_timer`` to ``AMMO_RELOAD_TIME``.
+
+______
+
+Let's look at ``body_entered_vision`` next, and thankfully it's rather short.
+
+We first check to see if we currently have a target by checking to see if ``current_target`` is equal to ``null``.
+If we do not have a target, we then check to see if the body that just entered the vision :ref:`Area <class_Area>` is a :ref:`KinematicBody <class_KinematicBody>`
+
+..note:: We're assuming the turret only should fire at :ref:`KinematicBody <class_KinematicBody>` nodes, since that's what our player(s) are using.
+
+If the body that just 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``.
+
+First we check to see if we have a target. If we have a target, we then check to see if the body that has just left our vision area
+is our target.
+
+If the body that just left the area is the current target, we set ``current_target`` to ``null``, set ``is_active`` to ``false``, and reset
+all of the variables related to firing the turret, since we no longer have a target to fire at.
+
+______
+
+Finally, let's look at ``bullet_hit``.
+
+We first remove however much damage we have received from the turret's health.
+
+Then we check to see if we've been destroyed. If we have, we start the smoke particles emitting and set ``destroyed_timer`` to ``DESTROYED_TIME`` so we
+have to wait to repair the turret.
+
+______
+
+Phew, with all of that done and coded we only have one last thing to do before our turrets are 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 ``Body`` 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 ``path_to_turret_root`` leads to. 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`` to it. Once the script is
+attached, assign 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 of our bullets use the ``bullet_hit`` function, we just need to add that to our 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 the player can pick up :ref:`RigidBody <class_RigidBody>` nodes and throw grenades. We now also have turrets to fire at our player.
+
+In :ref:`doc_fps_tutorial_part_six`, 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.
+
+.. 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>`

+ 466 - 1030
tutorials/3d/fps_tutorial/part_four.rst

@@ -6,1295 +6,731 @@ Part 4
 Part Overview
 -------------
 
-In this part we will be refactoring ``Player.gd`` to use a more modular format, add support for joypads, and add the ability to change weapons with the scroll wheel.
+In this part we will be adding health pick ups, ammo pick ups, targets we can destroy, add support for joypads, and add the ability to change weapons with the scroll wheel.
 
-.. image:: img/FinishedTutorialPicture.png
-
-While this part may not be the most interesting, it is very important. Having a clean and modular code base allows us to build
-more complex behaviour in the future.
-
-.. note:: You are assumed to have finished :ref:`part three <doc_fps_tutorial_part_three>` before moving on to this part of the tutorial.
+.. image:: img/PartFourFinished.png
 
-.. tip:: You can find the completed code for part three here: https://github.com/TwistedTwigleg/Godot_FPS_Tutorial/tree/part_3
-         
-         .. image:: img/GithubDownloadZip.png
-         
-         Just click the green "Clone or download" button and choose "Download Zip" to get the finished project for part 3.
+.. 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
+-------------------
 
-A quick note
-------------
-
-Before we dig into refactoring the code, let's quickly talk about *why* we want to refactor the code.
-
-First, what is refactoring? According to wikipedia:
-
-**"Code refactoring is the process of restructuring existing computer code—changing the factoring—without changing its external behaviour."**
-
-Basically, refactoring is taking code we've already written, and rewriting/restructuring it without changing what it does.
-
-Second, why refactor? There are plenty of reasons why you may want to refactor your code base, but for this tutorial there is really only three
-major reasons:
-
-1: By refactoring the code base we can take out certain elements from the various functions in ``player.gd`` and separate them into their own functions/scripts.
-``_physics_process`` benefits greatly from this, because while it does work right now, it is very confusing to navigate.
-
-2: With some careful refactoring, we can take out most of the gun logic from ``Player.gd`` and put them into their own scripts. This is key because it easily allows
-us to make/edit weapons and their behaviours without having to change much in ``Player.gd``.
-
-3: Currently performance in ``Player.gd`` is okay, but with some work we can make it even better! Performance was not a primary concern for the first three parts
-of this tutorial series, and while it still is not a major concern, we ideally want to write code with good performance when possible.
-
-All of these reasons are why we are going to refactor ``Player.gd``.
+.. 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.
 
-What we plan on doing in this part is taking our very linear ``Player.gd`` script and make it more modular and extendible. This will allow us
-to more easily add features later, as well as make it easier to work with in later parts.
+First we need to change a few things in our project's input map. Open up the project settings and select the ``Input Map`` tab.
 
-.. note:: Even though part 4 is dedicated to refactoring ``Player.gd``, it is likely we will need to do more refactoring in later parts as we continue to add features!
+Now we need to add some joypad buttons to our various actions. Click the plus icon and select ``Joy Button``.
 
+.. image:: img/ProjectSettingsAddKey.png
 
-Breaking it down
-----------------
+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:
 
-Current a majority of the code in ``Player.gd`` is located in ``_physics_process``. Right now ``_physics_process`` is a huge function with several works parts.
-With some refactoring, we can break ``_physics_process`` into several smaller functions.
+* 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 Right)``
+* fire_grenade: ``Device 0, Button 1 (PS Circle, XBox B, Nintendo A).``
 
-Ideally we want to make these smaller functions focused on doing a small set of tasks.
-This makes it much easier to know where we need to add code to when we are working on new features.
+.. note:: These are already set up for you if you downloaded the starter assets
 
-Another benefit of using smaller functions is they are generally easier to debug!
+Once you are happy with the input, close the project settings and save.
 
-Breaking down input processing
-______________________________
+______ 
 
-First, lets make a function for handling all of the :ref:`Input <class_Input>` related code.
-This allows us to more clearly see all of our player input.
+Now let's open up ``Player.gd`` and add joypad input.
 
-Create new function called `process_input` and add the following code:
+First, we need to define a few new global variables. Add the following global variables to ``Player.gd``:
 
 ::
     
-    func process_input(delta):
-        # ----------------------------------
-        # Walking
-        
-        dir = Vector3()
-        var cam_xform = camera.get_global_transform()
-        
-        var input_movement_vector = Vector2()
-        
-        # Add keyboard input
-        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()
-        
-        dir += -cam_xform.basis.z.normalized() * input_movement_vector.y
-        dir += cam_xform.basis.x.normalized() * input_movement_vector.x
-        # ----------------------------------
-        
-        # ----------------------------------
-        # Sprinting
-        
-        if Input.is_action_pressed("movement_sprint"):
-            is_spriting = true
-        else:
-            is_spriting = false
-        # ----------------------------------
-        
-        # ----------------------------------
-        # Jumping
-        
-        if is_on_floor():
-            if Input.is_action_just_pressed("movement_jump"):
-                vel.y = JUMP_SPEED
-        # ----------------------------------
-        
-        # ----------------------------------
-        # Changing weapons.
-        
-        if changing_gun == false and reloading_gun == false:
-            if Input.is_key_pressed(KEY_1):
-                current_gun = "UNARMED"
-                changing_gun = true
-            elif Input.is_key_pressed(KEY_2):
-                current_gun = "KNIFE"
-                changing_gun = true
-            elif Input.is_key_pressed(KEY_3):
-                current_gun = "PISTOL"
-                changing_gun = true
-            elif Input.is_key_pressed(KEY_4):
-                current_gun = "RIFLE"
-                changing_gun = true
-        # ----------------------------------
-        
-        # ----------------------------------
-        # Reloading
-        
-        if reloading_gun == false:
-            if Input.is_action_just_pressed("reload"):
-                if current_gun == "PISTOL" or current_gun == "RIFLE":
-                    if animation_manager.current_state != "Pistol_reload" and animation_manager.current_state != "Rifle_reload":
-                        reloading_gun = true
-        # ----------------------------------
-        
-        # ----------------------------------
-        # Firing the weapons
-        
-        if Input.is_action_pressed("fire"):
-            
-            if current_gun == "PISTOL":
-                if ammo_in_guns["PISTOL"] > 0:
-                    if animation_manager.current_state == "Pistol_idle":
-                        animation_manager.set_animation("Pistol_fire")
-                else:
-                    reloading_gun = true
-            
-            elif current_gun == "RIFLE":
-                if ammo_in_guns["RIFLE"] > 0:
-                    if animation_manager.current_state == "Rifle_idle":
-                        animation_manager.set_animation("Rifle_fire")
-                else:
-                    reloading_gun = true
-            
-            elif current_gun == "KNIFE":
-                if animation_manager.current_state == "Knife_idle":
-                    animation_manager.set_animation("Knife_fire")
-        # ----------------------------------
-        
-        # ----------------------------------
-        # Turning the flashlight on/off
-        
-        if Input.is_action_just_pressed("flashlight"):
-            if flashlight.is_visible_in_tree():
-                flashlight.hide()
-            else:
-                flashlight.show()
-        # ----------------------------------
-        
-        # ----------------------------------
-        
-        # 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)
-        # ----------------------------------
-
-You may have noticed that all of the code so far is exactly the same as the :ref:`Input <class_Input>` relate code already written in ``_physics_process``,
-but is now all placed in one function.
-
-There are a few changes though:
-
-Because we are now calling our input code outside of ``_physics_process`` we need to change ``dir`` from a local variable to a global variable.
-Add ``var dir = Vector3()`` with the rest of the global variables, ideally nearby the movement code for organization.
-
-.. warning:: Do not forget to change ``dir`` to a global variable!
+    # You may need to adjust depending on the sensitivity of your joypad
+    var JOYPAD_SENSITIVITY = 2
+    const JOYPAD_DEADZONE = 0.15
 
-Another change is we're not directly effecting ``dir`` any more. Before we were changing ``dir`` when a movement action was pressed. Now we are changing a new local variable,
-``input_movement_vector``, instead. This will later allow us to have more than one form of directional input. By multiplying ``input_movement_vector`` by the camera's
-directional vectors, we get the same result as when we were effecting ``dir`` directly.
+Let's go over what each of these do:
 
-Notice how we are normalizing ``input_movement_vector`` as well. This is important because later when we add additional forms of directional input, we do not
-want to move faster if two forms of input are moving at the same time. For example, we do not want to move faster if we are pressing the ``UP`` key on the keyboard and also
-are pushing forward on a controller. If we did not normalize, then we'd move twice as fast! By normalizing, we make everyone move at the same speed, regardless of how many
-input devices they are using.
+* ``JOYPAD_SENSITIVITY``: This is how fast our joypad joysticks will move our camera.
+* ``JOYPAD_DEADZONE``: The dead zone for the joypad. You may need to adjust depending on your joypad.
 
-Breaking down ``KinematicBody`` movement
-________________________________________
+.. note::  Many joypads jitter around a certain point. To counter this, we ignore any movement in a
+           with a radius of JOYPAD_DEADZONE. If we did not ignore said movement, the camera will jitter.
+           
+           Also, we are defining ``JOYPAD_SENSITIVITY`` as a variable instead of a constant because we'll later be changing it.
 
-Next we want to move all of the code relating to moving using the :ref:`KinematicBody <class_KinematicBody>` into its own function.
-This allows us to more clearly see what code we are sending :ref:`KinematicBody <class_KinematicBody>` and what it does.
+Now we are ready to start handling joypad input!           
 
-Create a new function and call it ``process_movement``. Lets add the following code:
+______
+           
+In ``process_input`` add the following code, just before ``input_movement_vector = input_movement_vector.normalized()``:
 
 ::
     
-    func process_movement(delta):
-        var grav = norm_grav
-        
-        dir.y = 0
-        dir = dir.normalized()
-        
-        vel.y += delta*grav
-        
-        var hvel = vel
-        hvel.y = 0
+    # Add joypad input, if there is a joypad
+    if Input.get_connected_joypads().size() > 0:
         
-        var target = dir
-        if is_spriting:
-            target *= MAX_SPRINT_SPEED
-        else:
-            target *= MAX_SPEED
+        var joypad_vec = Vector2(0, 0)
         
-        var accel
-        if dir.dot(hvel) > 0:
-            if is_spriting:
-                accel = SPRINT_ACCEL
-            else:
-                accel = ACCEL
+        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:
-            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))
+            joypad_vec = joypad_vec.normalized() * ((joypad_vec.length() - JOYPAD_DEADZONE) / (1 - JOYPAD_DEADZONE))
 
-Thankfully nothing is has changed here, all we've done is moved the code out of ``_physics_process``.
+        input_movement_vector += joypad_vec
 
-.. warning:: If you are using Godot ``master`` branch (or Godot 3.1), you will need to change ``vel = move_and_slide(vel,Vector3(0,1,0), 0.05, 4, deg2rad(MAX_SLOPE_ANGLE))``
-             to ``vel = move_and_slide(vel,Vector3(0,1,0), true, 0.05, 4, deg2rad(MAX_SLOPE_ANGLE))``.
+Let's go over what we're doing.
 
-Now when we are ready to have the :ref:`KinematicBody <class_KinematicBody>` process our movement and send us through space, all we need to do is call ``process_movement``.
+First 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 use different axes based on
+the OS.
 
-Changing the weapon code structure
-----------------------------------
+.. warning:: This tutorial assumes you are using a XBox 360 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!
 
-So far, we have not really changed the structure of the code, we've just shuffled it around, so lets change that.
+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 calculating.
 
-One of the major things we ideally want to change is how the weapon code is handled. Currently all of the weapon realted code is all in ``Player.gd``, everything
-from how much ammo a weapon carries, to firing bullets. While this has the advantage of having all of your code in one place, it would be much
-nicer if we make a weapon interface so we can create/change weapons easily without having to scroll through ``Player.gd`` to look for the bit of code we want to add/change.
+.. note:: You can find a great article explaining all about how to handle joypad/controller dead zones here:
+          https://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!
 
-Open up ``Player.tscn`` and navigate to the ``Gun_fire_points`` node. Lets make the pistol first. Select ``Pistol_point`` and attach a node node and call it
-``Weapon_Pistol.gd``.
+Finally, we add ``joypad_vec`` to ``input_movement_vector``.
 
-Our weapon scripts are going to do four things: They're going to handle *firing*, *reloading*, *equipping*, and *unequipping*.
+.. tip:: Remember how we normalize ``input_movement_vector``? This is why! If we did not normalize ``input_movement_vector`` players could
+         move faster if they are pushing in the same direction with both their keyboard and their joypad!
+         
+______
 
-Add the following code to ``Weapon_Pistol.gd``:
+Make a new function called ``process_view_input`` and add the following:
 
 ::
     
-    extends Spatial
-
-    var ammo_in_weapon = 20;
-    var spare_ammo = 60;
-    const AMMO_IN_MAG = 20;
-    const DAMAGE = 15;
-
-    const CAN_RELOAD = true;
-
-    const RELOADING_ANIM_NAME = "Pistol_reload"
-    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;
-        ammo_in_weapon -= 1
-        
-        player_node.create_sound("Pistol_shot", self.global_transform.origin)
-
-
-    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("Pistol_reload")
-            
-            player_node.create_sound("Gun_cock", player_node.camera.global_transform.origin)
-            
-            return true;
-        
-        return false;
-
-    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")
-            
-            player_node.create_sound("Gun_cock", player_node.camera.global_transform.origin)
-        
-        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")
+    func process_view_input(delta):
         
-        if player_node.animation_manager.current_state == "Idle_unarmed":
-            is_weapon_enabled = false;
-            return true
-        else:
-            return false
-
-            
-Lets go over what is happening in this script:
+        if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
+            return
 
-______
+        # NOTE: Until some bugs relating to captured mouses 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!
 
-First lets look at the constants and go over what each will do:
+        # ----------------------------------
+        # Joypad rotation
 
-* ``ammo_in_weapon``: How much ammo is *currently* in this weapon.
-* ``spare_ammo``: How much spare ammo we have in reserve for this weapon. ``spare_ammo + ammo_in_weapon = total ammo for this weapon``.
-* ``AMMO_IN_MAG``: The amount ammo needed to fill the weapon. To put it another way, the amount of ammo in each magazine.
-* ``DAMAGE``: The amount of damage a single bullet does.
-* ``CAN_RELOAD``: A boolean for tracking whether this weapon has the ability to reload.
-* ``RELOADING_ANIM_NAME``: The name of the reloading animation for this weapon.
-* ``IDLE_ANIM_NAME``: The name of the idle animation for this weapon.
-* ``FIRE_ANIM_NAME``: The name of the firing animation for this weapon.
-* ``is_weapon_enabled``: A boolean for tracking whether or not this weapon is the currently used/enabled weapon.
-* ``bullet_scene``: The bullet scene we created in part 2 of this tutorial.
-* ``player_node``: The player node and script (``Player.gd``).
+        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))
 
-Notice how we do not do anything in ``_ready``.
+            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))
 
-We could try and grab the player node here, but it makes a messy ``get_node`` call, and because we already
-have to aim these points in ``Player.gd`` anyway, we will just pass the player node then.
+            rotation_helper.rotate_x(deg2rad(joypad_vec.y * JOYPAD_SENSITIVITY))
 
-.. note:: This is just a design choice. Depending on your project, it may be better to use ``get_node`` in the
-          weapon scripts.
+            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:
 
-Lets look at ``fire_weapon``.
+First we check the mouse mode. If the mouse mode is not ``MOUSE_MODE_CAPTURED``, we want to return, which will skip the code below.
 
-First we make a clone of the bullet scene and add it as a child of the scene root.
-Next we set its global transform to ``self.global_transform``.
+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.
 
-.. note:: before we were using a ``get_node`` call to
-          get here because we were calling this from ``Player.gd``. Now that we are firing from the fire point itself, we do not
-          need to use ``get_node`` any more.
+.. warning:: As stated above, I do not (currently) has 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!
 
-Then we set its scale. As before, the bullet object is too small by default, so we scale it up so it's easier to see.
+We then account for the joypad's dead zone, just like in ``process_input``.
 
-Next we set its damage. This is new, but nothing crazy. To make this work, we just need to go into
-``Bullet_script.gd`` and change ``const BULLET_DAMAGE`` to ``var BULLET_DAMAGE``. The reason behind changing ``BULLET_DAMAGE`` from
-a constant to a normal variable is because we may reuse the bullet object later (for a different weapon)
+Then we rotate ``rotation_helper`` and our KinematicBody using ``joypad_vec``.
 
-.. warning:: Do not forgot to change ``const BULLET_DAMAGE`` to ``var BULLET_DAMAGE`` in ``Bullet_script.gd``!
+Notice how the code that handles rotating ourselves 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``.
 
-Then we remove one from the ammo in our weapon and play a sound (if we have sounds).
+.. note:: Due to 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 as well.
 
-.. note:: With the exception of how we are no longer using ``get_node``, everything in ``fire_weapon`` is the same as the code
-          as ``Player.gd``'s ``fire_bullet`` function.
+Finally, we clamp the camera's rotation so we cannot look upside down.
 
 ______
 
-In ``reload_weapon`` we are doing things a little differently.
-
-First we define a variable to track whether or not we can reload. We then do a couple checks. The first check is checking whether
-or not we are in this weapon's idle animation. We do not want to reload while we are playing any other animation, so this check ensures
-that does not happen.
+The last thing you need to do is add ``process_view_input`` to ``_physics_process``.
 
-The next thing we check is whether or not we have any ammo in reserve and/or if our weapon is full. We cannot reload with no spare ammo, and
-we do not want the player to be able to reload if the weapon is already full.
+Once ``process_view_input`` is added to ``_physics_process``, you should be able to play using a joypad!
 
-.. tip:: In some games you can reload while full. Many times in these cases you lose whatever ammo was in the weapon when you reload.
-         For this tutorial though, we will only allow the player to reload if they do not have a full weapon.
-
-Then we check ``can_reload`` to see if it is true.
+.. 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 button 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 proper axis value for the trigger,
+          and check if it's over a certain value, say ``0.8`` for example. If it is, you just add the same code as when the ``fire`` action was pressed.
+         
+Adding mouse scroll wheel input
+-------------------------------
 
-If it is, we then calculate how much ammo we need to fill the weapon.
+Let's add one input related feature before we start working on the pick ups and target. Let's add the ability to change weapons using the scroll wheel on the mouse.
 
-If we have enough ammo in spares to fill the weapon, we remove the ammo we are taking from spares and set ``ammo_in_weapon`` to however much ammo is in a full weapon.
+Open up ``Player.gd`` and add the following global variables:
 
-If we do not have enough ammo in spares, we instead add all of the ammo left in spares and then set our spare ammo to zero.
+::
+    
+    var mouse_scroll_value = 0
+    const MOUSE_SENSITIVITY_SCROLL_WHEEL = 0.08
 
-We then play the reloading animation and play a sound. We return ``true`` to signal we have successfully reloaded.
+Let's go over what each of these new variables will be doing:
 
-If we cannot reload because ``reload_weapon`` is ``false``, we return ``false`` to signal we did not successfully reload.
+* ``mouse_scroll_value``: The value of the mouse scroll wheel.
+* ``MOUSE_SENSITIVITY_SCROLL_WHEEL``: How much a single scroll action increases mouse_scroll_value
 
 ______
 
-For ``equip_weapon`` we first check if the player is in the pistol's idle state.
+Now let's add the following to ``_input``:
 
-If we are in the pistol's idle state we've successfully equipped the pistol.
-We set ``is_weapon_enabled`` to ``true`` because we are now using this weapon, and return ``true``.
+::
+    
+    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
 
-.. note:: We need ``is_weapon_enabled`` so we do not keep trying to equip/unequip the weapons over and over again. If we relied only on using
-          the ``equip_weapon``/``unequip_weapon`` functions, we could possibility get cases where we are stuck in a loop where we are equipping/unequipping
-          the same weapon over and over again.
+                        
+Let's go over what's happening here:
 
-Next we check if we are in the idle unarmed state, a state where we can transition to our equip animation. If we are, then we change the animation
-to ``Pistol_equip`` and play a sound. Finally, we return ``false``.
+First we check if the event is a ``InputEventMouseButton`` event and that our 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.
 
-The reason behind returning ``false`` unless we are in our idle animation is because we will be calling this function more than once, checking to see if we
-have successfully equipped the pistol.
+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/remove ``MOUSE_SENSITIVITY_SCROLL_WHEEL`` to/from ``mouse_scroll_value``.
 
-______
+Next we clamp mouse scroll value to assure it is inside the range of our weapons.
 
-``unequip_weapon`` is extremely similar to ``equip_weapon``, but the checks are in reverse.
+We then check to see if we are changing weapons or reloading. If we are doing neither, we round ``mouse_scroll_value`` and cast it to a ``int``.
 
-We just check if we are in our idle state. If we are, and we are not already unequipping we set our animation to ``Pistol_unequip``.
-Then we check if we are in the idle animation. If we are, we set ``is_weapon_enabled`` to ``false`` because we are no longer using this weapon, and return ``true``.
+.. note:: We are casting ``mouse_scroll_value`` to a ``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 try to run the project.
 
-Finally, if we did not return ``true``, we return false.
+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 than our current weapon, we assign ``changing_weapon_name``, set ``changing_weapon`` to true so we will change weapons in
+``process_changing_weapon``, and set ``mouse_scroll_value`` to ``round_mouse_scroll_value``.
 
-As with ``equip_weapon``, we want to return false by default because we will be calling this function until it returns true.
+.. 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 assure that each weapon takes exactly the same amount of scrolling to change.
 
 ______
 
-Now we just need to do the same thing for the knife and the rifle.
-
-There is only one minor difference with the knife and the rifle. We still define a reload function for the knife, but instead of doing
-anything we automatically return false.
-
-Select ``Knife_point``, created a new script called ``Weapon_Knife.gd``, and add the following:
+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``:
 
 ::
     
-    extends Spatial
-
-    var ammo_in_weapon = 1;
-    var spare_ammo = 1;
-    const AMMO_IN_MAG = 1;
-
-    const DAMAGE = 40;
-
-    const CAN_RELOAD = false;
-    const RELOADING_ANIM_NAME = ""
-    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 = get_node("Area")
-        var bodies = area.get_overlapping_bodies()
-        
-        for body in bodies:
-            if body.has_method("bullet_hit"):
-                body.bullet_hit(DAMAGE, area.global_transform.origin)
+    mouse_scroll_value = weapon_change_number
+    
+Now our scroll value we be changed with the keyboard input. If we did not change this, our scroll value will be out of sync. If the scroll wheel is 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.
 
+______
 
-    func reload_weapon():
-        return false;
+Now you can change weapons using the scroll wheel! Go give it a whirl!
 
-    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
+Adding the health pick ups
+--------------------------
 
-    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
+Now that our player has health and ammo, we ideally need a way to replenish those resources.
 
-There are only a few things to note here.
+Open up ``Health_Pickup.tscn``.
 
-The first is we still are defining ``ammo_in_weapon``, ``spare_ammo`` and ``AMMO_IN_MAG``. The reason behind this is so our code has a consistent
-interface. We may later need to access these variables in all weapons, so we are adding them for the knife as a way assure all weapons have these variables.
+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``.
 
-The second thing of note is in ``reload_weapon``. Because we cannot reload a knife (or at least, not this one), we just always return ``false``.
+This is because we're actually going to be making two sizes of health pick ups, one small and one large/normal. ``Health_Kit`` and ``Health_Kit_Small`` just
+have a single :ref:`MeshInstance <class_MeshInstance>` as their children.
 
-The last thing to note is how ``fire_weapon``'s code is exactly the same as the code from ``Player.gd``. The firing code for all three weapons,
-the pistol, rifle, and knife, are exactly the same as the code in ``Player.gd``. The only differences is how we are accessing the spawn point nodes
-and 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 pick up, so the smaller health pick up has a trigger collision shape closer to it's size.
 
-______
+The last thing to note is how we have a :ref:`AnimationPlayer <class_AnimationPlayer>` node so the health kit spins around slowly and bobs up and down.
 
-Finally, select ``Rifle_point``, create a new script called ``Weapon_Rifle.gd``, and add the following code:
+Select ``Health_Pickup`` and add a new script called ``Health_Pickup.gd``. Add the following:
 
 ::
     
     extends Spatial
 
-    var ammo_in_weapon = 80;
-    var spare_ammo = 160;
-    const AMMO_IN_MAG = 80;
-    const DAMAGE = 4;
+    export (int, "full size", "small") var kit_size = 0 setget kit_size_change
 
-    const CAN_RELOAD = true;
-    const RELOADING_ANIM_NAME = "Rifle_reload"
-    const IDLE_ANIM_NAME = "Rifle_idle"
-    const FIRE_ANIM_NAME = "Rifle_fire"
+    # 0 = full size pickup, 1 = small pickup
+    const HEALTH_AMOUNTS = [70, 30]
 
-    var is_weapon_enabled = false;
+    const RESPAWN_TIME = 20
+    var respawn_timer = 0
 
-    var player_node = null;
+    var is_ready = false
 
     func _ready():
-        pass;
-
-    func fire_weapon():
-        var ray = get_node("RayCast")
-        ray.force_raycast_update()
         
-        if ray.is_colliding():
-            var body = ray.get_collider()
-            if body.has_method("bullet_hit"):
-                body.bullet_hit(DAMAGE, ray.get_collision_point())
+        $Holder/Health_Pickup_Trigger.connect("body_entered", self, "trigger_body_entered")
         
-        ammo_in_weapon -= 1;
+        is_ready = true
         
-        player_node.create_sound("Rifle_shot", ray.global_transform.origin)
+        kit_size_change_values(0, false)
+        kit_size_change_values(1, false)
+        kit_size_change_values(kit_size, true)
 
 
-    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("Rifle_reload")
-            
-            player_node.create_sound("Gun_cock", player_node.camera.global_transform.origin)
-            
-            return true;
-        
-        return false;
-
-    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")
+    func _physics_process(delta):
+        if respawn_timer > 0:
+            respawn_timer -= delta
             
-            player_node.create_sound("Gun_cock", player_node.camera.global_transform.origin)
-        
-        return false
+            if respawn_timer <= 0:
+                kit_size_change_values(kit_size, true)
 
-    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
 
-Thankfully the code for the rifle is exactly the same as the pistol, with ``fire_weapon`` changed to use the rifle's firing code. Other than that, everything is exactly the same,
-just adjusted for the rifle.
-        
-Finishing refactoring ``Player.gd``
------------------------------------
-
-Now we are ready to use our newly refactored weapons in ``Player.gd``. First, we need to change some of the global variables.
-Find all of the constants relating to the weapons, delete them, and add the following:
-
-::
-    
-    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 reloading_weapon = false
-
-Lets go over each of these new global variables:
-
-* ``current_weapon_name``: The name of the weapon currently in use.
-* ``weapons``: A dictionary holding all of the weapon nodes, allowing us to access them by name instead of using ``get_node``.
-* ``weapon_number_to_name``: A dictionary holding all of the weapons and which number they represent.
-* ``weapon_name_to_number``: A dictionary holding all of the weapons numbers and which names they represent. Combined with ``weapon_number_to_name``, we can change from number to name and back.
-* ``changing_weapon``: A boolean to track whether we are trying to change weapons or not.
-* ``changing_weapon_name``: The name of the weapon we are trying to change to.
-* ``reloading_weapon``: A boolean to track whether we are reloading or not.
-
-We need to change ``_ready`` to the following:
-
-::
-    
-    func _ready():
-        camera = get_node("Rotation_helper/Camera")
-        rotation_helper = get_node("Rotation_helper")
-        
-        animation_manager = get_node("Rotation_helper/Model/AnimationPlayer")
-        animation_manager.callback_function = funcref(self, "fire_bullet")
-        
-        set_physics_process(true)
-        
-        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-        set_process_input(true)
-        
-        weapons["KNIFE"] = get_node("Rotation_helper/Gun_fire_points/Knife_point")
-        weapons["PISTOL"] = get_node("Rotation_helper/Gun_fire_points/Pistol_point")
-        weapons["RIFLE"] = get_node("Rotation_helper/Gun_fire_points/Rifle_point")
-        
-        var gun_aim_point_pos = get_node("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 = get_node("HUD/Panel/Gun_label")
-        flashlight = get_node("Rotation_helper/Flashlight")
-
-Lets quickly go over the new stuff.
+    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
 
-Notice how most of the code is exactly the same as before. The only code that's changed is how
-we are handling the gun aim points, so let's look at those changes.
 
-First, we get all of the weapon nodes using ``get_node`` and assign them to the ``weapons`` dictionary.
+    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
 
-Then we loop through all of the weapons in the ``weapons`` dictionary. For each weapon node, we get the value assigned to that key.
 
-.. tip:: When we are using ``for X in Y`` where ``Y`` is a dictionary, ``X`` is assigned to the each **key** in the dictionary, not the value. To get the value, we
-          have to retrieve it using ``Y[X]``.
+    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)
 
-If the weapon node is not ``null``, we set it's ``player_node`` variable to ``self``, and we make the point look at the gun aim position.
+Let's go over what this script is doing, starting with its global variables:
 
-.. note:: The reason we check for ``null`` is because our ``UNARMED`` weapon is ``null``. This is just a design choice, not a requirement for FPS games.
-          You could define a "weapon" for the UNARMED state, but in this series we are just going to use ``null``.
+* ``kit_size``: The size of the health pick up. Notice how we're using a ``setget`` function to tell if it's changed.
+* ``HEALTH_AMMOUNTS``: The amount of health each pick up in each size contains.
+* ``RESPAWN_TIME``: The amount of time, in seconds, it takes for the health pick up to respawn
+* ``respawn_timer``: A variable used to track how long the health pick up has been waiting to respawn.
+* ``is_ready``: A variable to track whether the ``_ready`` function has been called or not.
 
-Next we flip the aim point by ``180`` degrees so it doesn't fire backwards.
+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.
 
-.. warning:: The reason behind rotating the gun aim point is explained in :ref:`part 2 <doc_fps_tutorial_part_two>`
+Also, notice how we're using a exported variable. This is so we can change the size of the health pick up in the editor, for each pick up. This makes it where
+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.
 
-Finally, we set ``current_weapon_name`` and ``changing_weapon_name`` to ``UNARMED`` so our starting weapon is ``UNARMED``.
+.. tip:: See :ref:`doc_GDScript` and scroll down to the Exports section for a list of of export hints you can use.
 
 ______
 
-Now we need to change ``_physics_process``. Delete everything in ``_physics_process`` and add the following:
-
-::
-    
-    func _physics_process(delta):
-        process_input(delta)
-        #process_view_input(delta)
-        process_movement(delta)
-        process_changing_weapons(delta)
-        process_reloading(delta)
-        process_UI(delta)
-
-.. note:: You may have noticed how we have a commented out function, ``process_view_input``. We will be using this later!
-          For now just leave it commented out!
-
-Now we are calling each of our modular functions in order. Notice how we are still missing
-``process_changing_weapons``, ``process_reloading``, and ``process_UI``. Before we add those functions, lets quickly return to
-``process_input``.
+Let's look at ``_ready``:
 
-Finishing ``process_input``
-___________________________
+First we connect the ``body_entered`` signal from our ``Health_Pickup_Trigger`` to the ``trigger_body_entered`` function. This makes is where any
+body that enters the :ref:`Area <class_Area>` triggers the ``trigger_body_entered`` function.
 
-First, lets change ``process_input`` so our weapon related code works with the new weapon system.
+Next we set ``is_ready`` to ``true`` so we can use our ``setget`` function.
 
-First, delete all of the weapon related code in `process_input`. This is the includes:
-Changing weapons, Reloading, and Firing.
+Then we hide all of 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.
 
-Now at the bottom of ``process_input``, add the following code:
-
-::
-    
-    func process_input(delta):
-        
-        # Other input code (like movement, jumping, etc) above!
-        
-        # ----------------------------------
-        # 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 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
-        # ----------------------------------
-        
-        # ----------------------------------
-        # 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
-        # ----------------------------------
-        
-        # ----------------------------------
-        # 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
-        # ----------------------------------
-
-Lets go through what each of these sections are doing.
+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.
 
 ______
 
-Lets look at the weapon changing section first.
-
-The first thing we do is get the current weapon number and assign it to ``weapon_change_number``.
+Next let's look at ``kit_size_changed``.
 
-Next we check each of the four number keys and we assign ``weapon_change_number`` to their value if they are pressed.
+The first thing we do is check to see if ``is_ready`` is ``true``.
 
-.. note:: Most keyboards go in the order of ``1234567890``, so we when we set ``weapon_change_number``, we offset the value by ``-1`` so the first key (``1``)
-          is actually ``0``, which is our first weapon.
+If ``is_ready`` is ``true``, we then make whatever kit is currently assigned to ``kit_size`` disabled using ``kit_size_change_values``, passing in ``kit_size`` and ``false``.
 
-Then we check if two new actions are pressed: ``shift_weapon_positive`` and ``shift_weapon_negative``. We will add these actions once we've finished
-going over ``process_input``.
+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 we passed in visible.
 
-Next we clamp ``weapon_change_number`` so it cannot be higher or lower than the amount of weapons we have.
-
-.. tip:: We are making a small assumption here: We are assuming our weapons are defined in a linear pattern, where we do not have any jumps in number.
-         
-         Another thing to note is we are getting the maximum value using ``weapon_to_number.size()-1``. We remove ``1`` because ``size`` returns the number
-         of elements in the dictionary, starting from ``1``, while GDScript accesses values starting from ``0``.
-
-We do not want to suddenly change weapons while already changing weapons or reload, so we check to make sure both variables are ``false``.
-
-Then we convert ``weapon_change_number`` to a weapon name using ``weapon_number_to_name`` and check to make sure we not trying to change to the weapon we
-are already using. If we are indeed changing weapons, we set ``changing_weapon_name`` to the name of the weapon at ``weapon_change_name`` using ``weapon_number_to_name``.
-Finally, we set ``changing_weapon`` to true so we can process the actual weapon changing logic in ``process_changing_weapons``.
+If ``is_ready`` is not ``true``, we simply assign ``kit_size`` to the passed in ``value``.
 
 ______
 
-For reloading we first check to make sure we are not already reload, or changing weapons.
-
-Then we check to see if the reloading action has been pressed.
-Next we get the current weapon and assign it to ``current_weapon``.
-If the current weapon is not ``null`` we then make sure this weapon can reload using the weapon's ``CAN_RELOAD`` constant.
+Now let's look at ``kit_size_change_values``.
 
-.. tip:: We check for ``null`` because we do not want to reload ``UNARMED``!
+The first thing we do is check to see which size we're using. Based on which size we're wanting to enable/disable, we want to get different nodes.
 
-Next we check get the current animation state from our animation manager, and we set ``is_reloading`` to ``false``.
-The reason we need ``is_reloading`` is because we need to go through each weapon and make sure we are not in it's reloading state already,
-because we do not want to allow the player to (potentially) reload if they are already in a reloading animation.
+We get the collision shape for the node corresponding to ``size`` and disable it based on the ``enabled`` passed in argument/variable.
 
-We then go through each weapon in our ``weapons`` dictionary. We then get the weapon node, assign it to ``weapon_node`` and check to make sure it
-is not ``null``. If it is not ``null``, we then make sure it's ``RELOADING_ANIM_NAME`` constant to see if it is equal to the animation we are currently in. If it is,
-we set ``is_reloading`` to ``true``.
+.. 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``.
 
-If ``is_reloading`` is still ``false``, we then set ``reloading_weapon`` to true so we can process the reloading weapon logic in ``process_reloading``.
+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, we have the firing section.
+Finally, let's look at ``trigger_body_entered``.
 
-The first thing we do is check to see if the ``fire`` action has been pressed. If it has, we then make sure we are not reloading or changing weapons.
+The first thing we do is see whether or not the body that 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.
 
-Next we get the current weapon and assign it to ``current_weapon``. We then check to make sure it is not equal to ``null``.
+Then we set ``respawn_timer`` to ``RESPAWN_TIME`` so we have to wait before we 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 we've waited long enough to respawn.
 
-If the current weapon is not equal to ``null``, we then make sure the weapon actually has ammo. If it does, we then check to see if we are in the weapon's idle state.
-If we are indeed in the weapon's idle state, we set our animation to the weapon's fire animation.
+_______
 
-If the current weapon does not have any ammo, we set ``reloading_weapon`` to true.
+The last thing we need to do before we can use this health pick up is add a few things to our player.
 
-Adding our new input map actions
-________________________________
+Open up ``Player.gd`` and add the following global variable:
 
-As mentioned above, we've defined a couple new input actions: ``shift_weapon_positive`` and ``shift_weapon_negative``.
-Currently these input actions do not exist in our project, so let's add them!
+::
+    
+    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 our player. Add the following to ``Player.gd``:
 
-.. image:: img/ProjectSettingsAddAction.png
+::
+    
+    func add_health(additional_health):
+        health += additional_health
+        health = clamp(health, 0, MAX_HEALTH)
 
-Open up your project settings and go to the ``Input Map`` tab. In the ``Action`` text field, type ``shift_weapon_positive`` and press enter or press the
-button on the side that reads ``Add``. Next write ``shift_weapon_negative`` and press enter or press the ``Add`` button.
+Let's quickly go over what this does.
 
-Scroll down to the bottom of the list and click the little plus sign next to one of the newly created actions.
+We first add ``additional_health`` to our current health. We then clamp the health so that it cannot exceed a value higher than ``MAX_HEALTH``, nor a value lower
+than ``0``.
 
-.. image:: img/ProjectSettingsAddKey.png
+_______
+
+With that done, now we can collect health! Go place a few ``Health_Pickup`` scenes around and give it a try. You can change the size of the health pick up in the editor
+when a ``Health_Pickup`` instanced scene is selected, from a convenient drop down.
 
-You can assign whatever key you want to either
-of these actions. The finished project has the ``Equal`` and ``Kp Add`` keys assigned to ``shift_weapon_positive``. ``shift_weapon_negative`` has ``Minus`` and
-``Kp Subtract`` keys assigned in the finished project.
+Adding the ammo pick ups
+------------------------
 
-Once you've assigned whatever keys you want to both actions, close the project settings and save.
+While adding health is good and all, we can't really reap the rewards from it since nothing can (currently) damage us.
+Let's add some ammo pick ups next!
 
-Adding ``process_changing_weapons``
-___________________________________
+Open up ``Ammo_Pickup.tscn``. Notice how it's structured exactly the same as ``Health_Pickup.tscn``, just with the meshes and trigger collision shapes changed slightly to adjust
+for the difference in mesh sizes.
 
-Lets make the weapon changing logic next. Open up ``Player.gd`` and add the following function:
+Select ``Ammo_Pickup`` and add a new script called ``Ammo_Pickup.gd``. Add the following:
 
 ::
     
-    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_equiped = false
-                var weapon_to_equip = weapons[changing_weapon_name]
-                
-                if weapon_to_equip == null:
-                    weapon_equiped = true
-                else:
-                    if weapon_to_equip.is_weapon_enabled == false:
-                        weapon_equiped = weapon_to_equip.equip_weapon()
-                    else:
-                        weapon_equiped = true
-                
-                if weapon_equiped == true:
-                    changing_weapon = false
-                    current_weapon_name = changing_weapon_name
-                    changing_weapon_name = ""
+    extends Spatial
 
-Lets go over what's happening here.
+    export (int, "full size", "small") var kit_size = 0 setget kit_size_change
 
-First we check to make sure ``changing_weapon`` is ``true``.
+    # 0 = full size pickup, 1 = small pickup
+    const AMMO_AMOUNTS = [4, 1]
+    
+    const RESPAWN_TIME = 20
+    var respawn_timer = 0
 
-Next we make a new variable, ``weapon_unequipped``, and set it to ``false``. We will use ``weapon_unequipped`` to check whether or not the current weapon is unequipped.
-We then get the current weapon and assign it to ``current_weapon``.
+    var is_ready = false
 
-If the current weapon is ``null``, if we are ``UNARMED``, we can conclude the weapon has been successfully unequipped and set ``weapon_unequipped`` to ``true``.
+    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)
 
-If the weapon is not ``null``, we check if the weapon is enabled. If the weapon is enabled, we call it's ``unequip_weapon`` function. If it is not enabled, we set ``weapon_unequipped`` to ``true``.
 
-Next we check if ``weapon_unequipped`` is ``true`` or not. Remember, ``weapon_unequipped`` will only be true if the current weapon's ``is_weapon_enabled`` variable is ``false`` (or the weapon
-is ``null``).
+    func _physics_process(delta):
+        if respawn_timer > 0:
+            respawn_timer -= delta
+            
+            if respawn_timer <= 0:
+                kit_size_change_values(kit_size, true)
 
-If the current weapon is successfully unequipped, we then make a variable, ``weapon_equipped``. ``weapon_equipped`` will serve the same function as ``weapon_unequipped``, but instead of
-tracking if we've successfully unequipped the current weapon, we instead are tracking to see if the weapon we are wanting to change to has been successfully equipped.
 
-We then get the weapon we want to change to and assign it to ``weapon_to_equip``.
+    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
 
-Next we check to see if ``weapon_to_equip`` is ``null``. If it is, we set ``weapon_equipped`` to ``true`` because ``UNARMED`` does not need any additional processing.
 
-If ``weapon_to_equip`` is not null, we then check to see if the weapon is not enabled by checking it's ``is_weapon_enabled`` variable. If it is not enabled, we call ``equip_weapon``
-on the weapon we are wanting to equip.
+    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
 
-If the weapon we are wanting to equip is enabled, we set ``weapon_equipped`` to true.
 
-Finally, we check to see if ``weapon_equipped`` is ``true``. If it is, we set ``changing_weapon`` to ``false``, set ``current_weapon_name`` to the weapon we have changed to (``changing_weapon_name``),
-and we set ``changing_weapon_name`` to a empty string.
+    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)
 
-Adding ``process_reloading``
-____________________________
+You may have noticed this code looks almost exactly the same as the health pick up. 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.
 
-Let's finish up our new modular weapon system and add ``process_reloading``. Make a new function called ``process_reloading`` and add the following:
+First, notice how we have ``AMMO_AMOUNTS`` instead of ``HEALTH_AMMOUNTS``. ``AMMO_AMOUNTS`` will be how many ammo clips/magazines we add to the current weapon.
+(Unlike ``HEALTH_AMMOUNTS`` which was how many health points, we instead just add an entire clip for the current weapon, instead of the raw ammo amount)
 
-::
-    
-    
-    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
+The only other thing to notice is in ``trigger_body_entered`` we're checking and calling a function called ``add_ammo``, not ``add_health``.
 
-Let's go over what's this function does.
+Other than those two small changes, everything else is exactly the same as the health pickup!
 
-First we check to make sure we are wanting to reload. If we are, we then get the current weapon and assign it to ``current_weapon``.
-If ``current_weapon`` is not equal to ``null``, we call it's ``reload_weapon`` function.
+_______
 
-Finally, we set ``reloading_weapon`` to ``false`` because regardless of whether we've successfully reloaded, we have tried and no longer
-need to process weapon reloading.
-
-Changing ``fire_bullet``
-________________________
-
-Next we need to change ``fire_bullet`` because we are no longer actually firing the bullets in ``Player.gd``. Change ``fire_bullet`` to the following:
+All we need to do make the ammo pick ups work is add a new function to our player. Open ``Player.gd`` and add the following function:
 
 ::
     
-    func fire_bullet():
-        if changing_weapon == true:
-            return
-        weapons[current_weapon_name].fire_weapon()
-
-Now in ``fire_bullet`` we make sure we are not changing weapons, and if we are not we call the current weapon's ``fire_weapon`` function.
-        
-
-Adding ``process_UI``
-_____________________
-
+    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
 
-Because we've changed how weapons work, we need to change how we update the UI.
-Make a new function called ``process_UI`` and add the following:
+Let's go over what this function does.
 
-::
-    
-    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)
+The first thing we check is to see whether we're using ``UNARMED`` or not. Because ``UNARMED`` does not have a node/script, we want to make sure we're not using
+``UNARMED`` before trying to get the node/script attached to ``current_weapon_name``.
 
-        
-Nothing much has changed from the code that was in ``_physics_process``, we've mainly just moved the UI processing code to
-its own function.
+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`` variable times however much ammo clips we're adding (``additional_ammo``).
 
-The only major change is how we get the amount counts in the current weapon.
+_______
 
-______
+With that done, you should now be able to get additional ammo! Go place some ammo pick ups in one/both/all of the scenes and give it a try!
 
-Now we have successfully refactored ``Player.gd`` to use a more modular approach and the weapons now are (mainly) processed in their own scripts!
-Go give the game a test. If everything is written correctly you should be able to run around and shoot things just like before.
+.. 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 just need to add a additional variable to
+          each weapon's script, and then clamp the weapon's ``spare_ammo`` variable after adding ammo in ``add_ammo``.
 
-Now that we've refactored ``Player.gd``, lets add something new: Let's allow our plays to play using a joypad!
+Adding breakable targets
+------------------------
 
-Adding joypad input
--------------------
+Before we end this part, let's add some targets.
 
-.. 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.
+Open up ``Target.tscn`` and take a look at the scenes in the scene tree.
 
-First we need to change a few things in our project's input map. Open up the project settings and select the ``Input Map`` tab.
+First, notice how we're not using a :ref:`RigidBody <class_RigidBody>` node, but rather a :ref:`StaticBody <class_StaticBody>` node instead.
+The reason behind this is our non-broken targets will not be moving anywhere, using a :ref:`RigidBody <class_RigidBody>` would be more hassle then
+its worth, since all it has to do is stay still.
 
-Now we need to add some joypad buttons to our various actions. Click the plus icon and select ``Joy Button``.
+.. tip:: We also save a tiny bit of performance using a :ref:`StaticBody <class_StaticBody>` over a :ref:`RigidBody <class_RigidBody>`
 
-.. image:: img/ProjectSettingsAddKey.png
+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``.
 
-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:
+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.
 
-* 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 Right)``
+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 where we can shoot at the broken pieces and they will react to the bullets.
 
-Once you are happy with the input, close the project settings and save.
+Alright, now switch back to ``Target.tscn``, select the ``Target`` :ref:`StaticBody <class_StaticBody>` node and created a new script called ``Target.gd``.
 
-______
-
-Now let's open up ``Player.gd`` and add joypad input.
-
-First, we need to define a few new global variables. Add the following global variables to ``Player.gd``:
+Add the following code to ``Target.gd``:
 
 ::
     
-    # You may need to adjust depending on the sensitivity of your joypad
-    const JOYPAD_SENSITIVITY = 2
-    const JOYPAD_DEADZONE = 0.15
+    extends StaticBody
 
-Lets go over what each of these do:
+    const TARGET_HEALTH = 40
+    var current_health = 40
 
-* ``JOYPAD_SENSITIVITY``: This is how fast our joypad joysticks will move our camera.
-* ``JOYPAD_DEADZONE``: The dead zone for the joypad. You may need to adjust depending on your joypad.
+    var broken_target_holder
 
-.. note::  Many joypads jitter around a certain point. To counter this, we ignore any movement in a
-           with a radius of JOYPAD_DEADZONE. If we did not ignore said movement, the camera will jitter.
+    # The collision shape for the target.
+    # NOTE: this is for the whole target, not the pieces of the target
+    var target_collision_shape
 
-Now we are ready to start handling joypad input!           
+    const TARGET_RESPAWN_TIME = 14
+    var target_respawn_timer = 0
 
-______
-           
-In ``process_input`` add the following code, just before ``input_movement_vector = input_movement_vector.normalized()``:
+    export (PackedScene) var destroyed_target
 
-::
-    
-    # Add joypad input, if there is a joypad
-	if Input.get_connected_joypads().size() > 0:
-		var joypad_vec = Vector2(Input.get_joy_axis(0, 0), -Input.get_joy_axis(0, 1))
-		
-		if (abs(joypad_vec.x) <= JOYPAD_DEADZONE):
-			joypad_vec.x = 0
-		if (abs(joypad_vec.y) <= JOYPAD_DEADZONE):
-			joypad_vec.y = 0
-		
-		input_movement_vector += joypad_vec
-
-Lets go over what we're doing.
-
-First we check to see if there is a connected joypad.
-
-If there is a joypad connected, we then get it's left stick axes for right/left and up/down.
-
-.. warning:: This tutorial assumes you are using a XBox 360 wired controller
-             on Windows. The axes needed may be different on different operating systems and/or controllers.
-
-Next we check to see if the joypad vector is within the ``JOYPAD_DEADZONE`` radius. If the ``x`` or ``y`` coordinates
-are within the ``JOYPAD_DEADZONE`` radius, we set it to zero.
+    func _ready():
+        broken_target_holder = get_parent().get_node("Broken_Target_Holder")
+        target_collision_shape = $Collision_Shape
 
-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`` players could
-         move faster if they are pushing in the same direction with both their keyboard and their joypad!
-         
-______
+    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
 
-Remember that commented out function in ``_physics_process``? Lets add it! Remove the ``#`` in ``_physics_process`` and make a new function called ``process_view_input``.
-Add the following to ``process_view_input``:
 
-::
-    
-    func process_view_input(delta):
-	
-        if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
-            return
-        
-        # ----------------------------------
-        # Joypad rotation
+    func bullet_hit(damage, bullet_hit_pos):
+        current_health -= damage
         
-        var joypad_vec = Vector2()
-        if Input.get_connected_joypads().size() > 0:
+        if current_health <= 0:
+            var clone = destroyed_target.instance()
+            broken_target_holder.add_child(clone)
             
-            # For windows (XBOX 360)
-            joypad_vec = Vector2(Input.get_joy_axis(0, 2), Input.get_joy_axis(0, 3))
-            # For Linux (XBOX 360)
-            #joypad_vec = Vector2(Input.get_joy_axis(0, 3), Input.get_joy_axis(0, 4))
-            # For Mac (XBOX 360) Unknown, but likely:
-            #joypad_vec = Vector2(Input.get_joy_axis(0, 3), Input.get_joy_axis(0, 4))
+            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)
             
-            if abs(joypad_vec.x) <= JOYPAD_DEADZONE:
-                joypad_vec.x = 0
-            if abs(joypad_vec.y) <= JOYPAD_DEADZONE:
-                joypad_vec.y = 0
-        
-        rotation_helper.rotate_x(deg2rad(joypad_vec.y * JOYPAD_SENSITIVITY))
-        self.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:
+            target_respawn_timer = TARGET_RESPAWN_TIME
+            
+            target_collision_shape.disabled = true
+            visible = false
 
-First we check the mouse mode. If the mouse mode is not ``MOUSE_MODE_CAPTURED``, we want to return, which will skip the code below.
+Let's go over what this script does, starting with the global variables:
 
-.. note:: The reason we are checking to see if the mouse mode is captured or not is because we may want to add a pause menu later. If we do,
-          we do not want players to move around while the game is paused if they are using a joypad!
+* ``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.
 
-Next we define a new :ref:`Vector2 <class_Vector2>` called ``joypad_vec``. This will hold the right joystick position if there is one, and if there is not one it will
-default to ``(0, 0)``, which will do nothing.
+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 chose the scene from the editor, and when/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.
 
-We then check to see if we have a joypad connected. If we do, we then assign ``joypad_vec`` to the proper axes values.
+______
 
-.. warning:: Depending on our OS, you may need to change the axis order. The axis values proved are confirmed to work
-             on Linux and Windows 10 using a XBox 360 wired controller.
+Let's look at ``_ready``.
 
-We then account for the joypad's dead zone, just like in ``process_input``.
+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 want to use ``$``, then you'd need to change ``get_parent().get_node()`` to ``$"../Broken_Target_Holder"``.
 
-Regardless of whehter or not there is a joypad connected, we rotate ``rotation_helper`` and ourselves using ``joypad_vec``. If we do not have a joypad connected,
-``joypad_vec`` will be equal to zero, which will do nothing.
+.. 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.
 
-Notice how the code that handles rotating ourselves 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``.
+Next we get the collision shape and assign it to ``target_collision_shape``. The reason we need to collision shape is because even when the mesh is invisible, the
+collision shape will still exist in the physics world. This makes it where the player can 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.
 
-.. note:: Due to few mouse related bugs on Windows, we cannot put mouse rotation in ``process_view`` as well. The tutorial will be updated once the bugs are fixed!
+______
 
-Finally, we clamp the camera's rotation so we cannot look upside down.
+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 more than ``0``.
 
-If everything is setup correctly, you can now play around using a joypad!
+If it is, we then remove ``delta`` from it.
 
-.. 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 button 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 proper axis value for the trigger,
-          and check if it's over a certain value, say ``0.8`` for example. If it is, you just add the same code as when the ``fire`` action was pressed.
-         
-Adding mouse scroll wheel input
--------------------------------
+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 we've just got here, effectively allowing us to do whatever we need to do when the timer is finished.
 
-Let's add one more feature before we close this part off. Let's add the ability to change weapons using the scroll wheel on the mouse.
+In this case, we want to respawn our target.
 
-Open up ``Player.gd`` and add the following global variables:
+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.
 
-::
-    
-    var mouse_scroll_value = 0
-    const MOUSE_SENSITIVITY_SCROLL_WHEEL = 0.08
+Next we enable our collision shape by setting its ``disabled`` boolean to ``false``.
 
-Lets go over what each of these new varibles will be doing:
+Then we make ourselves, and all of our children nodes, visible.
 
-* ``mouse_scroll_value``: The value of the mouse scroll wheel.
-* ``MOUSE_SENSITIVITY_SCROLL_WHEEL``: How much a single scroll action increases mouse_scroll_value
+Finally, we reset ``current_health`` to ``TARGET_HEALTH``.
 
 ______
 
-Now lets add the following to ``_input``:
+Finally, let's look at ``bullet_hit``.
 
-::
-    
-    if event is InputEventMouseButton && 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
+The first the we do is remove however much damage the bullet does from our health.
 
-                        
-Let's go over what's happening here:
+Next we check to see if we're at ``0`` health or lower. If we are, then we've just died and need to spawn a broken target.
 
-First we check if the event is a ``InputEventMouseButton`` event and that our 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.
+We first instance a new destroyed target scene, and assign it to a new variable, ``clone``.
 
-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/remove ``MOUSE_SENSITIVITY_SCROLL_WHEEL`` to/from ``mouse_scroll_value``.
+Next we add ``clone`` as a child of our broken target holder.
 
-Next we clamp mouse scroll value to assure it is inside the range of our weapons.
+For an added bonus, we want to make all of the target pieces explode outwards. Do to this, we iterate over all of the children in ``clone``.
 
-We then check to see if we are changing weapons or reloading. If we are doing neither, we round ``mouse_scroll_value`` and cast it to a ``int``.
+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 we are 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 are casting ``mouse_scroll_value`` to a ``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 try to run the project.
+.. 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 explosive you want
+          your targets to shatter.
 
-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 than our current weapon, we assign ``changing_weapon_name``, set ``changing_weapon`` to true so we will change weapons in
-``process_changing_weapon``, and set ``mouse_scroll_value`` to ``round_mouse_scroll_value``.
+Next we set our respawn timer for our non-broken target. We set it to ``TARGET_RESPAWN_TIME``, so it takes ``TARGET_RESPAWN_TIME`` many seconds to respawn.
 
-.. 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 assure that each weapon takes exactly the same amount of scrolling to change.
+Then we disable the non-broken target's collision shape, and set our visibility to ``false``.
 
 ______
 
-Now you can change weapons using the scroll wheel! Go give it a whirl!
+.. 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
 -----------
 
-Now ``Player.gd`` is laid out much better, is easier to extend, we've added joypad input, and now the player can change weapons with the scroll wheel!
-
-.. tip:: You can find the finished project for part 4 here: https://github.com/TwistedTwigleg/Godot_FPS_Tutorial/tree/part_4
-         
-         The completed project has helpful comments every step of the way for almost every line of code!
-         
-         (Remember, you can download the completed project as a ZIP file if you want)
-         
-         .. image:: img/GithubDownloadZip.png
-
-If you want to see what is coming next, and what could be coming in the future, check out this issue on the repository: https://github.com/TwistedTwigleg/Godot_FPS_Tutorial/issues/6
-
-
-How to make ``Test_Level.tscn`` look cool!
-__________________________________________
-
-One quick thing! As noted by **MagicLord** from the Godot forums, you can make ``Test_Level.tscn`` look really cool with a little tweaking!
-
-If you change the roughness values down in the Spatial materials for the provided starter assets, you get this:
-
 .. image:: img/PartFourFinished.png
 
-.. note:: Huge thanks to **MagicLord** for sharing! (Credit for the picture goes to **MagicLord** as well!)
-
-All you have to do is lower the roughness (I found a value of ``0.1`` looks nice) in ``LevelAssets_SpatialMaterial.tres`` and ``LevelAssets_Transparent_SpatialMaterial.tres``,
-which you can find at ``assets/Level_assets``.
-
-.. note:: Remember, you have to hit the save button or your changes to ``LevelAssets_SpatialMaterial.tres`` and/or ``LevelAssets_Transparent_SpatialMaterial.tres``
-          will not be saved! The save icon looks like a little floppy disk!
+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.
 
-You can also turn on SSR (Screen Space Reflections) and/or use :ref:`reflection probes <class_ReflectionProbe>`
-as well! Turning up the metallic value a little can also give a more realistic look.
+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!
 
-In a later part we will likely change ``Test_Level.tscn`` a bit so the sky texture does not leak through the tiles before setting
-the material roughness down in the finished project.
+.. 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>`
 

+ 280 - 163
tutorials/3d/fps_tutorial/part_one.rst

@@ -10,13 +10,30 @@ Tutorial introduction
 
 This tutorial series will show you how to make a single player FPS game.
 
-Throughout the course of these tutorials, we will cover how:
+Throughout the course of this tutorial series, we will cover how:
 
-- To make a first person character, with sprinting and a flash light.
+- 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 a pistol, rifle, and knife to the first person character.
-- To add ammo and reloading to weapons that consume ammo.
+- 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`,
@@ -29,23 +46,22 @@ Throughout the course of these tutorials, we will cover how:
           This tutorial assumes you know have experience working with the Godot editor,
           have basic programming experience in GDScript, and have basic experience in game development.
 
-You can find the start assets for this parts 1 through 3 here: :download:`Godot_FPS_Starter.zip <files/Godot_FPS_Starter.zip>`
+You can find the start assets for this tutorial here: :download:`Godot_FPS_Starter.zip <files/Godot_FPS_Starter.zip>`
 
-.. warning:: A video version of this tutorial series is coming soon!
-
-The provided starter assets contain a animated 3D model, a bunch of 3D models for making levels,
+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 are created by me (TwistedTwigleg) unless otherwise noted, and are
-released under the ``MIT`` license.
+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``.
 
-.. note:: You can find the finished project for parts 1 through 3 at the bottom of
-          :ref:`doc_fps_tutorial_part_three`.
+.. tip:: You can find the finished project for each part at the bottom of each part's page
 
 Part Overview
 -------------
@@ -55,11 +71,10 @@ the environment.
 
 .. image:: img/PartOneFinished.png
 
-By the end of this part you will have a working first person character with a
-mouse based camera that can walk, jump, and sprint around the game environment in
-any direction
+By the end of this part you will have a working first person character who can move around the game environment,
+look around with a mouse based first person camera, that can jump into the air, turn on and off a flash light, and sprint.
 
-Getting everything setup
+Getting everything ready
 ------------------------
 Launch Godot and open up the project included in the starter assets.
 
@@ -71,191 +86,211 @@ First, go open the project settings and go to the "Input Map" tab. You'll find s
 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.
 
-While we still have the project settings open, quickly go check if MSAA (MultiSample Anti-Aliasing)
-is turned off. We want to make sure MSAA is off because otherwise we will get strange red lines
-between the tiles in our level later.
-
-.. tip:: The reason we get those red lines is because we are using lowpoly models
-        with low resolution textures. MSAA tries to reduce jagged edges between models and
-        because we are using lowpoly and low resolution textures in this project,
-        we need to turn it off to avoid texture bleeding.
-
-        A bonus with turning off MSAA is we get a more 'retro' looking result.
-
 _________
 
-Lets take a second to see what we have in the starter assets.
+Let's take a second to see what we have in the starter assets.
 
-Included in the starter assets are five scenes: ``BulletScene.tscn``, ``Player.tscn``,
-``SimpleAudioPlayer.tscn``, ``TestingArea.tscn``, and ``TestLevel.tscn``.
+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.
 
-We will visit all of these scenes later, but for now open up ``Player.tscn``.
+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 directly using them in this tutorial.
+          but we will not be exploring through ``Assets`` in this tutorial series. ``Assets`` contains all of 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 setup
+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 setup. Using a vertical pointing
+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 player will notice how 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 of the nodes we want to rotate on the ``X`` axis (up and down).
-The reason behind this is so we rotate ``Player`` on the ``Y`` axis, and ``Rotation_helper`` on
+Another thing to notice is how many nodes are children of ``Rotation_Helper``. This is because
+``Rotation_Helper`` contains all of 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:: If we did not use ``Rotation_helper`` then we'd likely have cases where we are rotating
           both the ``X`` and ``Y`` axes at the same time. This can lead to undesirable results, as we then
           could rotate 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``.
 
-Lets program our player by adding the ability to move around, look around with the mouse, and jump.
+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``:
 
 ::
 
     extends KinematicBody
 
-    const norm_grav = -24.8
+    const GRAVITY = -24.8
     var vel = Vector3()
     const MAX_SPEED = 20
     const JUMP_SPEED = 18
-    const ACCEL = 3.5
+    const ACCEL= 4.5
 
+    var dir = Vector3()
+    
     const DEACCEL= 16
     const MAX_SLOPE_ANGLE = 40
-
+    
     var camera
-    var camera_holder
-
-    # You may need to adjust depending on the sensitivity of your mouse
-    const MOUSE_SENSITIVITY = 0.05
-
-    var flashlight
-
+    var rotation_helper
+    
+    var MOUSE_SENSITIVITY = 0.05
+    
     func _ready():
-        camera = $Rotation_helper/Camera
-        camera_holder = $Rotation_helper
+        camera = $Rotation_Helper/Camera
+        rotation_helper = $Rotation_Helper
         
         Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-        
-        flashlight = $Rotation_helper/Flashlight
-
+    
     func _physics_process(delta):
-        var dir = Vector3()
+        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"):
-            dir += -cam_xform.basis.z.normalized()
+            input_movement_vector.y += 1
         if Input.is_action_pressed("movement_backward"):
-            dir += cam_xform.basis.z.normalized()
+            input_movement_vector.y -= 1
         if Input.is_action_pressed("movement_left"):
-            dir += -cam_xform.basis.x.normalized()
+            input_movement_vector.x -= 1
         if Input.is_action_pressed("movement_right"):
-            dir += cam_xform.basis.x.normalized()
-
+            input_movement_vector.x = 1
+        
+        input_movement_vector = input_movement_vector.normalized()
+        
+        dir += -cam_xform.basis.z.normalized() * input_movement_vector.y
+        dir += cam_xform.basis.x.normalized() * input_movement_vector.x
+        # ----------------------------------
+        
+        # ----------------------------------
+        # Jumping
         if is_on_floor():
             if Input.is_action_just_pressed("movement_jump"):
                 vel.y = JUMP_SPEED
-
-        if Input.is_action_just_pressed("flashlight"):
-    		if flashlight.is_visible_in_tree():
-    			flashlight.hide()
-    		else:
-    			flashlight.show()
-
+        # ----------------------------------
+        
+        # ----------------------------------
+        # 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()
-
-        var grav = norm_grav
-        vel.y += delta*grav
-
+        
+        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))
-
-        # (optional, but highly useful) 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 _input(event):
-        if event is InputEventMouseMotion && Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
-            camera_holder.rotate_x(deg2rad(event.relative.y * MOUSE_SENSITIVITY))
+        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 = camera_holder.rotation_degrees
+            
+            var camera_rot = rotation_helper.rotation_degrees
             camera_rot.x = clamp(camera_rot.x, -70, 70)
-            camera_holder.rotation_degrees = camera_rot
+            rotation_helper.rotation_degrees = camera_rot
+
+This is a lot of code, so let's break it down function by function:
 
-This is a lot of code, so let's break it down from top to bottom:
+.. 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 of 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 of the spaces into tabs. You can select "Convert Indent To Spaces" to convert t back into spaces.
 
 _________
 
 First, we define some global variables to dictate how our player will move about the world.
 
-.. note:: Throughout this tutorial, *variables defined outside functions will be
-          referred to as "global variables"*. This is because we can access any of these
+.. note:: Throughout this tutorial, **variables defined outside functions will be
+          referred to as "global variables"**. This is because we can access any of these
           variables from any place in the script. We can "globally" access them, hence the
           name.
 
-Lets go through each of the global variables:
+Let's go through each of the global variables:
 
-- ``norm_grav``: How strong gravity pulls us down while we are walking.
+- ``GRAV``: 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 fast we accelerate. The higher the value, the faster we get to max speed.
 - ``DEACCEL``: How fast we are going to decelerate. The higher the value, the faster we will come to a complete stop.
-- ``MAX_SLOPE_ANGLE``: The steepest angle we can climb.
+- ``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.
-- ``flashlight``: A :ref:`Spotlight <class_Spotlight>` node that will act as our player's flashlight.
 
-You can tweak many of these variables to get different results. For example, by lowering ``normal_gravity`` and/or
+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 is ``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 lets look at the ``_ready`` function:
+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.
+
+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 to 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 happen, we capture the mouse cursor.
@@ -263,21 +298,31 @@ would lose focus. To assure neither of these issues happen, we capture the mouse
 .. 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.
 
-We need to use ``_input`` so we can rotate the player and
-camera when there is mouse motion.
+_________
+
+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 of 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 of the date necessary to the :ref:`KinematicBody <class_KinematicBody>`
+so it can move through the game world.
 
 _________
 
-Next is ``_physics_process``:
+Let's look is ``process_movement`` next:
 
-We define a directional vector (``dir``) for storing the direction the player intends to move.
+First we set ``dir`` to an empty :ref:`Vector3 <class_Vector3>`.
 
-Next we get the camera's global transform and store it as well, into the ``cam_xform`` variable.
+``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``.
 
-Now we check for directional input. If we find that the player is moving, we get the ``camera``'s directional
-vector in the direction we are wanting to move towards and add (or subtract) it to ``dir``.
+Next we get the camera's global transform and store it as well, into the ``cam_xform`` variable.
 
-Many have found directional vectors confusing, so lets take a second to explain how they work:
+The reason we need the camera's global transform is so we can use it's directional vectors.
+Many have found directional vectors confusing, so let's take a second to explain how they work:
 
 _________
 
@@ -376,44 +421,72 @@ from the object's point of view, as opposed to using world vectors which give di
 
 _________
 
-Back to ``_physics_process``:
+Okay, back to ``process_input``:
 
-When the player pressed any of the directional movement actions, we get the local vector pointing in that direction
-and add it to ``dir``.
+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 so map the player's input to movement.
 
-.. note:: Because the camera is rotated by ``-180`` degrees, we have to flip the directional vectors.
+.. 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 or remove 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 where when we pressed forward or backwards we add the camera's
+local ``Z`` axis, so we move forward 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 when we press left or right, we move left/right in relation to the camera.
+
 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 our ``Y`` velocity to
 ``JUMP_SPEED``.
 
-Next we check if the flash light action was just pressed. If it was, we then check if the flash light
-is visible, or hidden. If it is visible, we hide it. If it is hidden, we make it visible.
+Because we're setting the Y velocity, we 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, then we capture it, and if it's not we make it visible (free it).
 
-Next we assure that our movement vector does not have any movement on the ``Y`` axis, and then we normalize it.
-We set a variable to our normal gravity and apply that gravity to our velocity.
+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 assure that ``dir`` does not have any movement on the ``Y`` axis by setting it's ``Y`` value to zero.
+
+Next we normalize ``dir`` to assure we're within a ``1`` radius unit circle. This makes it where we're moving at a constant speed regardless
+of whether we've moving straight, or moving diagonal. If we did not normalize, we would move faster on the diagonal than when we're going straight.
+
+Next we add gravity to our player by adding ``GRAVITY * delta`` to our ``Y`` velocity.
 
 After that we assign our velocity to a new variable (called ``hvel``) and remove any movement on the ``Y`` axis.
-Next we set a new variable (``target``) to our direction vector. Then we multiply that by our max speed
-so we know how far we will can move in the direction provided by ``dir``.
 
-After that we make a new variable for our acceleration, named ``accel``. We then take the dot product
-of ``hvel`` to see if we are moving according to ``hvel``. Remember, ``hvel`` does not have any
+Next we set a new variable (``target``) to our direction vector.
+Then we multiply that by our max speed so we know how far we will can move in the direction provided by ``dir``.
+
+After that we make a new variable for our acceleration, named ``accel``.
+
+We then take the dot product of ``hvel`` to see if we are moving according to ``hvel``. Remember, ``hvel`` does not have any
 ``Y`` velocity, meaning we are only checking if we are moving forwards, backwards, left, or right.
-If we are moving, then we set ``accel`` to our ``ACCEL`` constant so we accelerate, otherwise we set ``accel` to
-our ``DEACCEL`` constant so we decelerate.
 
-Finally, we interpolate our horizontal velocity, set our ``X`` and ``Z`` velocity to the interpolated horizontal velocity,
-and then call ``move_and_slide`` to let the :ref:`KinematicBody <class_KinematicBody>` handle moving through the physics world.
 
-.. tip:: All of the code in ``_physics_process`` is almost exactly the same as the movement code from the Kinematic Character demo!
-         The only thing that is different is how we use the directional vectors, and the flash light!
+If we are moving according to ``hvel``, then we set ``accel`` to our ``ACCEL`` constant so we accelerate, otherwise we set ``accel` to
+our ``DEACCEL`` constant so we decelerate.
+
+Then we interpolate our horizontal velocity, set our ``X`` and ``Z`` velocity to the interpolated horizontal velocity,
+and call ``move_and_slide`` to let the :ref:`KinematicBody <class_KinematicBody>` handle moving through the physics world.
 
-You can optionally add some code to capture and free the mouse cursor when "ui_cancel" is
-pressed. While entirely optional, it is highly recommended for debugging purposes.
+.. tip:: All of the code in ``process_movement`` is exactly the same as the movement code from the Kinematic Character demo!
 
 _________
 
@@ -422,11 +495,11 @@ The final function we have is the ``_input`` function, and thankfully it's fairl
 First we make sure that the event we are dealing with is a :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.
 
-.. tip:: See :ref:`Mouse and input coordinates <doc_mouse_and_input_coordinates>` for a list of
+.. 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 mouse motion provided by :ref:`InputEventMouseMotion <class_InputEventMouseMotion>`.
+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>`.
@@ -444,20 +517,24 @@ Then we rotate the entire :ref:`KinematicBody <class_KinematicBody>` on the ``Y`
 Finally, we clamp the ``rotation_helper``'s ``X`` rotation to be between ``-70`` and ``70``
 degrees so we cannot rotate ourselves 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
+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 tutorial, so be sure to keep it open in one of your scene tabs.
 
 Go ahead and test your code either by pressing ``F4`` with ``Testing_Area.tscn`` as the open tab, by pressing the
 play button in the top right corner, or by pressing ``F6``.
 You should now be able to walk around, jump in the air, and look around using the mouse.
 
-Giving the player the option to sprint
---------------------------------------
 
-Before we get to making the weapons work, there is one more thing we should add.
-Many FPS games have an option to sprint, and we can easily add sprinting to our player,
+Giving the player a flash light and the option to sprint
+--------------------------------------------------------
+
+Before we get to making the weapons work, there is a couple more things we should add.
+
+Many FPS games have an option to sprint and a flash light. We can easily add these to our player,
 so let's do that!
 
 First we need a few more global variables in our player script:
@@ -466,62 +543,102 @@ First we need a few more global variables in our player script:
 
     const MAX_SPRINT_SPEED = 30
     const SPRINT_ACCEL = 18
-    var is_sprinting = false
+    var is_spriting = false
+    
+    var flashlight
 
-All of these variables work exactly the same as the non sprinting variables with
-similar names. The only that's different is ``is_sprinting``, which is a boolean to track
-whether the player is currently sprinting.
+All of the sprinting variables work exactly the same as the non sprinting variables with
+similar names.
 
-Now we just need to change some of the code in our ``_physics_process`` function
-so we can add the ability to sprint.
+``is_sprinting`` is a boolean to track whether the player is currently sprinting, and ``flashlight`` is a variable
+we will be using to hold our flash light node.
 
-The first thing we need to do is add the following code, preferably by the other input related code:
+Now we just need to add a few lines of code, starting in ``_ready``. Add the following to ``_ready``:
 
 ::
+    
+    flashlight = $Rotation_Helper/Flashlight
 
+This gets our flash light 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``:
+
+::
+    
+    # ----------------------------------
+    # Sprinting
     if Input.is_action_pressed("movement_sprint"):
-        is_sprinting = true
+        is_spriting = true
     else:
-        is_sprinting = false;
+        is_spriting = false
+    # ----------------------------------
+    
+    # ----------------------------------
+    # Turning the flashlight on/off
+    if Input.is_action_just_pressed("flashlight"):
+        if flashlight.is_visible_in_tree():
+            flashlight.hide()
+        else:
+            flashlight.show()
+    # ----------------------------------
 
+Let's go over the additions:
 
-This will set ``is_sprinting`` to true when we are holding down the ``movement_sprint`` action, and false
-when the ``movement_sprint`` action is released.
+We set ``is_sprinting`` to true when we are 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're just going to change the ``is_sprinting`` variable.
 
-Next we need to set our max speed to the higher speed if we are sprinting, and we also need
-to change our acceleration to the new acceleration:
+We do something similar freeing/capturing the cursor for handling the flash light. 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.
 
-::
+_________
 
-    var target = dir
-    # NEW CODE. Replaces "target *= MAX_SPEED"
-    if is_sprinting:
+Now we just need to change a couple things in ``process_movement``. First, replace ``target *= MAX_SPEED`` with the following:
+
+::
+    
+    if is_spriting:
         target *= MAX_SPRINT_SPEED
     else:
         target *= MAX_SPEED
 
-    # Same code as before:
-    var accel
-    if dir.dot(hvel) > 0:
-        # New code. Replaces "accel = ACCEL"
-        if is_sprinting:
-            accel = SPRINT_ACCEL
-        else:
-            accel = ACCEL
+Now instead of always multiplying ``target`` by ``MAX_SPEED``, we first check to see if we are sprinting or not.
+If we are sprinting, we instead multiply ``target`` by ``MAX_SPRINT_SPEED``. 
+
+Now all that's left is changing the accleration when sprinting. Change ``accel = ACCEL`` to the following:
+
+::
+    
+    if is_spriting:
+        accel = SPRINT_ACCEL
     else:
-        accel = DEACCEL
+        accel = ACCEL
 
-Now you should be able to sprint if you press the shift button! Go give it a
-whirl! You can change the sprint related global variables to make the player faster when sprinting!
+
+Now when we are sprinting we'll use ``SPRINT_ACCEL`` instead of ``ACCEL``, which will accelerate us faster.        
+
+_________
+
+You should now be able to sprint if you press the ``shift`` button, and can toggle the flash light on and off by pressing the ``F`` button!
+
+Go give it a whirl! You can change the sprint related global variables to make the player faster or slower when sprinting!
+
+Final notes
+-----------
+
+.. image:: img/PartOneFinished.png
 
 Phew! 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 with sprinting!
+.. 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 also
-             download the finished project at the bottom of :ref:`doc_fps_tutorial_part_three`.
+.. 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>`

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

@@ -0,0 +1,1019 @@
+.. _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
+
+.. error:: TODO: replace this image
+
+.. 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_four` will be the starting project for part 6
+          
+Let's get started!
+
+Adding the main menu
+--------------------
+
+First, 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 just a camera looking around the skybox, nothing fancy.
+
+Feel free to expand all of the nodes and see how their set up. Just 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 really 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 global 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``
+
+First we get all of the :ref:`Panel <class_Panel>` nodes and assign them to the proper variables.
+
+Next we connect all of 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 we return to this scene our 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_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 engine 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 so we return to the main menu.
+
+If one of the scene changing buttons are pressed, we fist call ``set_mouse_and_joypad_sensitivity`` so our singleton has the values from the :ref:`HSlider <class_HSlider>` nodes.
+Then we tell the singleton to change nodes using it's ``load_new_scene`` function, passing in the file path of the scene we're wanting to change to.
+
+.. 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 so we 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 it's 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``.
+
+First we get the ``Globals`` singleton and assign it to a local variable.
+
+We then set the ``mouse_sensitivity`` and ``joypad_sensitvity`` variables to the values in their respective :ref:`HSlider <class_HSlider>` node counterparts.
+
+Making the ``Globals`` singleton
+--------------------------------
+
+Now, for this all to work we really need to make the ``Globals`` singleton. Make a new script in the ``Script`` tab and call it ``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 really quite small and simple. As this part progresses we will
+keeping adding complexities to ``Global.gd``, but for now all it really is doing is holding two variables for us, and abstracting 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're using ``Globals.gd`` for is a way to carry variables across scenes. Because the sensitivity for our mouse and joypad are
+stored in ``Globals.gd``, any changes we make in one scene (like ``Main_Menu``) effect the sensitivity for our 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 of 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 the picture above, then press ``Add``!
+
+This will make ``Globals.gd`` a singleton/autoload script, which will allow us to access it from anywhere 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 also want to change the main scene from ``Testing_Area.tscn`` to ``Main_Menu.tscn`` so when we export the game we 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 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 the game is running at, one for showing what OS the game is running on, and a label for showing the Godot version the game is running with.
+
+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 in :ref:`OS <class_OS>` using the ``get_name`` function. This will return the
+name of the OS (or Operating System) that Godot was compiled for. 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 Godot is currently running with. We only care for the string version for the purposes of this display, 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 a int, we have to cast
+it to a string using ``str`` before we can add it to our 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 in our singleton called ``set_debug_display``, so let's add that next!
+
+______
+
+Open up ``Globals.gd`` and add the following global variables:
+
+::
+    
+    # ------------------------------------
+    # All of 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 our GUI/UI 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 there is one.
+
+Now that we have our global variables defined, we need to add a few lines to ready so we have a canvas layer to use in ``canvas_layer``.
+Change ``_ready`` to the following:
+
+::
+    
+    func _ready():
+        canvas_layer = CanvasLayer.new()
+        add_child(canvas_layer)
+
+Now in ``_ready`` we're creating a new canvas layer and adding it as a child of the autoload script.
+
+The reason we're adding a :ref:`CanvasLayer <class_CanvasLayer>` is so all of 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 scene, meaning you can run into memory problems if you are
+instancing/spawning lots of nodes and are not freeing them.
+
+______
+        
+Now we just 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 we're trying to turn on the debug display, or turn it off.
+
+If we are 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 we
+most have a debug display currently active. If we have a debug display active, we free it using ``queue_free`` and then assign ``debug_display`` to ``null``.
+
+If we are turning on the display, we then check to make sure we 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 where 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, lets 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 be needed to receive a couple signals in ``Globals.gd``, we'll write all of the code for
+the pop up there.
+
+Open up ``Globals.gd`` and add the following global 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 we 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.
+
+______
+
+First we check to see if the ``ui_cancel`` action is pressed. Then we check to make sure we do not already
+have a ``popup`` open by checking to see if ``popup`` is equal to ``null``.
+
+If we do not have a pop up open, we instance ``POPUP_SCENE`` and assign it to ``popup``.
+
+We then get the quit button and assign it's ``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`` to we can interact with the pop up. If we did not do this, we would not be able to interact with the pop up
+in any scene where the mouse mode is ``MOUSE_MODE_CAPTURED``.
+
+Finally, get 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 we've connected the signals to. 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 very 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:
+
+::
+    
+    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 to see if 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 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 our player can lose all their health, it would be ideal if our players died and respawned too, so let's add that!
+
+First, open up ``Player.tscn`` and expand ``HUD``. Notice how there's 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 they're able to respawn.
+
+Open up ``Player.gd`` and add the following global 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``. 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 our global position
+using the origin from our global :ref:`Transform <class_Transform>` to the position returned by ``globals.get_respawn_position``.
+
+.. note:: Don't worry, we'll add ``get_respawn_position`` further below!
+    
+______
+    
+Next we need to make a few changes to ``physics_process``. Change ``physics_processing`` 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 we're not processing input or movement input when we're dead. We're also now calling ``process_respawn``, but we haven't written
+``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 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.
+
+______
+
+First we check to see if we just died by checking to see if ``health`` is equal or less than ``0`` and ``is_dead`` is ``false``.
+
+If we just died, we disable our collision shapes for the player. We do this to make sure we're not blocking anything with our dead body.
+
+We next set ``changing_weapon`` to ``true`` and set ``changing_weapon_name`` to ``UNARMED``. This is so if we are using a weapon, we put it away
+when we die.
+
+We then make the ``Death_Screen`` :ref:`ColorRect <class_ColorRect>` visible so we get a nice grey overlay over everything. 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 we've been dead. We also set ``is_dead`` to ``true`` so we know we've died.
+
+If we are holding an object when we died, we need to throw it. We first check to see if we are holding an object or not. If we are, we then throw it,
+using the same code as the throwing code we added in :ref:`doc_fps_tutorial_part_five`.
+
+______
+
+Then we check to see if we are dead. If we are, 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
+us a nice looking string showing how much time we have left to wait before we respawn.
+
+We then change the :ref:`Label <class_Label>` in ``Death_Screen`` to show how much time we have left.
+
+Next we check to see if we've waited long enough and can respawn. We do this by checking to see if ``dead_time`` is ``0`` or less.
+
+If we have 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 our collision shapes so the player can collide 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 it's ``reset_weapon`` function. We'll add ``reset_weapon`` soon.
+
+Then we reset ``health`` to ``100``, ``grenade_amounts`` to it's default values, and change ``current_grenade`` to ``Grenade``.
+
+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 we're dead we cannot look around with the mouse.
+
+Finishing the respawn system
+----------------------------
+
+First 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 our weapon 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 our weapons will reset when we die.
+
+______
+
+Now we need to add a few things to ``Globals.gd``. First, add the following global variable:
+
+::
+    
+    var respawn_points = null
+
+* ``respawn_points``: A variable to hold all of 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 using 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.
+
+______
+
+First we check to see if we have any ``respawn_points`` by checking to see if ``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're 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 we get to a level with no respawn points, we do not respawn
+at the respawn points 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 it's ``_ready`` function called, all of the children
+nodes of the node with ``Respawn_Point_Setter.gd``, ``Spawn_Points`` in the case of ``Ruins_Level.tscn``, we 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 you die you'll 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, lets make a sound system so we can play sounds from anywhere, without having to use the player.
+
+First, 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 a AudioPlayer3D, then uncomment these lines to set the position.
+        # 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's several changes from the old version, first and foremost being we're 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're forcing a audio stream to be passed
+in to ``play_sound``.
+
+Another change is we have a new global variable called ``should_loop``. Instead of just destroying the audio player every time it's finished, we instead want check to
+see if we are 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``, we're instead going to be spawned in ``Globals.gd`` so we can create sounds from any scene. We now need
+to store the ``Globals.gd`` singleton so when we destroy the audio player, we also remove it from a list in ``Globals.gd``.
+
+Let's go over the changes.
+
+______
+
+For the global variables
+we removed all of the ``audio_[insert name here]`` variables since we will instead have these passed in to.
+We also added two new global variables, ``should_loop`` and ``globals``. We'll use ``should_loop`` to tell whether we want to loop when the sound has
+finished, and ``globals`` will hold the ``Globals.gd`` singleton.
+
+The only change in ``_ready`` is now we're getting the ``Globals.gd`` singleton and assigning it to ``globals``
+
+In ``play_sound`` we now expect a 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 a audio stream is 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 we are supposed to loop or not using ``should_loop``. If we are supposed to loop, we play the sound
+again from the start of the audio, at position ``0.0``. If we are 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 global variables:
+
+::
+    
+    # ------------------------------------
+    # All of 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 = []
+    # ------------------------------------
+
+Lets go over these global variables.
+
+* ``audio_clips``: A dictionary holding all of the audio clips we can play.
+* ``SIMPLE_AUDIO_PLAYER_SCENE``: The simple audio player scene.
+* ``created_audio``: A list to hold all of the simple audio players we create
+
+.. note:: If you want to add additional audio, you just 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 script does.
+
+First we check to see if we have a audio clip with the name ``sound_name`` in ``audio_clips``. If we do not, we print an error message.
+
+If we do have a 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 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 we change scenes, we destroy all of the audio.
+
+Add the following to ``load_new_scene``:
+
+::
+    
+    for sound in created_audio:
+        if (sound != null):
+            sound.queue_free()
+    created_audio.clear()
+    
+Now before we change scenes we go through each simple audio player in ``created_sounds`` and free/destroy them. Once we've gone through
+all of the sounds in ``created_audio``, we clear ``created_audio`` so it no longer holds any references to any of the previously created 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 global variables, since we will
+no longer be directly instancing/spawning sounds from ``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 of the arguments we've revived.
+
+______
+
+Now all of 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``, passing in the name of the sound
+we want to play, whether we want it to loop or not, and the position to play the sound from.
+
+For example, if you want to play an explosion sound when the grenades explode 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 of the bodies within it's 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_5.zip <files/Godot_FPS_Finished.zip>`
+
+.. note:: The finished project source files contain the same exact 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 on the documentation**.
+         
+         The code in the documentation is likely better managed and/or more up to date.
+         If you are unsure on which to use, use the project(s) provided in the documentation as they are maintained by the Godot community.
+
+You can download all of 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 convert 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.**
+

+ 405 - 423
tutorials/3d/fps_tutorial/part_three.rst

@@ -6,16 +6,18 @@ Part 3
 Part Overview
 -------------
 
-In this part we will be limiting our guns by giving them ammo. We will also
+In this part we will be limiting our weapons by giving them ammo. We will also
 be giving the player the ability to reload, and we will be adding sounds when the
-guns fire.
+weapons fire.
 
 .. image:: img/PartThreeFinished.png
 
 By the end of this part, the player will have limited ammo, the ability to reload,
 and sounds will play when the player fires and changes weapons.
 
-.. note:: You are assumed to have finished :ref:`part two <doc_fps_tutorial_part_two>` before moving on to this part of the tutorial.
+.. 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!
 
@@ -23,352 +25,438 @@ 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 ``Test_Level.tscn``.
-``Test_Level.tscn`` is a complete custom FPS level created for the purpose of this tutorial. Press ``F6`` to
-play the open scene, or press the "play current scene button", and give it a whirl.
+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 ``F6`` to
+play the open scene, or press the ``play current scene button``, and give it them a whirl.
+
+.. 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.
+
+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
+
+    Expand "Other_Objects" and then expand "Turrets_And_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 "Box_Rigid_Body" and open it using the
+    "Open in Editor" button.
+    This will bring you to the "Box_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".
+    
+ 
+ .. code-tab:: gdscript Ruins_Level
+
+    Expand "Misc_Objects" and then expand "Physics_Objects".
+    
+    Select all of 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 back to "Ruins_Level.tscn".
+
+Now you can fire at all of the rigid bodies in either level!
 
-.. warning:: There will (likely) be the occasional random freeze as you go through the level. This is a known
-             issue.
+Adding ammo
+-----------
 
-             If you find any way to solve it, please let me know on the Github repository, the Godot forums,
-             or on Twitter! Be sure to include ``@TwistedTwigleg`` so I will have a greater chance of seeing it!
+Now that we've got working guns, let's give them a limited amount of ammo.
 
-You might have noticed there are several boxes and cylinders placed throughout the level. They are :ref:`RigidBody <class_RigidBody>`
-nodes we can place ``RigidBody_hit_test.gd`` on and then they will react to being hit with bullets, so lets do that!
+First we need to define a few variables in each of our weapon scripts.
 
-Select ``Center_room`` and open it up. From there select ``Physics_objects`` and open that up. You'll find there are
-``6`` crates in a seemingly random order. Go select one of them and press the "Open in Editor" button. It's the one that
-looks like a little movie slide.
+Open up ``Weapon_Pistol.gd`` and add the following global variables:
 
-.. note:: The reason the objects seem to be placed in a random order is because all of the objects were copied and pasted around
-          in the Godot editor to save on time. If you want to move any of the nodes around, it is highly suggested to just
-          left click inside the editor viewport to get the node you want, and then move it around with the :ref:`Spatial <class_Spatial>` gizmo.
+::
+    
+    var ammo_in_weapon = 10
+    var spare_ammo = 20
+    const AMMO_IN_MAG = 10
 
-This will bring you to the crate's scene. From there, select the ``Crate`` :ref:`RigidBody <class_RigidBody>` (the one that is the root of the scene)
-and scroll down in the inspector until you get to the script section. From there, click the drop down and select "Load". Chose
-``RigidBody_hit_test.gd`` and then return to ``Test_Level.tscn``.
+* ``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 reload weapon/magazine
 
-Now open ``Upper_room``, select ``Physics_objects``, and chose one of the cylinder :ref:`RigidBody <class_RigidBody>` nodes.
-Press the "Open in Editor" button beside one of the cylinders. This will bring you to the cylinder's scene.
+Now all we need to do is add a single line of code to ``fire_weapon``.
 
-From there, select the ``Cylinder`` :ref:`RigidBody <class_RigidBody>` (the one that is the root of the scene)
-and scroll down in the inspector until you get to the script section. From there, click the drop down and select "Load". Chose
-``RigidBody_hit_test.gd`` and then return to ``Test_Level.tscn``.
+Add the following right under ``Clone.BULLET_DAMAGE = DAMAGE``: ``ammo_in_weapon -= 1``
 
-Now you can fire at the boxes and cylinders and they will react to your bullets just like the cubes in ``Testing_Area.tscn``!
+This will remove one from ``ammo_in_weapon`` every time we fire. Notice we're not checking to see
+if we have ammo count of ``0`` or greater in ``fire_weapon``. Instead we're going to check that the ammo count in ``Player.gd``.
 
+_______
 
-Adding ammo
------------
+Now we need to add ammo for both the rifle and the knife.
 
-Now that we've got working guns, lets give them a limited amount of ammo.
+.. 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 of 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 all our weapons have the same variables.
 
-Lets define some more global variables in ``Player.gd``, ideally nearby the other gun related variables:
+Add the following global variables to ``Weapon_Rifle.gd``:
 
 ::
+    
+    var ammo_in_weapon = 50
+    var spare_ammo = 100
+    const AMMO_IN_MAG = 50
 
-    var ammo_for_guns = {"PISTOL":60, "RIFLE":160, "KNIFE":1}
-    var ammo_in_guns = {"PISTOL":20, "RIFLE":80, "KNIFE":1}
-    const AMMO_IN_MAGS = {"PISTOL":20, "RIFLE":80, "KNIFE":1}
-
-
-Here is what these variables will be doing for us:
+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
+we lost ammo regardless of whether we've hit something or not.
 
-- ``ammo_for_guns``: The amount of ammo we have in reserve for each weapon/gun.
-- ``ammo_in_guns``: The amount of ammo currently inside the weapon/gun.
-- ``AMMO_IN_MAGS``: How much ammo is in a fully filled weapon/gun.
+Now all that's left is the knife. Add the following to ``Weapon_Knife.gd``:
 
-.. note:: There is no reason we've included ammo for the knife, so feel free to remove the knife's ammo
-          if you desire.
+::
+    
+    var ammo_in_weapon = 1
+    var spare_ammo = 1
+    const AMMO_IN_MAG = 1
 
-          Depending on how you program melee weapons, you may need to define an ammo count even if the
-          weapon does not use ammo. Some games use extremely short range 'guns' as their melee weapons,
-          and in those cases you may need to define ammo for your melee weapons.
+And because our knife does not consume ammo, that is all we need to add.
 
-_________
+_______
 
-Now we need to add a few ``if`` checks to ``_physics_process``.
+Now all we need to do is change a one thing in ``Player.gd``.
 
-We need to make sure we have ammo in our gun before we try to fire a bullet.
-Go find the line that checks for the fire action being pressed and add the following new
-bits of code:
+All we need to change how we're firing our weapons in ``process_input``. Change the code for firing weapons to the following:
 
 ::
-
-    # NOTE: You should have this if condition in your _physics_process function
+    
+    # ----------------------------------
     # Firing the weapons
     if Input.is_action_pressed("fire"):
-        if current_gun == "PISTOL":
-            if ammo_in_guns["PISTOL"] > 0: # NEW CODE
-                if animation_manager.current_state == "Pistol_idle":
-                    animation_manager.set_animation("Pistol_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 our weapons have a limited amount of ammo, and will stop firing when we run out.
 
-        elif current_gun == "RIFLE":
-            if ammo_in_guns["RIFLE"] > 0: # NEW CODE
-                if animation_manager.current_state == "Rifle_idle":
-                    animation_manager.set_animation("Rifle_fire")
+_______
 
-        elif current_gun == "KNIFE":
-            if animation_manager.current_state == "Knife_idle":
-                animation_manager.set_animation("Knife_fire")
+Ideally we'd like to be able to see how much ammo we have left. Let's make a new function called ``process_ui``.
 
-These two additional ``if`` checks make sure we have a bullet to fire before setting our firing animation.
+First, add ``process_UI(delta)`` to ``_physics_process``.
 
-While we're still in ``_physics_process``, let's also add a way to track how much ammo we have. Find the line that
-has ``UI_status_label.text = "HEALTH: " + str(health)`` in ``_physics_process`` and replace it with the following:
+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)
 
-    # HUD (UI)
-    if current_gun == "UNARMED" or current_gun == "KNIFE":
-        UI_status_label.text = "HEALTH: " + str(health)
-    else:
-        UI_status_label.text = "HEALTH: " + str(health) + "\nAMMO:" + \
-            str(ammo_in_guns[current_gun]) + "/" + str(ammo_for_guns[current_gun])
+Let's go over what's happening:
 
-.. tip:: Did you now that you can combine two lines using ``\``? We're using it here
-         so we do not have a extremely long line of code all on one line by splitting it
-         into two lines!
+First 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 our health, since ``UNARMED`` and ``KNIFE`` do not consume ammo.
 
-This will show the player how much ammo they currently have and how much ammo they currently have in reserve, only for
-the appropriate weapons (not unarmed or the knife). Regardless of the currently selected weapon/gun, we will always show
-how much health the player has
+If we are using a weapon that does consume ammo, we first get the weapon node.
 
-.. note:: we cannot just add ``ammo_for_guns[current_gun]`` or ``ammo_in_guns[current_gun]`` to the ``string`` we
-          are passing in to the :ref:`Label <class_Label>`. Instead we have to cast them from ``floats`` to ``strings``, which is what we are doing
-          by using ``str()``.
+Then change ``UI_status_label``'s text to show our health, how much ammo we have in the weapon,
+along with how much spare ammo we have for that weapon.
 
-          For more information on casting, see this page from wiki books:
-          https://en.wikibooks.org/wiki/Computer_Programming/Type_conversion
 
-.. warning:: We are currently not using the player's health just yet in the tutorial. We will start
-             using health for the player and objects when we include turrets and targets in later parts.
+Now we can see how much ammo we have through the HUD.
 
+Adding reloading to the weapons
+-------------------------------
 
-Now we need to remove a bullet from the gun when we fire. To do that, we just need to add a few lines in
-``fire_bullet``:
+Now that we can run our weapons out of ammo, we really need a way to 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.
 
-    func fire_bullet():
-        if changing_gun == true:
-            return
+Open up ``Weapon_Pistol.gd`` and add the following global variables:
 
-        # Pistol bullet handling: Spawn a bullet object!
-        if current_gun == "PISTOL":
-            var clone = bullet_scene.instance()
-            var scene_root = get_tree().root.get_children()[0]
-            scene_root.add_child(clone)
+::
+    
+    const CAN_RELOAD = true
+    const CAN_REFILL = true
+    
+    const RELOADING_ANIM_NAME = "Pistol_reload"
 
-            clone.global_transform = $Rotation_helper/Gun_fire_points/Pistol_point.global_transform
-            # The bullet is a little too small (by default), so let's make it bigger!
-            clone.scale = Vector3(4, 4, 4)
+* ``CAN_RELOAD``: A boolean to track whether this weapon has the ability to reload
+* ``CAN_REFIL``: A boolean to track whether we can refill this weapon's spare ammo. We will not be using ``CAN_REFIL`` in this part, but we will in the next part!
+* ``RELOADING_ANIM_NAME``: The name of the reloading animation for this weapon.
 
-            ammo_in_guns["PISTOL"] -= 1 # NEW CODE
+Now we need to add a function for handling reloading. Add the following function to ``Weapon_Pistol.gd``:
 
-        # Rifle bullet handeling: Send a raycast!
-        elif current_gun == "RIFLE":
-                var ray = $Rotation_helper/Gun_fire_points/Rifle_point/RayCast
-                ray.force_raycast_update()
+::
+    
+    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:
 
-                if ray.is_colliding():
-                    var body = ray.get_collider()
-                    if body.has_method("bullet_hit"):
-                        body.bullet_hit(RIFLE_DAMAGE, ray.get_collision_point())
+First we define a variable to see whether or not we can reload.
 
-                ammo_in_guns["RIFLE"] -= 1 # NEW CODE
+We first check to see if we are in this weapon's idle animation state because we only want to be able to reload when we are not
+firing. equipping, or unequipping.
 
-        # Knife bullet(?) handeling: Use an area!
-        elif current_gun == "KNIFE":
-            var area = $Rotation_helper/Gun_fire_points/Knife_point/Area
-            var bodies = area.get_overlapping_bodies()
+Next we check to see if we have spare ammo, and if the ammo already in our weapon is equal to a fully reloaded weapon.
+This way we can assure we're not going to reload when we have no ammo or when the weapon is already full of ammo.
 
-            for body in bodies:
-                if body.has_method("bullet_hit"):
-                    body.bullet_hit(KNIFE_DAMAGE, area.global_transform.origin)
+If we still can reload, then we calculate the amount of ammo needed to reload the weapon.
 
+If we have 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.
 
-Go play the project again! Now you'll lose ammo as you fire, until you reach zero and
-cannot fire anymore.
+If we do not have enough ammo, we add all of the ammo left in ``spare_ammo``, then set ``spare_ammo`` to ``0``.
 
-Adding reloading
-----------------
+Next we play the reloading animation for this weapon, and then return ``true``.
 
-Now that we can empty our gun, we need a way to refill it!
+If we could not reload, we return ``false``.
 
-First, let's start by
-adding another global variable. Add ``var reloading_gun = false`` somewhere along with your
-other global variables, preferably near the other gun related variables.
+_______
 
-_________
+Now we need to add reloading to the rifle. Open up ``Weapon_Rifle.gd`` and add the following global variables:
 
-Now we need to add several things to ``_physics_process``.
+::
+    
+    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.
 
-First, let's make sure we cannot change guns while reloading.
-We need to change the weapon changing code to include the following:
+Now we just 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
 
-    # Was "if changing_gun == false"
-    if changing_gun == false and reloading_gun == false:
-        if Input.is_key_pressed(KEY_1):
-            current_gun = "UNARMED"
-            changing_gun = true
-        elif Input.is_key_pressed(KEY_2):
-            current_gun = "KNIFE"
-            changing_gun = true
-        elif Input.is_key_pressed(KEY_3):
-            current_gun = "PISTOL"
-            changing_gun = true
-        elif Input.is_key_pressed(KEY_4):
-            current_gun = "RIFLE"
-            changing_gun = true
-
-Now the player cannot change guns while reloading.
+This code is exactly the same as the pistol.
 
-_________
+_______
 
-Ideally we want the player to be able to reload when they chose, so lets given them
-the ability to reload when they press the ``reload`` action. Add the following
-somewhere in ``_physics_process``, ideally nearby your other input related code:
+The last bit we need to do for the weapons is add 'reloading' to the knife. Add the following global variables to ``Weapon_Knife.gd``:
 
 ::
+    
+    const CAN_RELOAD = false
+    const CAN_REFILL = false
 
-    # Reloading
-    if reloading_gun == false:
-        if Input.is_action_just_pressed("reload"):
-            if current_gun == "PISTOL" or current_gun == "RIFLE"
-                if animation_manager.current_state != "Pistol_reload" and animation_manager.current_state != "Rifle_reload":
-                    reloading_gun = true
+    const RELOADING_ANIM_NAME = ""
 
-First we see if the player is already reloading. If they are not, then we check if they've pressed
-the reloading action. If they have pressed the ``reload`` action, we then check if they are using
-a weapon that has the ability to be reloaded. Finally, we make sure they are not already
-in a reloading animation. If they are not, we set ``reloading_gun`` to ``true``.
+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.
 
-We do not want to do our reloading processing here with the input in an effort to keep game logic
-separate from input logic. Keeping them separate makes the code easier to debug, and as a bonus it
-keeps the input logic from being overly bloated.
+Now we just need to add ``reloading_weapon``, and thankfully it's really simple:
 
-_________
+::
+    
+    func reload_weapon():
+        return false
 
-Finally, we need to add the code that actually handles reloading. Add the following code to ``_physics_process``,
-ideally somewhere underneath the reloading input code you just inputted:
+Since we cannot reload a knife, we just always return ``false``.
 
-::
+Adding reloading to the player
+------------------------------
 
-    # Reloading logic
-    if reloading_gun == true:
-        var can_reload = false
+Now we just need to add a few things to ``Player.gd``. First we need to define a new global variable:
 
-        if current_gun == "PISTOL":
-            if animation_manager.current_state == "Pistol_idle":
-                can_reload = true
-        elif current_gun == "RIFLE":
-            if animation_manager.current_state == "Rifle_idle":
-                can_reload = true
-        elif current_gun == "KNIFE":
-            can_reload = false
-            reloading_gun = false
-        else:
-            can_reload = false
-            reloading_gun = false
+::
+    
+    var reloading_weapon = false
+    
+* ``reloading_weapon``: A variable to track whether or not we are currently trying to reload.
 
-        if ammo_for_guns[current_gun] <= 0 or ammo_in_guns[current_gun] == AMMO_IN_MAGS[current_gun]:
-            can_reload = false
-            reloading_gun = false
 
+Next we need to add another function call to ``_physics_process``.
 
-        if can_reload == true:
-            var ammo_needed = AMMO_IN_MAGS[current_gun] - ammo_in_guns[current_gun]
+Add ``process_reloading(delta)`` to ``_physics_process``. Now ``_physics_process`` should look something like this:
 
-            if ammo_for_guns[current_gun] >= ammo_needed:
-                ammo_for_guns[current_gun] -= ammo_needed
-                ammo_in_guns[current_gun] = AMMO_IN_MAGS[current_gun]
-            else:
-                ammo_in_guns[current_gun] += ammo_for_guns[current_gun]
-                ammo_for_guns[current_gun] = 0
+::
+    
+    func _physics_process(delta):
+        process_input(delta)
+        process_movement(delta)
+        process_changing_weapons(delta)
+        process_reloading(delta)
+        process_UI(delta)
 
-            if current_gun == "PISTOL":
-                animation_manager.set_animation("Pistol_reload")
-            elif current_gun == "RIFLE":
-                animation_manager.set_animation("Rifle_reload")
+Now we need to add ``process_reloading``. Add the following function to ``Player.gd``:
 
-            reloading_gun = false
+::
+    
+    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.
 
-Lets go over what this code does.
+First we check to make sure we are trying to reload.
 
-_________
+If we are, we then get the current weapon. If the current weapon does not equal ``null``, we call its ``reload_weapon`` function.
 
-First we check if ``reloading_gun`` is ``true``. If it is we then go through a series of checks
-to see if we can reload or not. We use ``can_reload`` as a variable to track whether or not
-it is possible to reload.
+.. note:: If the current weapon is equal to ``null``, then the current weapon is ``UNARMED``.
 
-We go through series of checks for each weapon. For the pistol and the rifle we check if
-we're in an idle state or not. If we are, then we set ``can_reload`` to ``true``.
+Finally, we set ``reloading_weapon`` to ``false``, because regardless of whether we've successfully reloaded, we've tried reloading
+and no longer need to keep trying.
 
-For the knife we do not want to reload, because you cannot reload a knife, so we set ``can_reload`` and ``reloading_gun``
-to ``false``. If we are using a weapon that we do not have a ``if`` or ``elif`` check for, we set
-``can_reload`` and ``reloading_gun`` to ``false``, as we do not want to be able to reload a weapon we are unaware of.
+_______
 
-Next we check if we have ammo in reserve for the gun in question. We also check to make sure the gun we are trying to reload
-is not already full of ammo. If the gun does not have ammo in reserve or the gun is already full, we set
-``can_reload`` and ``reloading_gun`` to ``false``.
+Before we can reload, we need to change a few things in ``process_input``.
 
-If we've made it through all those checks and we can reload, then we have a few more steps to take.
+The first thing we need to change is in the code for changing weapons. We need to add a additional check (``if reloading_weapon == false:``) to see if we are reloading:
 
-First we assign the ammo we are needing to fill the gun fully to the ``ammo_needed`` variable.
-We just subtract the amount of ammo we currently have in our gun by the amount of ammo in a full magazine.
+::
+    
+    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
 
-Then we check if have enough ammo in reserves to fill the gun fully. If we do, we subtract the amount of ammo
-we need to refill our gun from the reserves, and we set the amount of ammo in the gun to full.
+This makes it where we cannot change weapons if we are reloading.
 
-If we do not have enough ammo in reserves to fill the gun, we add all of the ammo left in reserves to our
-gun and then set the ammo in reserves to zero, making it empty.
+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``:
 
-Regardless of how much ammo we've added to the gun, we set our animation to the reloading animation for the current gun.
+::
+    
+    # ----------------------------------
+    # 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
+    # ----------------------------------
 
-Finally, we set ``reloading_gun`` to false because we have finished reloading the gun.
+Let's go over what's happening here.
 
-_________
+First we make sure we're not reloading already, nor are we trying to change weapons.
 
-Go test the project again, and you'll find you can reload your gun when it is not
-full and when there is ammo left in the ammo reserves.
+Then we check to see if the ``reload`` action has been pressed.
 
-_________
+If we have pressed ``reload``, we then get the current weapon and check to make sure it is not ``null``. Then we check to see if the
+weapon can reload or not using its ``CAN_RELOAD`` constant.
 
-Personally, I like the guns to automatically start reloading if we try to fire them
-when they have no ammo in them, so lets add that! Add the following code to the input code for
-firing the guns:
+If the weapon can reload, we then get the current animation state, and make a variable for tracking whether we are already reloading or not.
 
-::
+We then go through every weapon to make sure we're not already playing that weapon's reloading animation.
 
-    # Firing the weapons
-    if Input.is_action_pressed("fire"):
-        if current_gun == "PISTOL":
-            if ammo_in_guns["PISTOL"] > 0:
-                if animation_manager.current_state == "Pistol_idle":
-                    animation_manager.set_animation("Pistol_fire")
-            # NEW CODE!
-            else:
-                reloading_gun = true
+If we are not reloading with any weapon, we set ``reloading_weapon`` to ``true``.
 
-        elif current_gun == "RIFLE":
-            if ammo_in_guns["RIFLE"] > 0:
-                if animation_manager.current_state == "Rifle_idle":
-                    animation_manager.set_animation("Rifle_fire")
-            # NEW CODE!
-            else:
-                reloading_gun = true
+_______
+
+One thing I like to add is where the weapon will reload itself if you try to fire it when it's out of ammo.
 
-        elif current_gun == "KNIFE":
-            if animation_manager.current_state == "Knife_idle":
-                animation_manager.set_animation("Knife_fire")
+We also need to add a additional if check (``is_reloading_weapon == false:``) so we cannot fire the current weapon while
+reloading.
 
-Now whenever the player tries to fire the gun when it's empty, we automatically
-set ``reloading_gun`` to true, which will reload the gun if possible.
+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 we're not reloading before we fire out weapon, and when we have ``0`` or less ammo in our weapon
+we set ``reloading_weapon`` to ``true`` if we try to fire.
+
+This will make it where we will try to reload when we try to fire a empty weapon.
+    
+_______
+    
+With that we can reload our weapons! Give it a try! Now you can fire all of the spare ammo for each weapon.
+    
 Adding sounds
 -------------
 
@@ -379,23 +467,20 @@ are firing them.
          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.
 
-         The video tutorial will briefly show how to edit the audio files for use in the tutorial.
-
-Open up ``SimpleAudioPlayer.tscn``. It is simply a :ref:`Spatial <class_Spatial>` with a :ref:'AudioStreamPlayer <class_AudioStreamPlayer>' as it's child.
+Open up ``SimpleAudioPlayer.tscn``. It is simply a :ref:`Spatial <class_Spatial>` with a :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` as it's 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. This will likely change
-          in a future part.
+          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".
+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
+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 "SimpleAudioPlayer.gd". Attach it to the :ref:`Spatial <class_Spatial>` in ``SimpleAudioPlayer.tscn``
+Create a new script and call it ``SimpleAudioPlayer.gd``. Attach it to the :ref:`Spatial <class_Spatial>` in ``SimpleAudioPlayer.tscn``
 and insert the following code:
 
 ::
@@ -411,12 +496,18 @@ and insert the following code:
     var audio_node = null
 
     func _ready():
-        audio_node = $AudioStreamPlayer
+        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":
@@ -441,35 +532,36 @@ and insert the following code:
 
 
 .. 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 the ``play_sound``.
+         meaning ``position`` doesn't necessarily have to be passed in to call the ``play_sound``.
 
 Let's go over what's happening here:
 
 _________
 
-In ``_ready`` we get the :ref:'AudioStreamPlayer <class_AudioStreamPlayer>' and connect it's ``finished`` signal to ourselves.
-It doesn't matter if it's :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>'.
+In ``_ready`` we get the :ref:`AudioStreamPlayer <class_AudioStreamPlayer>` and connect its ``finished`` signal to ourselves.
+It doesn't matter if it's a :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 we set the audio stream for our :ref:'AudioStreamPlayer <class_AudioStreamPlayer>'
+is one of the three possible sounds, and if it is we set the audio stream for our :ref:`AudioStreamPlayer <class_AudioStreamPlayer>`
 to the correct sound.
 
 If it is an unknown sound, we print an error message to the console and free ourselves.
 
-If you are using a :ref:'AudioStreamPlayer3D <class_AudioStreamPlayer3D>', remove the ``#`` to set the position of
+If you are using a :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.
+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 ourself
+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 ourself
 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
@@ -477,19 +569,22 @@ to save on resources.
 
           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
+          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, lets open up ``Player.gd`` again.
+With that done, let's open up ``Player.gd`` again.
 First we need to load the ``SimpleAudioPlayer.tscn``. Place the following code in your global variables:
 
 ::
 
-    var simple_audio_player = preload("res://SimpleAudioPlayer.tscn")
+    var simple_audio_player = preload("res://Simple_Audio_Player.tscn")
 
-Now we just need to instance the simple audio player when we need it, and then call it's
+Now we just 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:
 
@@ -505,18 +600,18 @@ Lets walk through what this function does:
 
 _________
 
-The first line instances the ``simple_audio_player.tscn`` scene and assigns it to a variable,
+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, using one large 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 ``Test_Level.tscn``. We are making a huge assumption that the first child of the root
+``Test_Area.tscn`` or any of the other provided levels. We are making a huge assumption that the first child of the root
 is the root node that our player is under, which could 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 doesn't work
-reliably if you have multiple scenes loaded as childs to the root node at a time, which will rarely happen for most projects. This is really
-only potentially a issue depending on how you handle scene loading.
+reliably if you have multiple scenes loaded as children to the root node at a time, which will rarely happen for most projects.
+This is really only potentially a issue depending on how you handle scene loading.
 
 The third line adds our newly created ``SimpleAudioPlayer`` scene to be a child of the scene root. This
 works exactly the same as when we are spawning bullets.
@@ -526,179 +621,66 @@ Finally, we call the ``play_sound`` function and pass in the arguments we're giv
 
 _________
 
-Now all that is left is playing the sounds when we want to. First, let's play the shooting sounds
-when a bullet is fired. Go to ``fire_bullet`` and add the following:
-
-::
-
-    func fire_bullet():
-        if changing_gun == true:
-            return
-
-        # Pistol bullet handling: Spawn a bullet object!
-        if current_gun == "PISTOL":
-            var clone = bullet_scene.instance()
-            var scene_root = get_tree().root.get_children()[0]
-            scene_root.add_child(clone)
-
-            clone.global_transform = $Rotation_helper/Gun_fire_points/Pistol_point.global_transform
-            # The bullet is a little too small (by default), so let's make it bigger!
-            clone.scale = Vector3(4, 4, 4)
-
-            ammo_in_guns["PISTOL"] -= 1
-            create_sound("Pistol_shot", clone.global_transform.origin); # NEW CODE
-
-        # Rifle bullet handeling: Send a raycast!
-        elif current_gun == "RIFLE":
-            var ray = Rotation_helper/Gun_fire_points/Rifle_point/RayCast
-            ray.force_raycast_update()
+Now all that is left is playing the sounds when we want to. Let's add sound to the pistol first!
 
-            if ray.is_colliding():
-                var body = ray.get_collider()
-                if body.has_method("bullet_hit"):
-                    body.bullet_hit(RIFLE_DAMAGE, ray.get_collision_point())
+Open up ``Weapon_Pistol.gd``.
 
-            ammo_in_guns["RIFLE"] -= 1
-            create_sound("Rifle_shot", ray.global_transform.origin); # NEW CODE
-
-        # Knife bullet(?) handeling: Use an area!
-        elif current_gun == "KNIFE":
-            var area = $Rotation_helper/Gun_fire_points/Knife_point/Area
-            var bodies = area.get_overlapping_bodies()
-
-            for body in bodies:
-                if body.has_method("bullet_hit"):
-                    body.bullet_hit(KNIFE_DAMAGE, area.global_transform.origin)
-
-Now we will play the shooting noise for both the pistol and the rifle when a bullet is created.
-
-.. note:: We are passing in the positions of the ends of the guns using the bullet object's
-          global :ref:`Transform <class_transform>` and the :ref:`Raycast <class_raycast>`'s global :ref:`Transform <class_transform>`.
-          If you are not using a :ref:`AudioStreamPlayer3D <class_AudioStreamPlayer3D>` node, you can optionally leave the positions out and only
-          pass in the name of the sound you want to play.
-
-Finally, lets play the sound of a gun being cocked when we reload and when we change weapons.
-Add the following to our reloading logic section of ``_physics_process``:
+Now, we want to make a noise when we fire the pistol, so add the following to the end of the ``fire_weapon`` function:
 
 ::
+    
+    player_node.create_sound("pistol_shot", self.global_transform.origin)
 
-    # Reloading logic
-    if reloading_gun == true:
-        var can_reload = false
-
-        if current_gun == "PISTOL":
-            if animation_manager.current_state == "Pistol_idle":
-                can_reload = true
-        elif current_gun == "RIFLE":
-            if animation_manager.current_state == "Rifle_idle":
-                can_reload = true
-        elif current_gun == "KNIFE":
-            can_reload = false
-            reloading_gun = false
-        else:
-            can_reload = false
-            reloading_gun = false
-
-        if ammo_for_guns[current_gun] <= 0 or ammo_in_guns[current_gun] == AMMO_IN_MAGS[current_gun]:
-            can_reload = false
-            reloading_gun = false
-
-
-        if can_reload == true:
-            var ammo_needed = AMMO_IN_MAGS[current_gun] - ammo_in_guns[current_gun]
-
-            if ammo_for_guns[current_gun] >= ammo_needed:
-                ammo_for_guns[current_gun] -= ammo_needed
-                ammo_in_guns[current_gun] = AMMO_IN_MAGS[current_gun]
-            else:
-                ammo_in_guns[current_gun] += ammo_for_guns[current_gun]
-                ammo_for_guns[current_gun] = 0
-
-            if current_gun == "PISTOL":
-                animation_manager.set_animation("Pistol_reload")
-            elif current_gun == "RIFLE":
-                animation_manager.set_animation("Rifle_reload")
+Now when we fire our pistol, we'll play the ``pistol_shot`` sound.
 
-            reloading_gun = false
-            create_sound("Gun_cock", camera.global_transform.origin) # NEW CODE
-
-And add this code to the changing weapons section of ``_physics_process``:
+To make a sound when we reload, we just 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)
 
-    if changing_gun == true:
-        if current_gun != "PISTOL":
-            if animation_manager.current_state == "Pistol_idle":
-                animation_manager.set_animation("Pistol_unequip")
-        if current_gun != "RIFLE":
-            if animation_manager.current_state == "Rifle_idle":
-                animation_manager.set_animation("Rifle_unequip")
-        if current_gun != "KNIFE":
-            if animation_manager.current_state == "Knife_idle":
-                animation_manager.set_animation("Knife_unequip")
+Now when we reload we'll play the ``gun_cock`` sound.
 
-        if current_gun == "UNARMED":
-            if animation_manager.current_state == "Idle_unarmed":
-                changing_gun = false
+_________
 
-        elif current_gun == "KNIFE":
-            if animation_manager.current_state == "Knife_idle":
-                changing_gun = false
-            if animation_manager.current_state == "Idle_unarmed":
-                animation_manager.set_animation("Knife_equip")
+Now let's add sounds to the rifle.
+Open up ``Weapon_Rifle.gd``.
 
-        elif current_gun == "PISTOL":
-            if animation_manager.current_state == "Pistol_idle":
-                changing_gun = false
-            if animation_manager.current_state == "Idle_unarmed":
-                animation_manager.set_animation("Pistol_equip")
+To play sounds when the rifle is fired, add the following to the end of the ``fire_weapon`` function:
 
-                create_sound("Gun_cock", camera.global_transform.origin) # NEW CODE
+::
+    
+    player_node.create_sound("rifle_shot", ray.global_transform.origin)
 
-        elif current_gun == "RIFLE":
-            if animation_manager.current_state == "Rifle_idle":
-                changing_gun = false
-            if animation_manager.current_state == "Idle_unarmed":
-                animation_manager.set_animation("Rifle_equip")
+Now when we fire our rifle, we'll play the ``rifle_shot`` sound.
 
-                create_sound("Gun_cock", camera.global_transform.origin) # NEW CODE
+To make a sound when we reload, we just need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
+``reload_weapon`` function:
 
-Now whatever sound you have assigned to "Gun_cock" will play when you reload and when you
-change to either the pistol or the rifle.
+::
+    
+    player_node.create_sound("gun_cock", player_node.camera.global_transform.origin)
 
+Now when we reload we'll play the ``gun_cock`` sound.
 
 Final notes
 -----------
 
-.. image:: img/FinishedTutorialPicture.png
-
-Now you have a fully working single player FPS!
-
-You can find the completed project here: :download:`Godot_FPS_Finished.zip <files/Godot_FPS_Finished.zip>`
-
-.. tip:: The finished project source is hosted on Github as well: https://github.com/TwistedTwigleg/Godot_FPS_Tutorial
-
-You can also download all of the ``.blend`` files used here: :download:`Godot_FPS_BlenderFiles.zip <files/Godot_FPS_BlenderFiles.zip>`
-
-.. note:: The finished project source files contain the same exact 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.
+.. image:: img/PartThreeFinished.png
 
-The skybox is created by **StumpyStrust** and can be found at OpenGameArt.org. https://opengameart.org/content/space-skyboxes-0
+Now you have weapons with limited ammo that play sounds when you fire them!
 
-The font used is **Titillium-Regular**, and is licensed under the SIL Open Font License, Version 1.1.
+At this point we have all of the basics of a FPS working.
+There's still a few things that would be nice to add, and we're going to add them in the next three parts!
 
-The skybox was convert to a 360 equirectangular image using this tool: https://www.360toolkit.co/convert-cubemap-to-spherical-equirectangular.html
+For example, right now we have no way to add ammo to our spares, so we'll eventually run out. Also, we don't really
+have anything to shoot at outside of the :ref:`RigidBody <class_RigidBody>` nodes.
 
-While no sounds are provided, you can find many game ready sounds at https://gamesounds.xyz/
+In 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:: OpenGameArt.org, 360toolkit.co, the creator(s) of Titillium-Regular, and GameSounds.xyz are in no way involved in this tutorial.
+.. 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>`
 
-In :ref:`part four <doc_fps_tutorial_part_four>` we will be refactoring/rewriting ``Player.gd`` to a more modular format, as well as adding joypad support!

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 574 - 338
tutorials/3d/fps_tutorial/part_two.rst


Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott