HowTo: Build a 3rd person shooter in Unity - Part 4

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Wrong sub, surely?

👍︎︎ 9 👤︎︎ u/RadicalDog 📅︎︎ Apr 05 2018 🗫︎ replies
Captions
hey welcome back jason here community3d college it's time to pick up on our third person shooter and start hooking up an enemy something that we can actually kill and have it fight back and right now we've got it set up so that we can shoot a little capsule that's kind of an enemy so i can turn and now run over here keep clicking on him enough times i've got my audio muted on the gunshots but eventually he dies so click and kill him and you know lots of exciting stuff right i think it's kind of dull though so let's get in a real enemy character have him start animating have him walk over start shooting back at us and add a little bit of a challenge so the first thing i need to do is just find a character and i'm using uh one of the toon soldier characters so i think i'm just going to find something that kind of matches that something in the same theme i'll go with a free one but there are some really good ones by the same guy so if you're interested in you know buying a model or something or a pack i'd recommend grabbing some of his they look pretty good and they'll really match the theme here so i'm going to import in this tune soldier the world war ii guy and we'll just use him as our enemy it looks different enough from our player's character now it's imported let's see where's that at right here tune soldiers ww2 demo and i'm just going to grab this model and we've already got the enemy right here so we've got this enemy with the capsule capsule's a child i'm just going to take the model right here drop it on to the enemy so it becomes a child it should be zeroed out if you grabbed a different model just uh right click on the transform and hit reset make sure the position's all zeroed and centered in the right rotation sometimes these things are put in a little bit weird you know in the asset pack and they're offset so i just want to make sure that's zeroed out now i can delete that capsule and i've got well a slightly better character already right if i hit play i can at least shoot this guy in the back let's see there we go so now i can click on him a couple times and shoot him in the back and he should die yep there we go so this is one of the benefits again of separating out our visual effects or our visual part of our characters and other things from the actual implementations our health is all on this enemy the visual part's all a child we can totally swap that out without anything really breaking but i want to make this guy um become aggro start sensing players and then move towards them so i'm going to start here just by adding in another collider let's add a sphere collider what i want to do is set up an aggro radius and i'm just going to use a sphere collider with the trigger then when the player enters that it'll count it as you know the trigger integral fire he'll be marked as aggro and then go into some aggro state where he starts actually trying to attack so i've got the collider added um i want to check the is trigger box otherwise things are going to get really weird really fast and then just crank up the radius oh i don't know maybe 15 seems like a good range for this right now just get it big enough that it can um detect it when i walk in but it's not so big that when i start it's in there otherwise not super easy to test right i'm going to be able to walk just a little bit before aggroing them all right let's see save that and then i want to create a new script so i want to create some sort of a script that manages handling his aggro just checks for players entering and then sends off an event and two other scripts to tell them hey we're aggro and we're ready to fight so i'm gonna go into the scripts folder and create a new c sharp script and what do i want to name this thing [Music] oh i think i'll name it aggro protection i'll probably end up renaming it later oh i didn't get it named in time so let's fix it here the name of the class always has to match the name of the file or else things just aren't going to work now save and clean up my formatting with control k control d and let me think for just a moment so for aggro detection we need ontrigger enter and i think that's about it so we can get rid of start and update delete both of those and then just go over here and say on trigger enter right there hit enter let it auto create it and then i want to check when the trigger enter fires what the collider is and if it has a player on it basically so let's do something like this bar player equals other dot collider the collider is or not collider it's other dot get component that's right colliders deprecated i always do that so other dot get component and here we have a player movement script on our player so for now i'm just going to use that we'll see if we can get the player movement and if we do then we'll count that as you know being aggroed otherwise we're going to ignore it so to do that we just check to see if player is not equal to null then we know we want to be aggro so this again is just checking to see if there's a player movement component on the thing that triggered our ontrigger enter and if it's not null so there is one then we want to do something um i think the first thing we want to do is well let's just debug log a line real quick and just call this aggrode so now we'll have a debug entry when we become aggro and just try that out real quick we should be able to walk in see a log right here up here saying hey we're aggro it's not going to actually aggro or do anything but we'll get the log entry right oh we did not get a log entry let's take a look at the enemy again ah i did what i always do created a script and forgot to attach it so let's add that aggro detection script to the enemy try one more time run over here oh and we got a log entry i can see it right there aggro cool and if i walk out and then walk or let's run out and run back in i should get the log entry again there we go so that's good now the first thing i want to make this guy do before he starts fighting and everything else is just turn and face and kind of run towards the player so to do that we're going to use the built-in navigation system so just select the enemy and we'll just add a nav mesh agent now there is a new navigation system that adds a little bit more um i don't think we need it for this though so i'm just gonna stick with the built-in stuff and the new stuff i think is just gonna eventually all be built into the engine anyway let's see we've got a navmesh agent set up or added and i want to well actually before i play with the stopping distance let's bake a nav mesh so to make this guy actually navigate we need to select our environment and we don't really need everything here but i'm just going to select it all because it doesn't make a big difference and then on this little static drop down oh let's pull this over to the side you can check navigation static and just hit yes change children you get that little dash there just meaning that something is selected here but it's just navigation static is selected for all of our objects what that does is make it so when we go to the navigation window which i have the tab right here but you just go to window and then navigation never find these there it is it just opens that tab up and then go to this little bake mini tab and with everything that's marked as navigation static it'll all be calculated in and used for generating a nav mesh so now i can hit generate or bake and you'll see that i got nav meshes this blue area everywhere and i did get it on top of some of these buildings kind of a downside of selecting those buildings but it doesn't matter because our players and characters aren't getting up there anyway it's not going to make a bit of difference here what this area is doing though is just showing where the ai agents or the nav mesh agents can walk so they can walk in any of these blue areas now if they want to go up here they kind of got to go up and around and that's just because of the slope right here on on these um meshes on the stairs that's kind of a weird one though but whatever i think it's good enough the character should be able to run all the way down here and all the way over to here and right now he's just going to come around towards the player a little bit so i'm going to save my scene just save off that nav mesh generation and then let's go back into our aggro detection script and temporarily i'm just going to add in a call to tell the character to go chase after the player and then we'll move that out of here so on trigger enter hits we find a player if there is a player we're going to say git component nav mesh agent and i'll just hit control period and add the using statement for that i need that unity engine.ai for nav mesh agent and we got to put the parentheses and then we call set destination and we'll just give it player player.transform.position so it's just going to tell the character to run over towards the player let's give that a try hit play get in and as soon as i run into aggro range he should just kind of run right towards me there we go came right to where i was when i walked in range and i noticed he doesn't you know follow me around or anything else he's just when i entered the trigger got that call and went to the point where i entered so if i enter over here let's see i gotta exit oh i can't even exit the trigger because this trigger moved i need to move way way way over here let's just pull this side by side so we can see it and select that enemy just make sure it's really clear what i'm talking about here so the enemy where where is he where's his oh there it is there's a sphere collider so when i enter the collider right about there he should run over to that point as well i'm just gonna want to demonstrate this right there so now he's gonna run to that point where i entered and if i leave here and re-enter here he's gonna run back to there okay interesting stuff right so let's uh get back in here and start cleaning this up a little all right i'm gonna open this script up and i think what i want to do is create just an enemy movement script just something simple that's responsible for setting these nav mesh agent destinations uh getting the character to the right place and playing the right animations so i'm just going to create another script actually let's just go back into the editor and we'll just create an enemy movement now this script is going to listen for aggro so when i get aggro it's going to know who to target and who to run after right now we only have one character but never know we could add in the ability for enemies to go chase after something else we may as well make it a little bit more robust so if we want to have a bad guy go chase after something that we're trying to rescue or a character that we're trying to protect or something we can do that as well we don't want to just hard code it to only go to the player so i'm going to clean up that formatting and get rid of these two for now and then we'll add in an awake let's do private void awake and here i want to get my aggro detection script so i'm say aggro detection equals get component aggro detection and i'll just generate a field with that control period remember just generates or pops up dialogue hit enter and it generates that field then i'll say aggro detection dot on aggro and this doesn't exist yet so i'm thinking i want to do an event here for on aggro and then have it target something so let's uh copy that go into aggro detection and right up here i'm going to add a public event action and we need to add a using statement for system for action to work and it's going to be of oh let's do transform as the type again keep it pretty versatile so we can go target just about anything and i'll just call this on aggro again just pasted it in i'd already copied it from my clipboard and then i'll assign an empty delegate as the default again this is just so that i don't have to do a null check when i'm calling this event so here i'll just call on aggro and pass in player.transform and we're good now i'm going to leave this debug log but i'm going to cut line 19 so just shift delete to cut it and then hold shift down arrow hit delete without holding shift and get rid of that extra line and then remove all the using statements and that extra space so now what will happen is we get aggro detection if something gets aggro it's player right now that's the only thing that we look for if a player aggros we call our on aggro event and anything that's listening will fire off if nothing's listening we have an empty delegate so nothing bad happens all right i'm going to go into enemy movement and now this exists so i can just do plus equals and hit tab and it's going to auto generate that method for me and the trans oh i need to hit enter the transform here is just going to be the target so let's name that target and then i'm going to paste in that copied nav mesh agent call and here instead of using player.transform i'll just use target.position because remember target is a transform now we do have this error again because remember we need the using statement for unityengine.ai so just hit control period again and enter to add that in and again clean up those using statements and get rid of that so all we've done so far is switch over our movement into a different script and the real reason for this is just to separate out the concerns completely i want to have a single script it's just responsible for acro detection and if i want to expand on aggro detection i can just add it into there and i want my movement script to just be responsible for moving towards targets stopping when it gets to them that kind of stuff in fact in this case we probably don't even need it to do the stopping because we can go into our nav mesh agent right here so i select the enemy and we have a stopping distance here so we can actually just set the stopping distance for how far out it's going to stop and i think maybe let's go with like eight meters from now he's gonna get a little bit close come up and then eventually do some shooting so i'm gonna save this and i need to add that other script let's add in our enemy movement and i'm going to drag that up here so there the scripts are just kind of next to each other actually i think i'm going to pull both of these up to here get them up by the health so that way it's kind of separated out from the other components and save and then just play just want to make sure that he runs over towards me there we go we turn get in there and he turns and faces me and comes right towards me perfect so the next thing i want to do is just make him animate since we have an enemy movement script already we can pretty easily hook that up let's take a look at our player movement script one more time though so in player movement if you remember we have an animator that we cache just from the get component and children call because our visual part is a child of the actual object and then here let's select that and if you hit shift f12 it'll find all the references and you can see it right here we've got the part where we get it and then we can click right here to see the other part where we use it which is just an update and all we're doing is setting the float for the speed to our vertical now our enemy doesn't have a vertical but there is something on the nav mesh agent that we can use so i'm going to go into nav or enemy movement again and let's cache our animator so do animator and escape so we don't get that bad autocomplete equals git component in children of type animator and again control period enter to generate that field and then we just create an update so let's do private void update and i'll just say animator dot set float speed and then the value that i want to use is going to come from this nav mesh agent but we don't have the nav mesh agent cached so let's do that as well i'm going to just cut this and we'll go right up here just go right above this one and say nav mesh agent just like that lower case and of course equals get component nav mesh agent just pasted it right in and then control period to generate that field as well there we go so now we're not getting the nav mesh agent every frame in this case when we're just doing it in the on aggro didn't really matter because it was just kind of a one-off thing that wasn't happening a lot but if we're going to do this every frame i don't want to um i don't want to keep calling git component so here um actually let's create a float i'm going to say float speed equals nav meshagent dot speed or not speed it's um velocity nav message.velocity.magnitude speed is the value that you set on there for how fast the character can go so that's more of a it's an adjustable thing for the inspector so you can make a guy go fast or slow magnitude of the velocity is how fast he's actually moving so here we'll just copy this paste it right in and add the semicolon and we're good and we could just drop this right into here just like to separate it out into another variable just to make it a little bit more obvious what it is um actually i'm going to call this current speed so we know it's the actual speed the thing's moving just naming it as explicitly as possible so let's jump back over here and i don't know if our enemy is set up yet it's not so our enemy this tune soldier doesn't have an animator controller on him now because he matches with our other character it's from the same pack and same set same guy i think what we can do is just reuse that animator controller so let's see let's hit the search box and pick i think we're using soldier controller let me double check where's this one located yep that's in the demo so soldier controller from our animation folder and that'll probably just work let's give it a try hit play and run over here get aggro yep and he starts running he does do some weird turning he's like running and not turning right that's something to fix later it's just a little bit of extra animation controller work and navigation work so that he'll turn and run or be a little bit more realistic but for now he um he runs over to me he animates he stops when he gets there and starts idling oh can i let's see if i can aggro him one more time so just run out run back in there we go and he comes over i is chasing me and he's ready to shoot right um oh what if i okay the last thing i want to add in here is a way to set this so that he doesn't just run to that target position so right now when he aggroes we set the destination he stops at that point at the aggro point he doesn't really follow me around so if i keep running away he's not going to keep chasing after me he's not really that aggro so what i'm going to do is instead of setting the destination here i'm going to copy target i'm just going to say this dot target equals target and then i'll generate a field and now we have a private transform named target so here we're just taking in a target and we're setting a variable on our class instead of using this parameter so that's what this this keyword does saying hey i know these variables have the same name use the one from the class don't use this one right here so if you see this dot here again just to explicitly say that you want to reference the one in the class not the parameter that has the same name just a little shortcut there to allow you to have parameters that have the same name now sometimes it's not a great idea to have parameters that match the name of the thing in your class but it can be unavoidable and sometimes it's just named better and it's better to keep it that way than adding something else there so here we're setting a target and now what i can do is just cut line 23 get rid of that space and i can say if target is not equal to null set destination to target.position in our update there and let's add the braces around it so now every time we go through update if we don't have a target we're just gonna do pretty much nothing we're gonna set our speed to zero whatever we probably don't even need to do that because it's gonna be at zero by default anyway actually here yeah let's just cut that and put it right there so now we're not even calling into the animator to update the speed until we've reached or made a target now let's hit play now he should gonna run towards me follow and then stop about eight meters out all right let's see there he goes he's running he's chasing he's still chasing me um and i go over here and he's still chasing perfect so he'll just keep following me around now you may notice when i'm running around these things like that i can totally clip out my character and i can't see him and that's the next thing that i want to fix up so yeah we're at 20 something minutes let's go through and fix that because it's actually a really easy thing to resolve so what we can do to fix this let's save my scene again is select the cinemachine virtual camera this cmv cam one remember that was created by going into cinemachine and creating a new virtual camera that's also what's allowing us to track the player and stay right behind them have that semi-smooth movement that we've got now what we can do is go down to the extensions area where it says extensions add extension click on it and there's a cinemachine collider option now if you just add this it's not going to do what you want you need to also select the strategy right here and just change this to pull camera forward now zero code written just added in a thing and pick from a drop down and watch what happens so here i'm gonna unselect the camera so we don't have the overlay now if i run over here oh did not work let's see let's let's get behind something just trying to get that to occlude again there we go so you see how it i don't really like that though so part of the issue that i'm having right now is just that the camera the center point is right here that's what we're looking at so my character is still kind of getting occluded but you'll see that when we go like this it pops right over and the occlusion disappears it's as soon as this point right here becomes occluded now i can adjust that too and make it a little smoother just by selecting that v cam scrolling down and pulling up this damping value so say i put it like .5 now when i turn you'll see that it did that little pull in so as soon as i got occluded it pulls in the camera a little bit smoother and i kind of like that effect the speed here i'm not sure if this is in seconds it feels like it's in seconds so if i go like 0.25 it's quite a bit faster and now at least i'm not getting included on my shooting area we are still kind of occluding our character which i don't like but i think we'll fix that up later because it's pretty good i can still see where i'm aiming and i think it's going to be rare that i get into cases where i'm backed up and i you know can't see the character but i can see this so i think we're good there um i'm gonna end this part right here and then i think uh next time we'll go through and actually make the enemy shoot or you know never mind let's just do it let's make the enemy shoot at the player so let's add in another script here i'm going to select the enemy and we'll create a new c sharp script name it enemy and i'm going to make this one just be responsible for shooting at the player so the first thing i'm going to need is a reference to my aggro detection because i want to know if i get aggro and that's when i start shooting so i'll just do a private void awake again and cache my aggro detection just aggro detection with the lowercase a equals get component aggro detection and generate the field with the control period again and then clean up the formatting and control k control d to clean that up and let's see we don't need start um we'll probably use an update so i'll just leave that here now in act or in awake when we have the hybrid detection i'm just say aggro detection dot on aggro plus equals and then hit tab this is going to say hey we've aggroed and we now have a target so we'll name this target and um let's see what do we want to do i guess we just need to get the player because our target here for actually attacking is going to be a little bit different than our our target for aggro detection because we need to make sure that the thing has a health component on it right we want to target something that has health if we're gonna shoot so i'm gonna say health health equals target dot get component help and we only want to attack things that are you know that have health so we'll say if health is not equal to null um i don't want to do this i'll say health target equals health and then i'll generate a field for that so this health target is just going to be the thing that our enemy is going after and it's the health component of that target now to do an attack we use our update let's do private void update and i usually follow a very similar pattern first we'll check to see if we should be attacking at all so here we just know if health target is not equal to null that means we at least have a target then we want to check if we should attack so say if can attack then attack just like that this is almost always the way that i start these off just stub them out and then generate a method go up to here and generate another method and i like to do them in that order just so can attack shows up above attack and i don't have to move them around and then here in our can attack method we'll just do a a really basic timer so let's say um return attack timer greater than or equal to attack refresh rate and neither one of these fields exists so i'm going to generate them both generate field generate field and they're going to be wrong it's going to generate them as ants and i want to both be floats one thing you can do is hold down alt [Music] click and drag to select both of them like that and then just type in the word float and just update them both at the same time now our attack refresh rate is actually going to be a serialized field so i'm going to grab that line cut it with shift delete move it up to the top and then add the serialized field attribute because i want to be able to modify this in the inspector and i'll give it a good default of maybe 1.5 seconds so let's see we've got an attack refresh rate and an attack timer and here we're just returning back whether or not the attack timer is greater than or equal to the refresh rate as it stands it's never going to be true because our attack timer is always zero so to fix that we just go into update um let's do it right here we'll only update our timer if we have a target i'm going to say attack timer plus equals time dot delta time let's just increment our attack timer after one and a half seconds of having a target can attack will be true now with can attack is true so we'll get here we'll go count attack's true which means the timer's ready we'll go into attack the first thing we always want to do is just set attack timer back down to zero that way if something goes wrong we have an error or a bug in our code in our attack and there's an exception we want to make sure that our attack timer is at least getting reset so it's not spamming an error every single frame and lagging this out while we're trying to debug and figure this out so we've got the attack timer reset [Music] and now we just need to do some damage so we already have a health target so just a health target dot take damage and we can give it a damage amount we could make this variable i'm just going to pass in a one for now so remember our health component that we used on the enemy takes damage and it reduces the current health current health drops low enough they die and our current implementation of dying is just disabling our game object so now when i get into aggro range of the enemy should deal damage to me every one and a half seconds and then i die after however many points of damage now our player doesn't have a health component so we need to add that on so just go health like that add it on we'll start at five just like the enemies and then i move it up here just again to keep all the scripts together now i'll save and i should be able to run into aggro range have the guy start chasing after me and shoot me oh look at that he's actually running in place right now i'm gonna fix that first so the reason for that remember we pulled the um let me let me just go back into enemy movement we pulled this line up into the part where he has to have a target so speed is sitting at the default value now i could pull this back out and change it but the real reason that it's happening is if we go into this controller so select the enemy get in the animator controller if you look at the parameters the speed value is just set to one and set it back to zero and be good too although i may just pull that code back out just in case somebody changes it i guess in a bigger project you may have to worry about people going in and messing with those things so it wouldn't hurt to have that line in there resetting it back to zero okay but now he's good i'm going to select my player and i'm going to switch over to debug view in the inspector so we can see the current health now it's at five i aggro one and a half seconds should pass and is he not shooting okay oh you know what it is the enemy script isn't on the enemy so here we go select the enemy add the script and he should still just oh he's not going to start shooting because he's not aggro so let's add that stop playing at it drag it up here and hit play one more time and let's get that player selected so we can watch the health now he should attack there we go four three two one and i'm disabled and dead perfect okay so i think we're good now um in the next section i'm not sure what we're going to dive into probably some more enemy stuff maybe get them animating and you know playing some gun sounds some particles and other stuff if you have specific requests though just drop them down in the comments below and i'll try to work in this the stuff that you want to see for this game into the next video or one of the videos after that anyway um thanks for watching again don't forget to like subscribe and share with friends and have a great day keep building games
Info
Channel: Jason Weimann
Views: 32,572
Rating: undefined out of 5
Keywords: Unity, Unity3D, Unity Shooter, Unity3D Shooter, Unity 3rd Person, Unity 3rd Person Shooter, Unity3D 3rd Person Shooter, Unity3d 3rd Person, Shooter Game, Build a Shooter, Build FPS, Unity FPS, Unity3D FPS, untiy build fps, Unity Third Person Shooter, Unity Third Person, Unity3D Third Person Shooter, Unity3D Third Person
Id: qmdC7kydWa4
Channel Id: undefined
Length: 32min 40sec (1960 seconds)
Published: Thu Apr 05 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.