< Return to Video

Survival Shooter Tutorial - 7 of 10 : Harming Enemies - Unity Official Tutorials (new)

  • 0:02 - 0:04
    So we have previously set
  • 0:04 - 0:06
    the player up so we can see that the model
  • 0:06 - 0:09
    has a gun built in, so let's go ahead
  • 0:09 - 0:11
    and get the player to
  • 0:11 - 0:13
    a point where the player can defend themselves.
  • 0:13 - 0:15
    What we're going to do is give the enemy the ability to
  • 0:15 - 0:17
    have health and then we're going to give the player
  • 0:17 - 0:19
    the ability to take that health away.
  • 0:19 - 0:22
    So we're going to go through the enemy health script next.
  • 0:22 - 0:24
    So we'll start off by finding it in
  • 0:24 - 0:26
    Scripts - Enemy folder.
  • 0:26 - 0:28
    Then we can drag and drop that
  • 0:28 - 0:30
    on to the Zombunny in the hierarchy.
  • 0:30 - 0:33
    So that's going to apply the script for us.
  • 0:35 - 0:39
    On the Zombunny, so we can see that there's
  • 0:39 - 0:41
    a Death clip
  • 0:41 - 0:43
    which we're going to apply.
  • 0:44 - 0:46
    Use the circle select button
  • 0:47 - 0:50
    and that's opened up the context sensitive menu so we can
  • 0:50 - 0:53
    find Zombunny Death. Apply that.
  • 0:54 - 0:56
    So now everything's setup for us, we can
  • 0:56 - 0:58
    edit that script or view it
  • 0:58 - 1:00
    and see what's going on in that.
  • 1:01 - 1:03
    Double click the icon to open it.
  • 1:05 - 1:08
    As always we've got our public variables at the top.
  • 1:08 - 1:11
    And very similar to the player's health we've got
  • 1:11 - 1:13
    startingHealth and a currentHealth.
  • 1:13 - 1:15
    They work exactly the same as the player.
  • 1:16 - 1:18
    The next one is the sinkSpeed.
  • 1:18 - 1:21
    When these enemies die
  • 1:21 - 1:23
    it looks a bit funky to just have them
  • 1:23 - 1:26
    lay there and then suddenly disappear.
  • 1:26 - 1:28
    So what we're going to do is make them sink through
  • 1:28 - 1:30
    the floor, so as soon as they've
  • 1:30 - 1:32
    finished flopping over and dying they sink
  • 1:32 - 1:34
    through the floor, and that's how fast
  • 1:34 - 1:35
    we want them to sink through the floor.
  • 1:35 - 1:37
    Later on in the day we're going to start doing
  • 1:37 - 1:39
    scoring for this game and
  • 1:39 - 1:41
    so each enemy needs to have a scoreValue,
  • 1:41 - 1:43
    how much they increase our score by
  • 1:43 - 1:45
    and that is the scoreValue.
  • 1:46 - 1:48
    And we've got the deathClip
  • 1:48 - 1:50
    that they play when they die.
  • 1:50 - 1:52
    We've got some private variables
  • 1:52 - 1:55
    starting off with the animator component reference.
  • 1:55 - 1:57
    Then we've got a reference to the
  • 1:57 - 2:00
    audio source, we've also got a reference
  • 2:00 - 2:01
    to the hit particles.
  • 2:01 - 2:04
    If you remember we dragged that on as a prefab
  • 2:04 - 2:06
    and applied it as a child object.
  • 2:06 - 2:09
    Likewise we've got a capsule collider reference.
  • 2:10 - 2:13
    Then we've got a pair of boolean variables.
  • 2:13 - 2:16
    We've got IsDead, which works exactly
    the same as with the player.
  • 2:16 - 2:20
    And IsSinking, so they don't immediately start sinking
  • 2:20 - 2:23
    because we want to see the animation so we need to have
  • 2:23 - 2:25
    separate bools to determine
  • 2:25 - 2:27
    whether or not they're sinking and whether they're dead.
  • 2:28 - 2:31
    Next we've got our awake function.
  • 2:31 - 2:33
    Which is going to setup our references as usual.
  • 2:34 - 2:38
    The first two, as we've seen before, GetComponent,
  • 2:38 - 2:40
    the type of the component that we're going to find
  • 2:40 - 2:42
    animator, audio source,
  • 2:42 - 2:44
    but with hitParticles we need to
  • 2:44 - 2:48
    find a component in the child object hitParticles.
  • 2:49 - 2:51
    So what GetComponentInChildren will do
  • 2:51 - 2:53
    will go through all of the children
  • 2:53 - 2:55
    game object and then find
  • 2:55 - 2:58
    the first particle system and return that.
  • 2:58 - 3:00
    Again, we've got GetComponent to find the capsule collider.
  • 3:01 - 3:03
    Then at the end of the awake function
  • 3:03 - 3:05
    we're setting the current health to the starting health.
  • 3:06 - 3:08
    In update
  • 3:08 - 3:11
    all we're doing is we're checking whether or not
  • 3:11 - 3:13
    the enemy is supposed to be sinking or not.
  • 3:13 - 3:17
    If it is sinking then we're going to translate
  • 3:17 - 3:19
    the transform, and that means just move it.
  • 3:20 - 3:22
    So we're going to move it in a negative-up
  • 3:22 - 3:24
    direction, down.
  • 3:24 - 3:27
    and we're going to do that by the sinkSpeed
  • 3:27 - 3:31
    per second, so that's that Time.DeltaTime thing.
  • 3:32 - 3:34
    If we do that then we're moving per second
  • 3:34 - 3:36
    instead of per frame.
  • 3:36 - 3:37
    So just a quick note about translate.
  • 3:37 - 3:39
    Previously we used move position to move
  • 3:39 - 3:41
    this thing but we're going to be no longer using
  • 3:41 - 3:43
    physics when the enemies die so
  • 3:43 - 3:45
    we can go ahead and use translate without
  • 3:45 - 3:47
    worrying about losing sync with physics.
  • 3:49 - 3:52
    Next we've got, again very similar
  • 3:52 - 3:54
    function to the player's health we've got
  • 3:54 - 3:56
    a public function, so again that means it
  • 3:56 - 3:58
    can be called from another function
  • 3:58 - 3:59
    and that's where we'll be calling it from.
  • 3:59 - 4:00
    Another script.
  • 4:00 - 4:01
    Another script, sorry.
  • 4:02 - 4:04
    But this time we've got the integer
  • 4:04 - 4:06
    of how much damage is going to be taken
  • 4:06 - 4:08
    but also the hitPoint,
  • 4:08 - 4:10
    so where has it been it?
  • 4:10 - 4:12
    And we'll be using that hitPoint to
  • 4:12 - 4:15
    move the particle system around the enemy
  • 4:15 - 4:17
    so that fluff is flying out wherever it gets hit.
  • 4:19 - 4:21
    Right, so the first thing we want to do in this function
  • 4:21 - 4:25
    is check if the enemy is dead.
  • 4:25 - 4:27
    If it is dead then we don't need to do
  • 4:27 - 4:29
    anything so we're going to return out of this function.
  • 4:30 - 4:32
    Assuming we are not dead, or the enemy is not dead
  • 4:32 - 4:34
    we can continue on with this function.
  • 4:34 - 4:36
    Then since we've taken damage we want to play
  • 4:36 - 4:38
    the Hurt sound effect.
  • 4:38 - 4:40
    We'll then lose the amount of health
  • 4:40 - 4:42
    from our current health.
  • 4:43 - 4:45
    Next what we're going to do is
  • 4:45 - 4:49
    find the hitParticles, so that's the particle system
  • 4:49 - 4:51
    Find the transform that that is on
  • 4:51 - 4:54
    and move that position to the hitPoint.
  • 4:55 - 4:58
    So we've got a child game object
  • 4:58 - 5:01
    finding that position and moving it to
  • 5:01 - 5:03
    where ever we've been hit.
  • 5:03 - 5:05
    So note that we haven't actually defined the hitPoint
  • 5:05 - 5:08
    but it's going to be passed in to this
    TakeDamage function
  • 5:08 - 5:10
    using that second argument, this vector3.
  • 5:10 - 5:13
    So we're going to send it wherever we call TakeDamage
  • 5:13 - 5:15
    and you'll see that a little later on.
  • 5:16 - 5:18
    Okay, so after we've moved
  • 5:18 - 5:20
    the position of the particle system
  • 5:20 - 5:23
    we can then play the particle system, so the fluff starts flying out.
  • 5:26 - 5:28
    Last in this function, we're going to check
  • 5:28 - 5:30
    if our current health is less than
  • 5:30 - 5:32
    or equal to 0.
  • 5:32 - 5:36
    If we've run out of health then we'll use the Death function.
  • 5:37 - 5:38
    So the Death function.
  • 5:39 - 5:42
    First of all we set isDead equals to true.
  • 5:43 - 5:47
    Then we set the capsule collider to a trigger.
  • 5:47 - 5:49
    So what that means is because you don't
  • 5:49 - 5:52
    actually physically hit triggers
  • 5:52 - 5:55
    if the player is running along mowing down enemies
  • 5:56 - 5:58
    then when they die they won't become
  • 5:58 - 6:00
    an obstacle any more, it can keep on moving
  • 6:00 - 6:01
    and keep on mowing through them.
  • 6:03 - 6:05
    We set the animator trigger Dead
  • 6:05 - 6:07
    so the enemy knows it's dead
  • 6:07 - 6:09
    it performs it's Dead animation.
  • 6:10 - 6:12
    And lastly we're going to set the audio
  • 6:12 - 6:14
    source to play the Death clip.
  • 6:14 - 6:16
    So we change the clip that it's got to play to Death
  • 6:16 - 6:18
    and then make it play.
  • 6:18 - 6:20
    Okay, so we've got a public function here
  • 6:20 - 6:22
    called StartSinking and we'll discuss why it's
  • 6:22 - 6:24
    public in a minute but for now we'll just
  • 6:24 - 6:25
    go through what it does.
  • 6:26 - 6:28
    In this we're going to find references
  • 6:28 - 6:30
    to the nav mesh agent
  • 6:31 - 6:33
    and disable it.
  • 6:33 - 6:35
    And then we're going to find a reference to the
  • 6:35 - 6:38
    rigidbody component and set it to isKinematic
  • 6:38 - 6:41
    The reason we're going to set it to kinematic is
  • 6:41 - 6:43
    that when you move a collider
  • 6:43 - 6:45
    in the scene Unity will try and
  • 6:45 - 6:47
    recalculate all the static geometry
  • 6:47 - 6:50
    because it thinks 'okay, the level's changed,
  • 6:50 - 6:52
    I need to rethink about this.
  • 6:53 - 6:55
    But if you've got a kinematic rigidbody
  • 6:55 - 6:58
    and you're translating this object
  • 6:58 - 7:01
    then it will ignore it, so that's why we're doing that.
  • 7:01 - 7:05
    Real quick here, we see GetComponent
  • 7:05 - 7:07
    .enabled = false;
  • 7:07 - 7:09
    so if we were trying to turn
  • 7:09 - 7:11
    off a game object
  • 7:11 - 7:15
    we say .setActive
  • 7:15 - 7:17
    and in parenthesis say false.
  • 7:17 - 7:19
    Nav mesh agent's a component so we say
  • 7:19 - 7:21
    .enabled, so just keep that in mind.
  • 7:21 - 7:24
    If you see .setActive = false
  • 7:24 - 7:26
    that's a game object and we're turning the whole
  • 7:26 - 7:27
    game object off.
  • 7:27 - 7:30
    Here we're doing .enabled = false
  • 7:30 - 7:32
    That means I'm not turning off the whole game object
  • 7:32 - 7:35
    just this one component of that game object.
  • 7:36 - 7:40
    Since we're starting to sink isSinking is true.
  • 7:40 - 7:43
    And lastly we're going to destroy the game object
  • 7:43 - 7:46
    after 2 seconds, so basically
  • 7:46 - 7:48
    it's started sinking, it's going through the floor,
  • 7:48 - 7:50
    after 2 seconds we're not going to see it any more
  • 7:50 - 7:52
    we can get rid of it, so we'll destroy the game object.
  • 7:52 - 7:54
    And that's the end of that function
  • 7:54 - 7:55
    and the end of this script as well.
  • 7:55 - 7:57
    When we're done with that we can hop back over
  • 7:57 - 7:59
    in to Unity here.
  • 8:01 - 8:04
    The enemy now has health and so one of the
  • 8:04 - 8:06
    things that we want to do is we
  • 8:06 - 8:08
    want to make the enemy's
  • 8:08 - 8:10
    ability to attack dependent on whether or not
  • 8:10 - 8:12
    the enemy is alive.
  • 8:12 - 8:14
    Sorry to interrupt you Mike, I've just remembered that we've
  • 8:14 - 8:16
    missed something out.
  • 8:16 - 8:18
    So we had that StartSinking function
  • 8:18 - 8:20
    and it was public
  • 8:20 - 8:22
    but we never called it.
  • 8:22 - 8:23
    The reason we never called it is because
  • 8:23 - 8:25
    it's on an animation event.
  • 8:25 - 8:29
    So all these enemies, they have an animation event
  • 8:29 - 8:31
    where they flop and then die.
  • 8:31 - 8:34
    And what we can do in Unity is say
  • 8:34 - 8:36
    somewhere along the line of that animation
  • 8:36 - 8:38
    we're going to say 'at this point
  • 8:38 - 8:41
    try and look for this function
  • 8:41 - 8:43
    on the game object, somewhere on the game object
  • 8:43 - 8:46
    there will be a function called StartSinking.
  • 8:46 - 8:48
    So it'll look for that and then if
  • 8:48 - 8:50
    it finds it it'll play that function.
  • 8:51 - 8:53
    This was setup already.
  • 8:53 - 8:55
    Yes, this isn't something that you have to do,
  • 8:55 - 8:57
    this is something that we've setup for you.
  • 9:00 - 9:04
    So this is something that is already there,
  • 9:04 - 9:06
    and basically what this says is at this
  • 9:06 - 9:08
    mark, which is something that is already in the animation
  • 9:08 - 9:09
    it's not anything that you guys have to do,
  • 9:09 - 9:11
    it's going to attempt to call a method called
  • 9:11 - 9:13
    StartSinking.
  • 9:13 - 9:15
    Now up until this point there has been
  • 9:15 - 9:16
    no such method, alright.
  • 9:16 - 9:18
    But now we've created one and we've added
  • 9:18 - 9:20
    it so now it knows
  • 9:20 - 9:22
    I have a method called StartSinking and
  • 9:22 - 9:24
    that will happen when it's time comes.
  • 9:26 - 9:28
    Normally if the animation were to play
  • 9:28 - 9:30
    and that function were to not be there you would
  • 9:30 - 9:32
    get an error saying 'hey, I'm trying to call this function
  • 9:32 - 9:33
    and one does not exist.
  • 9:33 - 9:35
    We did not get an error because we have yet to
  • 9:35 - 9:37
    have any way of killing the enemy.
  • 9:37 - 9:39
    If we had we would have seen an error but
  • 9:39 - 9:41
    if we don't then we do not see an error.
  • 9:41 - 9:45
    The function was public and so this animation will
  • 9:45 - 9:48
    automatically call that function when the time comes.
  • 9:48 - 9:50
    Animation events are really useful,
  • 9:50 - 9:52
    you can use them for all kinds of things.
  • 9:52 - 9:54
    A real common use would be footsteps
  • 9:54 - 9:56
    if you had a single function to call a
  • 9:56 - 9:58
    footstep at a particular point in an animation
  • 9:58 - 10:00
    because obviously you can pick a particular frame
  • 10:00 - 10:02
    where you want this to happen.
  • 10:02 - 10:04
    We've got this fairly roughly placed
  • 10:04 - 10:06
    and it just means that as soon as he just leaps up
  • 10:06 - 10:08
    we'll start sending him down as well
  • 10:08 - 10:10
    as his falling animation,
  • 10:10 - 10:12
    which actually means that we're not getting the bounce on
  • 10:12 - 10:14
    on the floor, but we could move it along if we wanted
  • 10:14 - 10:16
    to but we're not going to bother doing that,
  • 10:16 - 10:18
    you can play around with that later on.
  • 10:20 - 10:22
    Now that we have the Enemy Health script
  • 10:22 - 10:24
    it's important for us to pair the Enemy Attack script
  • 10:24 - 10:26
    to that so that the enemy does not
  • 10:26 - 10:28
    attack once they're already dead.
  • 10:28 - 10:31
    What we'd like to do is edit
  • 10:31 - 10:34
    the Enemy Attack script and uncomment
  • 10:34 - 10:36
    those lines that we previously saw commented.
  • 10:36 - 10:38
    Now we could locate the script in the project view
  • 10:38 - 10:39
    and double click it and open it
  • 10:39 - 10:41
    but I just want to run through another way that we
  • 10:41 - 10:43
    could open that script.
  • 10:43 - 10:46
    What I'm going to do is click on the Zombunny,
  • 10:46 - 10:48
    and I am going to find the
  • 10:48 - 10:51
    Enemy Attack script, the Enemy Attack Script.
  • 10:51 - 10:55
    And of the script components the first property is always
  • 10:55 - 10:57
    the script itself.
  • 10:57 - 10:59
    Every script component has a first property called
  • 10:59 - 11:02
    Script and the value of that is itself.
  • 11:02 - 11:04
    So if I click on it what it does is highlight
  • 11:04 - 11:06
    for me in the project view that script.
  • 11:06 - 11:08
    So I'm like 'hey, which script is this?',
  • 11:08 - 11:09
    you click on it, there it is.
  • 11:09 - 11:11
    But I can then double click on it here
  • 11:11 - 11:13
    inside this property and it again will
  • 11:13 - 11:15
    open up inside Mono Develop.
  • 11:15 - 11:17
    So that's another way to open the script up.
  • 11:17 - 11:19
    So this is now a part that you're all going to want to
  • 11:19 - 11:21
    follow along with because we're now going to remove
  • 11:21 - 11:23
    this commenting while we explain what
  • 11:23 - 11:24
    the comments were for.
  • 11:24 - 11:26
    I'm going to come up to the top here
  • 11:26 - 11:28
    and the first bit of commenting I see
  • 11:28 - 11:30
    is a commented out variable
  • 11:30 - 11:33
    that references EnemyHealth.
  • 11:33 - 11:35
    Obviously we had to comment that out before
  • 11:35 - 11:37
    because EnemyHealth didn't exist on the enemy yet
  • 11:37 - 11:39
    so we had to keep that commented out.
  • 11:39 - 11:41
    Now we're going to uncomment it so we can now have a
  • 11:41 - 11:43
    reference to the enemy health script.
  • 11:43 - 11:45
    Next we're going to go to our awake function,
  • 11:45 - 11:47
    and again, since we have this variable,
  • 11:47 - 11:49
    we now have to get that reference and we dothat
  • 11:49 - 11:52
    by saying enemyHealth = GetComponent,
  • 11:52 - 11:54
    and the component name is the name of the script,
  • 11:54 - 11:56
    which is EnemyHealth.
  • 11:57 - 11:59
    And then we're going to come down here towards the bottom
  • 11:59 - 12:01
    and we're going to notice this.
  • 12:01 - 12:05
    And this is not the commenting you've seen before.
  • 12:05 - 12:07
    There we go, it's about as close as it'll let me get.
  • 12:07 - 12:10
    So this is called a Block Comment
  • 12:10 - 12:12
    and what block comments enable me to do is
  • 12:12 - 12:14
    comment many, many, many lines
  • 12:14 - 12:17
    or pieces inside a line
  • 12:17 - 12:19
    or whatever, right? So what we have here
  • 12:19 - 12:21
    is what's called a Block Comment.
  • 12:21 - 12:23
    And we can see that here's
  • 12:23 - 12:25
    the start of the block comment,
  • 12:25 - 12:27
    and here is the end of the block comment.
  • 12:27 - 12:32
    So it's / all the way through to /.
  • 12:32 - 12:34
    And anything between there is commented out.
  • 12:34 - 12:36
    And you'll see that these parentheses
  • 12:36 - 12:39
    or parenthesis is not commented out
  • 12:39 - 12:41
    because only the things between the block
  • 12:41 - 12:42
    comments get commented out.
  • 12:42 - 12:44
    So what we want to do is remove the block comment.
  • 12:44 - 12:46
    So when we start to remove this
  • 12:46 - 12:48
    we'll see everything gets commented out and then
  • 12:48 - 12:49
    nothing's commented out.
  • 12:49 - 12:51
    So what this line says now
  • 12:51 - 12:53
    if you recall previously it says
  • 12:53 - 12:55
    'hey, if it's time to attack
  • 12:55 - 12:57
    and the player is in range
  • 12:57 - 12:59
    we attack the player'.
  • 12:59 - 13:01
    Well there's one more step, one more decision
  • 13:01 - 13:02
    you have to make, we have to say
  • 13:02 - 13:04
    'if it's time to attack
  • 13:04 - 13:06
    and the player is in range
  • 13:06 - 13:08
    and we're not dead'
  • 13:08 - 13:10
    and at that point we attack.
  • 13:10 - 13:12
    So at this point now with all of that stuff
  • 13:12 - 13:14
    uncommented now the enemy will attack the player
  • 13:14 - 13:16
    correctly like they had been and they'll
  • 13:16 - 13:18
    also stop when they're dead,
  • 13:18 - 13:22
    which is obviously an important part of this whole dynamic.
  • 13:22 - 13:24
    Be sure to get that stuff done. When you're finished
  • 13:24 - 13:25
    be sure to save,
  • 13:25 - 13:27
    save the script and return,
  • 13:27 - 13:30
    which will bring us back in to Unity.
  • 13:31 - 13:36
    The enemy is cool, we can leave it alone for now.
  • 13:36 - 13:38
    Now let's go ahead and get this
  • 13:38 - 13:39
    player ready to rock and roll.
  • 13:39 - 13:41
    There's a few things that we're going to need to do.
  • 13:41 - 13:43
    The player already has this mesh and the mesh
  • 13:43 - 13:45
    has a gun, so the player is already setup
  • 13:45 - 13:47
    with his weapon of choice so what we want to
  • 13:47 - 13:50
    do is we want to make it behave appropriately.
  • 13:50 - 13:51
    So there's some stuff we want to add to it.
  • 13:51 - 13:54
    The first is we're going to add a particle component
  • 13:54 - 13:56
    which is going to enable the gun to
  • 13:56 - 13:58
    spit fire, which makes it kinda fun.
  • 13:58 - 14:00
    We're also going to add the ability for
  • 14:00 - 14:03
    it to have sound so we can hear
  • 14:03 - 14:04
    when the player is firing.
  • 14:04 - 14:06
    We're going to add a light so that the player
  • 14:06 - 14:08
    illuminates the scene when firing
  • 14:08 - 14:10
    and then we're going to add a line renderer
  • 14:10 - 14:12
    and the line renderer is actually going to be that
  • 14:12 - 14:14
    line that we're firing out
  • 14:14 - 14:16
    to make it look like we're firing bullets
  • 14:16 - 14:18
    or lasers or whatever,
  • 14:18 - 14:20
    and all of these things are going to make this
  • 14:20 - 14:23
    a much more fun look and feel to the game.
  • 14:23 - 14:25
    So what we're going to do is go to the prefabs folder
  • 14:25 - 14:28
    and we're going to locate gunParticles.
  • 14:28 - 14:31
    Unlike the hitParticles of the enemy
  • 14:31 - 14:33
    we are not going to click and drag this prefab
  • 14:33 - 14:35
    anywhere near the player.
  • 14:35 - 14:37
    Instead we are going to copy
  • 14:37 - 14:39
    a component off of it.
  • 14:39 - 14:42
    So we're not going to use this prefab
  • 14:42 - 14:44
    we're just going to use a piece of this prefab.
  • 14:44 - 14:46
    So if we look over here in the inspector
  • 14:46 - 14:48
    we see the particle system that is
  • 14:48 - 14:51
    a part of that gunParticles
  • 14:51 - 14:54
    and I can click the cog, or gear
  • 14:54 - 14:57
    right here and I can select Copy Component.
  • 14:57 - 14:59
    I'm not actually interested in the game object or the
  • 14:59 - 15:02
    prefab I'm interested in the component that's on it.
  • 15:02 - 15:04
    Once I've copied that component
  • 15:04 - 15:06
    I'm going to go to the player in my hierarchy
  • 15:06 - 15:07
    and I'm going to expand it.
  • 15:07 - 15:11
    And I'm going to look for GunBarrelEnd.
  • 15:11 - 15:13
    Since the player has a collider
  • 15:13 - 15:15
    and the player has all these pieces and parts
  • 15:15 - 15:17
    I'm actually really interested in the
  • 15:17 - 15:19
    tip of the gun so that I can
  • 15:19 - 15:21
    align bullets and everything with
  • 15:21 - 15:23
    the tip of the gun and get
  • 15:23 - 15:25
    shooting to happen the way we want it to.
  • 15:26 - 15:29
    With GunBarrelEnd not Gun,
  • 15:29 - 15:31
    not Player, GunBarrelEnd selected
  • 15:31 - 15:33
    in the hierarchy I need to
  • 15:33 - 15:36
    locate a cog, there's always a cog
  • 15:36 - 15:38
    in the upper right hand corner of the transform component.
  • 15:38 - 15:40
    And I'm going to click that and I'm going to select
  • 15:40 - 15:42
    Component As New.
  • 15:42 - 15:44
    And there's my particles.
  • 15:44 - 15:46
    So at this point the particles are
  • 15:46 - 15:48
    on the end of the gun.
  • 15:48 - 15:49
    Now they're not set to play.
  • 15:49 - 15:51
    We going to use scripts to say when
  • 15:51 - 15:53
    those particles should start firing off.
  • 15:53 - 15:56
    So now we have the particle system on the gun.
  • 15:56 - 16:01
    Now let's minimise the particle system by
  • 16:01 - 16:03
    clicking the little arrow next to it
  • 16:03 - 16:05
    because the particle system itself takes up so much space
  • 16:05 - 16:07
    so we're just going to collapse that down
  • 16:07 - 16:09
    so that we have some room to work.
  • 16:09 - 16:11
    So we have our particle system and the next thing
  • 16:11 - 16:12
    we want is a Line Renderer.
  • 16:12 - 16:14
    The line renderer is going to be the visual
  • 16:14 - 16:16
    component of shooting and we're going to add that
  • 16:16 - 16:19
    by going to Add Component and I'm just going to type Line
  • 16:19 - 16:20
    and find Line Renderer.
  • 16:20 - 16:22
    I'm specifically typing in line because I can't
  • 16:22 - 16:23
    remember where it is otherwise.
  • 16:23 - 16:25
    Now a line renderer appears
  • 16:25 - 16:27
    as a component in our game object
  • 16:27 - 16:29
    and so what the line renderer is, like I say,
  • 16:29 - 16:31
    it renders a line, and so there's some settings
  • 16:31 - 16:33
    that we've got to do because as we can see right now
  • 16:33 - 16:35
    that doesn't really look like a bullet and that doesn't
  • 16:35 - 16:36
    really look like a gunshot, it just looks like
  • 16:36 - 16:38
    a giant magenta block.
  • 16:38 - 16:41
    So we need to set this up appropriately.
  • 16:41 - 16:43
    The first thing we're going to do is
  • 16:43 - 16:46
    expand the Materials drop down, and you can see here
  • 16:46 - 16:49
    I can just expand that by clicking the Materials drop down.
  • 16:49 - 16:51
    And I'm going to look for this Element 0.
  • 16:51 - 16:53
    And right now the reason this is
  • 16:53 - 16:56
    that hideous fuchsia colour is that it doesn't have
  • 16:56 - 16:58
    a material, it doesn't know what it's supposed to look like.
  • 16:58 - 17:00
    So what we want to do is give it
  • 17:00 - 17:02
    a colour so we're going to use the
  • 17:02 - 17:04
    circle selector, we're going to click on that,
  • 17:04 - 17:07
    and we already have a material created.
  • 17:07 - 17:09
    It's just a basic line renderer material
  • 17:09 - 17:13
    which we have cleverly named LineRendererMaterial.
  • 17:13 - 17:15
    So if you use the circle selector and look for
  • 17:15 - 17:17
    that list you should see a line renderer material.
  • 17:17 - 17:19
    Double click on that and it will apply it
  • 17:19 - 17:21
    to the gun.
  • 17:21 - 17:25
    What we want to do is and manage this line renderer better.
  • 17:25 - 17:27
    As we can see it's still, while it's still a
  • 17:27 - 17:30
    better colour, it's the colour of our laser
  • 17:30 - 17:33
    it's still way too big, so we definitely want to manage this.
  • 17:33 - 17:35
    I'll go ahead and collapse the material
  • 17:35 - 17:37
    back down as we're done there.
  • 17:37 - 17:39
    I'm going to expand Parameters and there's two things
  • 17:39 - 17:41
    I'm interested in, the first is Start Width
  • 17:41 - 17:42
    and the second is End Width.
  • 17:42 - 17:44
    And what we're going to do is set these up
  • 17:44 - 17:45
    to be the same value.
  • 17:45 - 17:47
    Because they're the same value the laser will
  • 17:47 - 17:48
    consider them to be the same size.
  • 17:48 - 17:50
    If they were different values it would either flare out in a cone
  • 17:50 - 17:52
    or narrow in or whatever.
  • 17:52 - 17:54
    And so for each of these we're going to specify
  • 17:54 - 17:56
    .05.
  • 17:56 - 17:59
    That's not 0.5, that's .05.
  • 17:59 - 18:01
    We're going to do that for both the start
  • 18:01 - 18:03
    and the end width.
  • 18:04 - 18:06
    Once that is done we are going
  • 18:06 - 18:09
    to go ahead and disable this component.
  • 18:09 - 18:11
    And the way that we're going to disable this component
  • 18:11 - 18:13
    is with this checkbox right here.
  • 18:13 - 18:15
    Right next to the name Line Renderer I'm
  • 18:15 - 18:16
    going to turn it off
  • 18:16 - 18:18
    And the reason I'm going to do that is the game doesn't
  • 18:18 - 18:20
    start with you shooting, the game starts with you
  • 18:20 - 18:22
    not shooting so I'm going to turn it off and only
  • 18:22 - 18:24
    turn it on once the time comes that
  • 18:24 - 18:25
    you have actually fired.
  • 18:25 - 18:27
    Now when we fire the gun what we want to do is
  • 18:27 - 18:29
    we want to have the gun flash and light things up
  • 18:29 - 18:31
    and in order to do that we need a
  • 18:31 - 18:33
    light so I'm going to go ahead and
  • 18:33 - 18:35
    collapse Line Renderer and now I'm
  • 18:35 - 18:37
    going to add a light component.
  • 18:37 - 18:41
    So I'm going to click the Add Component button
  • 18:41 - 18:43
    and I'm going to go to
  • 18:43 - 18:46
    Rendering and I'm going to select Light.
  • 18:47 - 18:49
    What that's going to do is add a light
  • 18:49 - 18:51
    to my gun, which we can see there.
  • 18:51 - 18:53
    What we want to do now is give this
  • 18:53 - 18:55
    the settings that will be appropriate
  • 18:55 - 18:57
    to this particular gun.
  • 18:57 - 19:00
    So the first thing to do is choose a colour
  • 19:00 - 19:01
    and we have this little eye dropper,
  • 19:01 - 19:03
    we can use the eye dropper just like you'd expect,
  • 19:03 - 19:05
    pick a colour out of something,
  • 19:05 - 19:07
    or we can just click next to it
  • 19:07 - 19:09
    and actually use the gradient/color picker
  • 19:09 - 19:11
    to pick a color.
  • 19:11 - 19:13
    I'm going to pick a yellowish color.
  • 19:13 - 19:15
    If you want to pick a different color go for it.
  • 19:15 - 19:17
    But I kind of want my light to be the same color
  • 19:17 - 19:19
    as my line renderer so I'm going with yellow there.
  • 19:20 - 19:23
    So now when we fire the weapon
  • 19:23 - 19:25
    there will in fact be a yellow light.
  • 19:25 - 19:27
    Now again like the line renderer we're not
  • 19:27 - 19:29
    starting firing so we're going to
  • 19:29 - 19:31
    disable the light.
  • 19:31 - 19:33
    So we'll just uncheck it there
  • 19:33 - 19:35
    and the light will be turned off until
  • 19:35 - 19:37
    we turn it on when we fire.
  • 19:37 - 19:39
    And so the last little bit we're going to
  • 19:39 - 19:41
    add is we need an audio source
  • 19:41 - 19:44
    so the gun can play the firing sound.
  • 19:44 - 19:47
    So what we're going to do is click Add Component.
  • 19:47 - 19:51
    We're going to choose Audio and Audio Source.
  • 19:51 - 19:55
    Now once the audio source is on the game object,
  • 19:55 - 19:57
    again just like we've done in the past we're going
  • 19:57 - 20:00
    to use the circle select picker
  • 20:00 - 20:03
    and we are going to locate Player GunShot.
  • 20:03 - 20:05
    Double click to add that and we are going to
  • 20:05 - 20:07
    uncheck Play On Wake.
  • 20:07 - 20:09
    We also want to be sure
  • 20:09 - 20:11
    that we do not have loop because
  • 20:11 - 20:13
    that will just drive everybody nuts.
  • 20:13 - 20:16
    So no play on awake, no looping,
  • 20:16 - 20:17
    That would be completely unnecessary.
  • 20:17 - 20:20
    At this point the gun is setup.
  • 20:20 - 20:22
    So now we can add the scripts
  • 20:22 - 20:24
    that's going to allow the player to attack the enemy.
  • 20:24 - 20:27
    So to recap, the enemy has health,
  • 20:27 - 20:29
    we've added the health script to the enemy which will
  • 20:29 - 20:32
    control when the enemy can attack and how the enemy dies.
  • 20:32 - 20:36
    The gun has particle effects, lights, line renderers and sound.
  • 20:36 - 20:38
    Now the last piece of this puzzle
  • 20:38 - 20:40
    is to give the player a script that's
  • 20:40 - 20:42
    going to allow the player to actually
  • 20:42 - 20:45
    fire the gun and harm the enemy.
  • 20:45 - 20:48
    So in the Scripts - Player folder
  • 20:50 - 20:54
    we're going to look for the PlayerShooting script.
  • 20:54 - 20:56
    And just like the previous scripts we're going to
  • 20:56 - 20:58
    click and drag this
  • 20:59 - 21:01
    and we are going to place it on the GunBarrelEnd,
  • 21:01 - 21:04
    not on the Player,
  • 21:04 - 21:05
    on the GunBarrelEnd.
  • 21:05 - 21:08
    So if we select the GunBarrelEnd we should see
  • 21:08 - 21:10
    the PlayerShooting script there.
  • 21:10 - 21:12
    So again ensure that it is not
  • 21:12 - 21:16
    on the Player, it is on the GunBarrelEnd.
  • 21:16 - 21:17
    And now let's go ahead and open up the PlayerShooting script.
  • 21:17 - 21:21
    Save your scene first. And let's look at what this script does.
  • 21:21 - 21:23
    The first thing we have is
  • 21:23 - 21:25
    these public variable declarations here,
  • 21:25 - 21:27
    the first is public in damagerPerShot
  • 21:27 - 21:29
    and we can see that every bullet is going to do
  • 21:29 - 21:31
    20 points of damage.
  • 21:31 - 21:34
    We also have a public float timeBetweenBullets
  • 21:34 - 21:36
    which again is going to control how quickly
  • 21:36 - 21:39
    our gun can fire, obviously we reduce that value
  • 21:39 - 21:41
    if we want to make our gun fire more quickly.
  • 21:41 - 21:43
    Then we have public float range
  • 21:43 - 21:45
    and that's how far bullets can go.
  • 21:45 - 21:47
    In this case they're going to be able to go 100 units
  • 21:47 - 21:50
    which is actually a really far distance.
  • 21:50 - 21:52
    Then we've got some private variables here
  • 21:52 - 21:53
    the first is a float timer,
  • 21:53 - 21:55
    and the float timer, just like the enemy attack,
  • 21:55 - 21:57
    it's going to keep everything in sync,
  • 21:57 - 22:00
    it'll make sure we can only attack when the time is right.
  • 22:00 - 22:03
    Then we have a Ray shootRay.
  • 22:03 - 22:05
    If you recall we have a gun,
  • 22:05 - 22:07
    we're firing so we're going to use this ray to actually
  • 22:07 - 22:10
    raycast out and figure out what it is we've hit
  • 22:10 - 22:13
    with these bullets, and that's how we're going to hit things.
  • 22:13 - 22:16
    We then have a RaycastHit variable called shootHit,
  • 22:16 - 22:18
    which is going to return back to us
  • 22:18 - 22:19
    whatever it is that we've hit.
  • 22:19 - 22:22
    We're then going to have an int shootableMask.
  • 22:22 - 22:25
    So we remember the floorMask which dictated that the
  • 22:25 - 22:28
    raycast from the camera could only click on the floor.
  • 22:28 - 22:30
    So what we're going to have is a shootable mask
  • 22:30 - 22:33
    to make sure that we can only hit shootable things,
  • 22:33 - 22:35
    we only want to shoot things that we can actually shoot.
  • 22:35 - 22:37
    Then we have a particle system referenced
  • 22:37 - 22:40
    to gunParticles, you'll recall that's the particle component
  • 22:40 - 22:42
    that we added in our previous step,
  • 22:42 - 22:43
    so that just gives us a reference to it.
  • 22:43 - 22:45
    Here's our reference to our line renderer called
  • 22:45 - 22:49
    gunLine, right, so again just so we can reference this in the script.
  • 22:49 - 22:52
    Our audio source reference called gunAudio.
  • 22:52 - 22:55
    Our light reference called gunLight.
  • 22:55 - 22:58
    And then our float effectsDisplayTime, which is
  • 22:58 - 23:00
    how long these effects are going to be
  • 23:00 - 23:03
    viewable before they disappear.
  • 23:03 - 23:05
    In our awake function we're going to setup all of our
  • 23:05 - 23:07
    references so we want to
  • 23:07 - 23:09
    set out shootableMask to the appropriate values
  • 23:09 - 23:13
    by saying LayerMask.GetMask ("Shootable") ;
  • 23:13 - 23:15
    What this is going to return back to us is
  • 23:15 - 23:17
    the number of our shootable layer.
  • 23:17 - 23:20
    You'll recall the level or the obstacles and everything
  • 23:20 - 23:23
    is on the shootable layer and the Zombunny we
  • 23:23 - 23:24
    created is also on the shootable layer.
  • 23:24 - 23:26
    So by setting up this mask we can shoot pretty
  • 23:26 - 23:28
    much anything that should be shootable.
  • 23:28 - 23:31
    Then we have the gun particles which we're going to
  • 23:31 - 23:34
    get access to by saying GetComponent
  • 23:34 - 23:37
    Then we're going to do the same for line, audio and light,
  • 23:37 - 23:39
    just gunLine = GetComponent
  • 23:39 - 23:41
    gunAudio = GetComponent
  • 23:41 - 23:43
    gunLight = GetComponent
  • 23:43 - 23:45
    which is just giving us a reference
  • 23:45 - 23:47
    so we can directly access those.
  • 23:47 - 23:49
    Now in the update function is where we
  • 23:49 - 23:51
    control whether or not it is time to shoot.
  • 23:51 - 23:53
    So very much like with the enemy attacking
  • 23:53 - 23:55
    here we have a function that's going to manage that.
  • 23:55 - 23:57
    So the first thing we're going to do is
  • 23:57 - 23:59
    accumulate your time and we do that by
  • 23:59 - 24:01
    saying time += Time.deltaTime.
  • 24:01 - 24:03
    So we'll basically increase in size
  • 24:03 - 24:05
    as time progresses.
  • 24:05 - 24:07
    Then we're going to say
  • 24:07 - 24:13
    if(Input.GetButton ("Fire1") and you might be thinking 'what is Fire1?'
  • 24:13 - 24:14
    Remember earlier we talked about the
  • 24:14 - 24:18
    Input.GetAxisHorizontal, Input.GetAxisVerticle,
  • 24:18 - 24:22
    these input axis that are built in to Unity for us
  • 24:22 - 24:23
    Fire1 is one of those.
  • 24:23 - 24:25
    Fire1 automatically maps to the
  • 24:25 - 24:28
    left control on your keyboard or
  • 24:28 - 24:30
    your mouse0 which is your left mouse button.
  • 24:30 - 24:31
    So that happens for you automatically.
  • 24:31 - 24:33
    You can override it here but if you don't do anything
  • 24:33 - 24:35
    that's built in to Unity, so
  • 24:35 - 24:37
    so you can always say Fire1 and that's how you talk
  • 24:37 - 24:39
    about the left mouse button.
  • 24:40 - 24:42
    So what we're saying is
  • 24:42 - 24:44
    if the player has clicked the left mouse button
  • 24:44 - 24:47
    or pressed the left control key
  • 24:47 - 24:49
    and
  • 24:49 - 24:52
    timer is greater than the delay between our shots.
  • 24:52 - 24:54
    So if it's time to shoot and the player wants to shoot
  • 24:54 - 24:55
    by clicking the button,
  • 24:55 - 24:57
    then we're going to call our function Shoot.
  • 24:57 - 24:59
    Shoot is a function we've written further down and
  • 24:59 - 25:01
    we'll talk about that in a second.
  • 25:01 - 25:04
    So if it's time and you're pressing the button we're going to shoot.
  • 25:04 - 25:06
    Then we're going to say if the timer
  • 25:06 - 25:08
    is greater than or equal to the
  • 25:08 - 25:10
    timeBetterBullets times the
  • 25:10 - 25:14
    effectDisplayTime what we'll do is disable the effects.
  • 25:14 - 25:16
    So what that means is if we've fired
  • 25:16 - 25:18
    and then enough time has progressed we're going
  • 25:18 - 25:20
    to turn the light and the line renderer and everything back off.
  • 25:20 - 25:23
    So we don't leave it on consistently.
  • 25:23 - 25:26
    So the DisableEffects function is public
  • 25:26 - 25:29
    which means again it can be A) referenced
  • 25:29 - 25:34
    by another script, B) referenced by another script on another game object
  • 25:34 - 25:37
    C) accessed by animation events and so on and so forth.
  • 25:37 - 25:39
    Public basically gives us a lot of access to it.
  • 25:39 - 25:41
    And the function basically says
  • 25:41 - 25:44
    the light and the line renderer,
  • 25:44 - 25:45
    just disable both of those.
  • 25:45 - 25:47
    Again not SetActive but Enabled = false
  • 25:47 - 25:49
    because they're components.
  • 25:49 - 25:51
    Now the Shoot function itself.
  • 25:51 - 25:53
    This is where we do the physics
  • 25:53 - 25:55
    of actually firing the bullet and it's
  • 25:55 - 25:58
    actually a fairly complex function here
  • 25:58 - 26:00
    so we'll step through it nice and easy.
  • 26:00 - 26:02
    The first thing we're going to do is reset the timer
  • 26:02 - 26:04
    back to 0 because we're firing now and we're going to
  • 26:04 - 26:07
    reset the amount of time we have to wait between firing.
  • 26:07 - 26:09
    The very next thing we're going to do is play the audio
  • 26:09 - 26:11
    and then we're turning the light on.
  • 26:11 - 26:12
    Now we don't need to do anything with the light
  • 26:12 - 26:15
    or the audio, we basically need to say
  • 26:15 - 26:17
    Then what we're going to say is if the
  • 26:17 - 26:20
    particles are still playing
  • 26:20 - 26:22
    stop them and then start them again.
  • 26:22 - 26:24
    What you don't want to happen is you don't
  • 26:24 - 26:26
    want to go to play the particles
  • 26:26 - 26:28
    have them already be playing
  • 26:28 - 26:30
    thus they don't replay and we get
  • 26:30 - 26:33
    a disconnect between the visuals of firing
  • 26:33 - 26:36
    and the actual raycasting and physics that's happening.
  • 26:36 - 26:39
    So we say if the particles are playing stop and start again.
  • 26:39 - 26:41
    Also if that were to happen the stop
  • 26:41 - 26:43
    and start would be so far your eye wouldn't even pick it up.
  • 26:43 - 26:47
    It would just feel like you're just firing really fast.
  • 26:47 - 26:51
    Then we're going to say 'let's turn on our line renderer',
  • 26:51 - 26:53
    which is the actual visual element of the bullet.
  • 26:53 - 26:55
    So we turn that on, so we say
  • 26:55 - 26:57
    gunLine.enabled = true.
  • 26:57 - 27:00
    Then here comes the tricky part about using lines,
  • 27:00 - 27:01
    lines have 2 points right?
  • 27:01 - 27:03
    One end and the other end.
  • 27:03 - 27:04
    Well the first end we know, it's the end of the gun,
  • 27:04 - 27:06
    it's the barrel of the gun,
  • 27:06 - 27:10
    so we access that by saying gunLine.SetPosition 0.
  • 27:10 - 27:12
    Computers start counting at 0
  • 27:12 - 27:14
    so when we say SetPosition 0 we mean
  • 27:14 - 27:16
    the first position of the line,
  • 27:16 - 27:18
    which is right at the barrel of our gun.
  • 27:18 - 27:20
    So we specify that as transform.position
  • 27:20 - 27:22
    since the script is on the barrel of the gun.
  • 27:22 - 27:24
    So that's the first point.
  • 27:24 - 27:26
    But what's the second point?
  • 27:26 - 27:29
    We don't know yet, that's the part we need to calculate.
  • 27:29 - 27:31
    And that's the part that requires a bit of physics
  • 27:31 - 27:32
    and a bit of raycasting.
  • 27:32 - 27:35
    So if you recall we create a variable called shootRay,
  • 27:35 - 27:37
    which is the raycast from our gun
  • 27:37 - 27:39
    and so the first thing we want to do is
  • 27:39 - 27:41
    setup this ray so that we can utilise it.
  • 27:41 - 27:43
    The ray is going to start
  • 27:43 - 27:45
    at the tip of the gun, so
  • 27:45 - 27:49
    shootRay.origin = transform.position;
  • 27:49 - 27:51
    That's where the ray is starting off.
  • 27:51 - 27:53
    A ray starts at one point and
  • 27:53 - 27:55
    goes in some direction, so we need to specify
  • 27:55 - 27:57
    a direction for our ray, and we say
  • 27:57 - 28:01
    shootRay.direction = transform.forward;
  • 28:01 - 28:04
    and this is something James has talked about previously,
  • 28:04 - 28:06
    we generally treat forward in the Z axis
  • 28:06 - 28:08
    as forward, positive on Z axis as forward.
  • 28:08 - 28:12
    So as the gun is pointing directly away from the player
  • 28:12 - 28:14
    that is forward.
  • 28:14 - 28:16
    So if I say transform.forward what I'm saying
  • 28:16 - 28:18
    is 'that way',
  • 28:18 - 28:20
    so that the bullet will travel
  • 28:20 - 28:25
    directly along the line of this gun barrel and this gun.
  • 28:25 - 28:27
    So we have our ray setup, at the tip of the gun
  • 28:27 - 28:29
    that way, right, forward, so now we need to
  • 28:29 - 28:32
    actually use physics to fire it.
  • 28:32 - 28:34
    And so let me tell you what's going to happen
  • 28:34 - 28:35
    and then we'll walk through the code.
  • 28:35 - 28:37
    The idea is that we are going to fire a ray
  • 28:37 - 28:39
    forward 100 units, because that's
  • 28:39 - 28:41
    how far we say we can fire it.
  • 28:41 - 28:44
    If it hits something, what ever it hits is going to be returned
  • 28:44 - 28:46
    back to us and we're going to say 'the other end of
  • 28:46 - 28:48
    the line is there', whatever it is we hit
  • 28:48 - 28:50
    that's the other end and we draw the line.
  • 28:50 - 28:52
    If we don't hit anything,
  • 28:52 - 28:54
    we still want to fire, but if we don't hit anything
  • 28:54 - 28:56
    what we're going to do is say
  • 28:56 - 28:57
    'where's the other end of this line?
  • 28:57 - 28:59
    It's just way out there'
  • 28:59 - 29:01
    and it's actually such a long line
  • 29:01 - 29:03
    there's literally no way to see
  • 29:03 - 29:05
    the end of it so you just think
  • 29:05 - 29:07
    'cool, he's just firing', you don't really notice.
  • 29:07 - 29:10
    So we need to say shoot a ray, if it hits something
  • 29:10 - 29:12
    that's what we hit, and if it doesn't
  • 29:12 - 29:14
    then just draw a really long line.
  • 29:14 - 29:15
    We do that by saying
  • 29:15 - 29:19
    if(Physics.Raycast, so this again is that raycast function,
  • 29:19 - 29:21
    and we're parsing in to it the ray that we specify,
  • 29:21 - 29:22
    we're saying 'that way'.
  • 29:22 - 29:24
    And then we're going to say 'give us information
  • 29:24 - 29:27
    about what it is that we've hit'
  • 29:27 - 29:29
    and that's why we have this Out keyword
  • 29:29 - 29:30
    and the shootHit variable.
  • 29:30 - 29:32
    If we hit something the variable shootHit will be
  • 29:32 - 29:34
    like 'this is what you hit'
  • 29:34 - 29:37
    cool, we need that information so it's important to have.
  • 29:37 - 29:39
    Then we specify the range, and the range
  • 29:39 - 29:41
    is 100f, it's something that we specified
  • 29:41 - 29:43
    up at the top, it's a variable.
  • 29:43 - 29:45
    Finally we parse in our shootable mask.
  • 29:45 - 29:47
    Meaning this ray can only hit
  • 29:47 - 29:49
    the things we want this ray to be able to hit,
  • 29:49 - 29:50
    shootable things.
  • 29:50 - 29:53
    We're not interested in anything else.
  • 29:53 - 29:56
    If that ray hits something
  • 29:56 - 29:58
    we're going to go in to this code.
  • 29:58 - 30:01
    if it hits something what we're going to do
  • 30:01 - 30:03
    is we are going to get from
  • 30:03 - 30:06
    it the enemy health script.
  • 30:06 - 30:07
    I'm going to talk about that here in a second.
  • 30:07 - 30:08
    So what we're going to say is
  • 30:08 - 30:10
    shootHit was going to have whatever
  • 30:10 - 30:12
    it is we hit, we know we hit something.
  • 30:12 - 30:14
    So we're going to say
  • 30:14 - 30:18
    shootHit.collider.GetComponent
  • 30:18 - 30:20
    So whatever it is I shoot I'm going to say
  • 30:20 - 30:22
    give me your enemy health script and I'm going to store it.
  • 30:22 - 30:24
    We need the enemy health script so we can
  • 30:24 - 30:27
    reduce the life of the enemy.
  • 30:27 - 30:29
    But what if we shot a wall?
  • 30:29 - 30:31
    Or the ground?
  • 30:31 - 30:32
    Or some Legos?
  • 30:32 - 30:34
    Those do not have an enemy health script,
  • 30:34 - 30:36
    those are not able to
  • 30:36 - 30:38
    have health taken away from them.
  • 30:38 - 30:41
    So if we attempt to access that enemy health script
  • 30:41 - 30:43
    right away it's not going to work
  • 30:43 - 30:45
    and we're going to get an error and the whole thing's
  • 30:45 - 30:46
    going to stop working.
  • 30:46 - 30:48
    So what we need to do next is
  • 30:48 - 30:50
    we need to say if the enemy health script
  • 30:50 - 30:52
    does not equal null,
  • 30:52 - 30:54
    this is specifically in here to
  • 30:54 - 30:56
    show you that this
  • 30:56 - 30:58
    function will work even if that component does not
  • 30:58 - 31:01
    It's just going to give you null, and null means nothing.
  • 31:01 - 31:04
    It means one does not exist.
  • 31:04 - 31:06
    So now we need to check it. We need today
  • 31:06 - 31:08
    'hey, by the way, if that
  • 31:08 - 31:10
    actually exists we're going to do
  • 31:10 - 31:13
    enemyHealth.TakeDamage.
  • 31:13 - 31:15
    We're going to parse in our damagePerShot
  • 31:15 - 31:17
    and exactly where we hit it,
  • 31:17 - 31:19
    that's a really nice thing about raycasting too,
  • 31:19 - 31:21
    instead of just having a generic effect
  • 31:21 - 31:23
    if we shoot on the shoulder that's where
  • 31:23 - 31:25
    we hit it, the shoulder, wherever,
  • 31:25 - 31:27
    we get to put the effects exactly
  • 31:27 - 31:29
    where we hit it, which is pretty neat.
  • 31:29 - 31:31
    If you remember in the enemy health script
  • 31:31 - 31:33
    TakeDamage, if I just jump back to that,
  • 31:33 - 31:35
    very briefly.
  • 31:35 - 31:40
    We can see that there is a vector3 hitPoint.
  • 31:40 - 31:42
    So you can see that TakeDamage here
  • 31:42 - 31:44
    needs to have a vector3, needs to have a position
  • 31:44 - 31:46
    in order to move the hitParticles to
  • 31:46 - 31:48
    where they need to be
  • 31:48 - 31:50
    so in PlayerShooting that's exactly what we
  • 31:50 - 31:52
    provide using that raycast.
  • 31:52 - 31:56
    Whether or not whatever we've shot has an enemy health script,
  • 31:56 - 31:59
    regardless of whatever it is we still hit something
  • 31:59 - 32:04
    and thus we say gunLine.SetPosition (1), meaning the second point
  • 32:04 - 32:06
    and we parse in that point that we hit.
  • 32:06 - 32:08
    So whether we're hitting an enemy or the wall or
  • 32:08 - 32:10
    some Legos or whatever,
  • 32:10 - 32:11
    we now have our line
  • 32:11 - 32:14
    the beginning of the gun to the object that we hit.
  • 32:14 - 32:15
    1 line.
  • 32:15 - 32:17
    When we were prototyping this game
  • 32:17 - 32:19
    we just had the raycast shoot by
  • 32:19 - 32:21
    100 units but then we realised that actually it makes more
  • 32:21 - 32:23
    sense if the gunLine stops at
  • 32:23 - 32:25
    that point, we could expand upon
  • 32:25 - 32:27
    the idea to have effects like ricochets
  • 32:27 - 32:29
    and things like that but we didn't want to get too bogged down.
  • 32:29 - 32:31
    So actually what this is saying is
  • 32:31 - 32:33
    if we hit something
  • 32:33 - 32:36
    then we end that line renderers second
  • 32:36 - 32:38
    point or it's end point at
  • 32:38 - 32:40
    the point at which the ray hit it,
  • 32:40 - 32:42
    so when we shoot a bit of the environment
  • 32:42 - 32:44
    it's going to stop at that point,
  • 32:44 - 32:46
    likewise with the enemies.
  • 32:46 - 32:48
    So all of that happens
  • 32:48 - 32:50
    if we hit something.
  • 32:50 - 32:52
    What if we don't hit something? That's our else.
  • 32:52 - 32:55
    We're going to say gunLine.SetPosition
  • 32:55 - 32:57
    1 again because it's the second point,
  • 32:57 - 32:59
    the second part of the line, and what we're
  • 32:59 - 33:05
    going to say is shootRay.origin, so where the ray starts,
  • 33:05 - 33:09
    + shootRay.direction * range;
  • 33:09 - 33:11
    So what that's going to mean is it'll take
  • 33:11 - 33:15
    the point and then it's going to multiply (0, 0, 1)
  • 33:15 - 33:17
    because that's forward in the Z direction,
  • 33:17 - 33:19
    by 100, which is the range, and it's going to say
  • 33:19 - 33:21
    this point and then take it way down there
  • 33:21 - 33:23
    and then that point, and then it's going to draw a line.
  • 33:23 - 33:25
    So it's really simple, it'll say
  • 33:25 - 33:28
    one end, the other end, we're going to draw a line between it.
  • 33:28 - 33:30
    So a lot of physics stuff in there but basically
  • 33:30 - 33:32
    we're just attempting to point at something
  • 33:32 - 33:34
    and if we're successful at
  • 33:34 - 33:36
    pointing at something we're going to draw a line to it
  • 33:36 - 33:39
    and take damage from it, otherwise we're just going to draw the line.
  • 33:39 - 33:41
    So the else there effectively
  • 33:41 - 33:43
    is giving us the ability to shoot in
  • 33:43 - 33:45
    a direction if we don't hit something on the
  • 33:45 - 33:46
    on the shootable layer.
  • 33:46 - 33:48
    So if you remember that the level is basically a box,
  • 33:48 - 33:50
    if you're aiming around in the other direction
  • 33:50 - 33:52
    and you're effectively raycasting off
  • 33:52 - 33:54
    of the screen you still want to see the
  • 33:54 - 33:56
    gun fire so we're just giving it a range
  • 33:56 - 33:58
    of 100, which is outside of the camera
  • 33:58 - 34:02
    frustum, the view that you can see so we're
  • 34:02 - 34:04
    just spraying bullets around even though we don't hit anything.
  • 34:07 - 34:09
    What we'll do now that the gun barrel
  • 34:09 - 34:11
    script is on there is save our scene
  • 34:11 - 34:12
    if you haven't saved in a while.
  • 34:12 - 34:14
    Now with the player selected
  • 34:14 - 34:16
    in the hierarchy we're going to
  • 34:16 - 34:18
    look at the Apply button in the upper
  • 34:18 - 34:19
    right hand corner
  • 34:19 - 34:21
    You'll recall we clicked and dragged the player
  • 34:21 - 34:23
    and turned it in to a prefab but the
  • 34:23 - 34:25
    prefab that we have on file is now
  • 34:25 - 34:28
    slightly different than the prefab we have in our scene.
  • 34:28 - 34:30
    The one on file doesn't have all the
  • 34:30 - 34:31
    changes we just made
  • 34:31 - 34:33
    If we would like to update the one we have
  • 34:33 - 34:35
    on file we have to click the Apply button
  • 34:35 - 34:37
    in the upper right hand corner.
  • 34:37 - 34:39
    That will apply all of the changes we've made
  • 34:39 - 34:41
    to the copy we have on file,
  • 34:41 - 34:43
    thus saving it, if you will.
  • 34:43 - 34:45
    The way that you notice the difference between
  • 34:45 - 34:48
    a prefab and a prefab that
  • 34:48 - 34:50
    needs updating is that somethings will appear
  • 34:50 - 34:52
    in bold, so if you note the difference between
  • 34:52 - 34:54
    Player Movement's properties and
  • 34:54 - 34:56
    Player Health's which is added after
  • 34:56 - 34:58
    that we made it in to a prefab
  • 34:58 - 35:01
    you'll see that these are in bold and when I update
  • 35:01 - 35:04
    or apply the changes and look back down
  • 35:04 - 35:06
    some of them change so that the things
  • 35:06 - 35:09
    that are still bold are things that are in the scene.
  • 35:09 - 35:11
    So now we know that's up to date we can carry on
  • 35:11 - 35:13
    using it in other scenes and if
  • 35:13 - 35:16
    there are instances of this prefab elsewhere
  • 35:16 - 35:18
    then you would see those changes are
  • 35:18 - 35:20
    automatically applied.
  • 35:20 - 35:22
    Let's go ahead and everyone
  • 35:22 - 35:24
    turn your volume down because we're about to test this.
  • 35:24 - 35:26
    Cool, let's see how loud it is.
  • 35:29 - 35:30
    Oh yeah!
  • 35:31 - 35:32
    That's what I'm talking about,
  • 35:32 - 35:33
    that's an American gun right there.
  • 35:36 - 35:38
    Just to reiterate, do not worry about
  • 35:38 - 35:40
    this error that you will see appearing at the
  • 35:40 - 35:42
    bottom of the screen, it's deliberate,
  • 35:42 - 35:45
    this actual mistake is a genuine mistake
  • 35:45 - 35:48
    that we want to show you how to fix.
  • 35:49 - 35:51
    What you will notice is that at the
  • 35:51 - 35:53
    bottom of the screen you have an error.
  • 35:53 - 35:56
    So just to give you some insight on
  • 35:56 - 35:58
    catching errors in Unity.
  • 35:58 - 36:00
    Sometimes there'll be a compile error,
  • 36:00 - 36:02
    in that you've written something wrong in a script
  • 36:02 - 36:04
    and the bottom of the screen
  • 36:04 - 36:07
    will show you where and what in that script has happened.
  • 36:08 - 36:11
    And this is all contained within the console.
  • 36:11 - 36:13
    So if you go to Window - Console
  • 36:13 - 36:15
    you will see that there are a lot
  • 36:15 - 36:18
    of errors saying all about the same thing,
  • 36:18 - 36:20
    'set destination can only be called
  • 36:20 - 36:22
    on an active agent that has been
  • 36:22 - 36:24
    placed on a nav mesh'.
  • 36:24 - 36:26
    So remember that the word 'agent'
  • 36:26 - 36:28
    is referring to the enemy,
  • 36:28 - 36:31
    the enemy has that nav mesh agent component
  • 36:31 - 36:34
    and set destination is the function of code
  • 36:34 - 36:37
    that we used to tell it to seek out the player.
  • 36:37 - 36:40
    So we said nav.setDestination player.position.
  • 36:41 - 36:43
    What is actually happening there is that there is
  • 36:43 - 36:46
    a problem in our Enemy Movement script.
  • 36:47 - 36:49
    What we can do is double click on that
  • 36:49 - 36:51
    error in the console.
  • 36:51 - 36:53
    Watch that one more time, I double click that and it
  • 36:53 - 36:57
    takes me to what's causing that error.
  • 36:57 - 36:59
    And if you recall earlier we mentioned
  • 36:59 - 37:01
    that there are some bits of code that are
  • 37:01 - 37:04
    commented out, that are disabled currently in this.
  • 37:04 - 37:07
    When we first made the enemy chase after you
  • 37:07 - 37:09
    we didn't have a concept of
  • 37:09 - 37:11
    the enemy's health or the player's health.
  • 37:11 - 37:13
    So having those things in our script
  • 37:13 - 37:15
    wouldn't have made any sense.
  • 37:16 - 37:19
    So now we do have those things.
  • 37:19 - 37:23
    The player can be killed or the enemy can be killed
  • 37:23 - 37:25
    and if it is then
  • 37:25 - 37:27
    setting it's destination on the nav mesh
  • 37:27 - 37:29
    doesn't make any sense any more
  • 37:29 - 37:31
    so it's creating an error.
  • 37:31 - 37:33
    So now what we can do is we can
  • 37:33 - 37:35
    bring back those references to
  • 37:35 - 37:38
    the enemy's health and the player's health
  • 37:38 - 37:42
    and every time we do an update
  • 37:42 - 37:44
    we want to check if both the player and the enemy
  • 37:44 - 37:46
    are alive before we say
  • 37:47 - 37:49
    setDesination, because if they're not
  • 37:49 - 37:50
    then we're in trouble.
  • 37:50 - 37:52
    I'm going to use a shortcut here
  • 37:52 - 37:55
    I'll teach you which is command /
  • 37:55 - 37:58
    which is a way of commenting out and entire line.
  • 37:58 - 38:00
    That's control / for you PC folk.
  • 38:00 - 38:03
    Yes, for PC, and we can do all of this at once.
  • 38:04 - 38:06
    We've re-enabled this if statement and
  • 38:06 - 38:08
    else structure around this to just check
  • 38:08 - 38:10
    those different scripts, so it's checking the
  • 38:10 - 38:12
    enemy's health, it's checking the player's health
  • 38:12 - 38:14
    and if they're both more than 0 then it should
  • 38:14 - 38:17
    keep trying to seek out the player.
  • 38:17 - 38:20
    But if they're not then we switch off the nav mesh agent.
  • 38:20 - 38:23
    So the error that we were having in Unity
  • 38:23 - 38:26
    is saying that setDestination is effectively invalid
  • 38:26 - 38:28
    and we're solving that by checking
  • 38:28 - 38:31
    if the player is actually dead to do it.
  • 38:31 - 38:33
    And likewise if the enemy has enough health
  • 38:33 - 38:35
    to be moving around.
  • 38:35 - 38:37
    If not we switch off that component
  • 38:37 - 38:40
    by using .enabled = false.
  • 38:41 - 38:44
    So uncomment those lines in Enemy Movement,
  • 38:44 - 38:48
    save the script and then return to Unity.
  • 38:48 - 38:50
    Basically all of Enemy Movement should
  • 38:50 - 38:52
    now be enabled, you shouldn't have any comments
  • 38:52 - 38:54
    in it at all and that should get you to the
  • 38:54 - 38:55
    same point as us.
  • 38:55 - 38:58
    Okay, so the last part of this
  • 38:58 - 39:02
    is to look at the Player Health script.
  • 39:02 - 39:04
    What we're going to do is
  • 39:04 - 39:06
    reopen the Player Health script,
  • 39:06 - 39:08
    so if you double click on it
  • 39:08 - 39:10
    so go in to Scripts - Player
  • 39:10 - 39:12
    double click on the icon to open it.
  • 39:14 - 39:16
    And you'll see that
  • 39:16 - 39:18
    on the player's death
  • 39:20 - 39:21
    we've got some commented stuff here,
  • 39:21 - 39:23
    so we want to be able to put that back in
  • 39:23 - 39:25
    so that when the player dies
  • 39:25 - 39:26
    he can no longer shoot his gun.
  • 39:26 - 39:29
    But we haven't got our references to PlayerShooting yet.
  • 39:29 - 39:31
    Because it's turning red it's saying
  • 39:31 - 39:33
    'I don't know what PlayerShooting is and I
  • 39:33 - 39:34
    don't know what DisableEffects is'.
  • 39:34 - 39:36
    It can't find the reference to that so it's
  • 39:36 - 39:39
    turning red to alert us that there's a problem.
  • 39:39 - 39:41
    So on line 19
  • 39:41 - 39:45
    PlayerShooting, reference to the PlayerShooting script
  • 39:45 - 39:46
    which we've named the same.
  • 39:46 - 39:48
    So this can cause some confusion.
  • 39:48 - 39:50
    We've got PlayerMovement, PlayerMovement
  • 39:50 - 39:52
    remember this is the type, which is the name
  • 39:52 - 39:55
    of the script, and this is the name of the variable.
  • 39:55 - 39:57
    Names of variables can of course be anything
  • 39:57 - 39:59
    you want them to be but if I name PlayerMovement
  • 39:59 - 40:02
    Blah I will have to write Blah anywhere else.
  • 40:02 - 40:03
    But we're not going to do that.
  • 40:03 - 40:06
    We've named it something sensible, which means it's going to
  • 40:06 - 40:09
    sync up with the other instances and work.
  • 40:09 - 40:11
    So the last thing we need to uncomment is
  • 40:11 - 40:13
    the GetComponentInChildren
  • 40:13 - 40:15
    for PlayerShooting because remember
  • 40:15 - 40:17
    that the PlayerShooting script is on the
  • 40:17 - 40:19
    GunBarrelEnd, it's not on the Player
  • 40:19 - 40:21
    so we need to find that component in the children.
  • 40:21 - 40:23
    And now we've got our references and we've already
  • 40:23 - 40:28
    uncommented the codes about shooting when dead.
  • 40:28 - 40:30
    They're no longer red.
  • 40:30 - 40:32
    So it should all work.
  • 40:32 - 40:34
    Make sure that you save your script.
  • 40:34 - 40:37
    It's very important, and switch back to Unity.
  • 40:38 - 40:41
    You can then go ahead and play
  • 40:41 - 40:43
    and test your game.
  • 40:45 - 40:47
    Now we can kill them, there's no more error
  • 40:47 - 40:49
    about the nav mesh destination.
  • 40:50 - 40:52
    It's a very easy game, 1 enemy.
  • 40:53 - 40:56
    And we can also be killed by them.
  • 41:01 - 41:03
    So that is the end of phase 7.
Title:
Survival Shooter Tutorial - 7 of 10 : Harming Enemies - Unity Official Tutorials (new)
Description:

more » « less
Video Language:
English
Duration:
41:04

English subtitles

Revisions