C # Godot | Creating a Turret Like Enemy

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys this is mitch with fine point cgi and today we're going to talk about creating a turret like enemy and in this case it's an archer inside of godot using c sharp so we're going to go through the process of creating the enemy we're going to go ahead and code its detection system we're going to go through the process of ray casting determine if the player is behind an object we're going to go ahead and set up all of our animations and shoot our projectiles and do damage to the player and this is kind of part of my tutorial series of creating a 2d character controller kind of at this point it's moving more towards like being an actual 2d platformer but you know if you feel like it you can watch the previous videos if not this one is a standalone video so that's what i have in store for you guys today so let's go ahead and get started okay so the first thing that we need to do is we need to go ahead and do a little bit of housekeeping so the first thing i'm going to do is i'm going to right click the player i am going to come down here and i am going to save branch as seen as player i'm going to click save and same thing with spike trap i'm going to right click it save branch as scene spike trap now that we've got that done what i'm going to do is i'm going to go ahead and right click add a node at a 2d node i am going to right click add a node add an animated sprite and i'm going to right click and add in an area 2d and what this area 2d object is going to be it's going to be the the enemies detection radius and what that's going to do is it's going to event it's going to tell the character or the enemy in this case that something has gotten into its radius that it can go ahead and recast to try to hit it so then if you look at the detection radius it says hey you need to have a collision shape or collision polygon so we're going to do is we're going to right click and add in a collision shape and we're going to go ahead and make that into a circle here and let's go ahead and just make it something fairly large something like that and then we're going to go ahead and right click our node 2d and add in a position 2d this is the bullet or arrow or project august project that would be better and what we're going to do is we'll figure out where this is supposed to be but we'll keep it in the center for right now but that's where that's going to spawn so actually we'll say projectile spawn all right now with the animated sprite we've got a little exclamation point here so let's go ahead and go over to our frames and add in a new sprite frames and go ahead and click on that now in my case i'm going to go ahead and use the archer hero by dark pixel uh this is a really cool little um character thing that he's got which has a bunch of cool little things so if you wanted your character to actually be an archer right this is a pretty good little um design here but in my case i'm just gonna go ahead and use this for our little project so uh let's go ahead and download it download now and hit no thank you and then just click on download and you see i've already downloaded it so i'm just gonna hit cancel if i come over to my downloads you'll see that i have archer hero here i've already extracted it you can just right click it and extract it if you'd like and i basically just copied this so ctrl c and let's go over to our project which in my case it's document celeste like tutorial this has been like my ongoing little platformer like series that i've been doing with you guys so i'm just going to throw it in my platform metrovania assets and then we are going to go back to the project and you'll see that it loads it in right here so we're going to go ahead and select all of these go to import presets 2d pixel and now that we have that let's click on our animated sprite make sure that our sprite frames is up like it is and we are going to click on this little add frames to sprite sheet or from a sprite sheet and we're gonna pick normal attack so we're gonna go with eight and four and we are going to uh go ahead and click on these like so and that's gonna go ahead and give us a little animation so if we kind of zoom in on our guy and we go to our default animation and we play it he just shoots a little arrow awesome so now that we have that let's change this to shooting so next we're going to go ahead and add a new animation we're going to call it idle and we are going to click on our little ad frames we're going to choose our idle and we're going to change this to 8 and 2 and we're going to click on these two which is his two idle frames and we're going to add those two frames so now if we go ahead and play that that's his little idle animation now we're going to probably want to slow that down by quite a bit we're probably going to want to slow it down to like three frames per second so it doesn't look like he's having a seizure we can maybe go down to two frames per second that's not too shabby awesome so now that we've got that what we can do is we can stop his little animation and we can call this archer enemy we're going to go ahead and right click attach a script and we're going to say archer enemy.cs and we're going to create that okay so now that we've got our basic stuff set up what we're going to do is we are going to connect our two uh area 2d events that we're going to be broadcasting so let's come over here we will go back to our godot project here we're going to go over to our node and we're going to click on our detection radius here and we're going to say on body enter and we're going to say on detection radius body enter so let's control a control c click on the archer enemy make sure you click on that and hit connect and then we're going to have to go ahead and type these in all right and that is going to allow us to take a body so it's going to be an object body and then we're going to do the same thing private void with our exit so we're going to click on this and we're going to say on body exit and we're going to take this copy it connect it and oh i think i connected it to the wrong thing i did disconnect let's go ahead and connect it to our archer enemy and let's copy that all right object body okay so now that we've got these when the body enters let's go ahead and say gd dot print body has entered and we're gonna say um plus object all right and then we're going to do the same thing we're going to say body has exited i'm sorry we're going to say body so let's go ahead and copy body my apologies all right so now if i save this i come over here and i go find my archer enemy let's put him and if i click on this so i don't have to manually move my stuff individually so that way they're all moving as one big group i'm gonna move this guy um i guess temporarily we'll put him here i'm gonna scale him down by quite a bit because he needs to match our character size so actually if we just do this and this is because we're using two different packs so they don't quite match up but that's okay um this is for demo purposes so it's okay but let's go ahead and scale him down so he kind of matches so let's see that's about right and then we are going to shut that off we're going to move this oop we're going to move this to the center oh goodness there we're gonna move him back to the center of our little object here we're gonna turn that back on and then we're gonna move our entire object by turning on our little um children objects not selectable so now i'm going to drag him over here and we're going to go ahead and hit play and let's see what kind of uh stuff we get out of this so as we can see there was nothing going on and it couldn't seem to detect the player well if we look at our errors you can see can instance cannot instance because of class archer enemy cannot be found script archer enemy dot cs one of the things that we need to learn about godot is that godot does not allow spaces in your um in your classes but it does allow spaces in your scripts so it's just easier to not have the space because if you have the space the class name and the actual file doesn't link up and c-sharp can get very confused very fast so let's go ahead and recompile and let's try that again awesome so you can see body has entered tile map so if i actually avoid the spikes and i enter you can see body has entered kinematic 2d so that's awesome body has exited kinematic 2d so the reason why is because you can't have spaces in your cs class so it's best just to make sure that all of your names and everything is lower or is uh no spaces either underscores or just no spaces in general so now that we have that working let's go back to our script and let's do some processing here so what we're going to want to do is we're going to want to say hey if the character if the if the body that's detected is a character so if it's the player so if body is player controller then i want you to grab i want you to um like basically attack it right well the thing is is we're going to want the player to do we're going to want the enemy to do more than just one attack right so we're going to want to do that inside of our process section right so what we need to do is we need to say yep we've detected the player and we need to attack that said player right so we can say private player controller player right and then we can say player is equal to body as player controller and what that's going to do is that's going to cast the body that we got as a player controller only if it is a player controller and we're going to do the same thing down here just kind of in the opposite so if body is player controller then we want to say um like basically deactivate right so we need to make a global boolean here and we'll say active oh goodness i can't type today there we go and we'll say active is equal to true all right because we want him to just kind of idle if he's not doing anything right all right so now we're going to say under here we're going to uncomment this and we're going to say if active then i want you to go ahead and print shooting so now if we go out and run this little project here so if i go ahead and run this then i jump in here you'll see that we have just a crap ton of shooting and then if i run out it stops body has exited so that's perfect that's what we want but this is just an unnecessarily large amount of shooting right so we need to have so it has a timing system right so that it only shoots every couple seconds instead of all of the time so if we go over to our enemy and we come down here and we say let's see if able to shoot let's say let's go ahead and create ourselves a little boolean here and we're going to want to make this a private variable up here so we'll say private able to shoot and we'll default that to true so that way by default when it spawns in the character can shoot now what we need to do is we need to say hey if you've shot able to shoot is going to be equal to false and then we're going to need to add in a small timing system and if you guys haven't seen my other stuff when i do that but it's pretty simple so i'll show you how to do that real quick so we'll add a private float shoot timer and we'll default that to one and i'm doing one f because it's a float so you're saying hey this uh little bit of data here is a float instead of uh instead of an integer and i'm going to add a little reset timer here now the reason why i do this is because it's super easy for you to um be able to reset your time and you can also make it so that the um initial shot timer is shorter so you could say like hey you know the player can shoot uh you could say like for instance two right so it'll be one second wait uh after their first shot and then a two second wait after their third shot right so that's kind of why i do it that way and also it makes it a little easier for me to do adjustments because i only have to adjust it up here instead of adjusting it throughout the code so what we're going to do is here once you shoot you want to reset your timer and then you're going to want to set up a small timer inside of your process here so if shoot timer is less than or equal to zero then we wanna say whoops then we wanna say able to shoot is equal to true else we're going to say shoot timer minus equals 1 or delta i'm sorry we don't want to do one because then i'll shoot every frame instead of every other frame now i've got a couple of issues here that i got to clean up and i think that'll do it awesome so now if we go ahead and run this a little bit here what should happen is it should shoot every second or so so if i jump shooting shooting you can see how it's going much slower than what it was going so that's perfect that's exactly what we want so now that we are at this point so now we're at this point we need to go ahead and have it raycast to the player and make sure that it can shoot at the player because we don't want it to shoot at the player when they're you know below the character or you know not within the detection range of that character right so what we can do is we can say hey if you are able to shoot then i'm going to say var screen space our space state is equal to get world 2d dot direct space state and what that's going to give me is it's going to give me access to the physics system so i could do stuff like as it says querying physics and things like that so it's super useful for doing uh raycasting through code so now what we're going to do is we're going to say godot.collision or collections dot direct or dictionary result is equal to space state dot intersect ray which is going to call out a ray cast we're going to say this stop position comma uh wherever our player controller is so player dot position and then we're going to pass in a new godot dot collections dot array and we are going to say this all right so what does all this do right so we're saying hey we're going to pass in a ray craft oh so we're going to call a ray cast from the from the monster to the player and we're going to ignore the monster so if the monster has a collision it doesn't collide with the monster it can just ignore that collision so now we're going to say if result our es result does not equal null because there's a possibility could equal null so we want to make sure that we do some null checking here we are going to want to say if result collider is equal equal to player then we're going to want to do our stuff and we're also going to want to check to see if the result dot has or contains i'm sorry i keep forgetting contains versus has and if it has the collider here awesome so now we can go ahead and just drag all of this into the raycast or into the the raycasting code here so now it should only shoot if the player is within distance and is not like obscured by a wall or something like that so let's go ahead and test this so if i open up my godot and the best way to test this is by jumping around him so you can see shooting shooting shooting all right let's dash up and grab and you can see he's not shooting even though we're within his collision he's not shooting now he is now he is now he's not see that perfect so now we need to go about creating our our projectile right our arrow that he's gonna shoot at them so we're gonna do is we are going to take uh right click up here and we are going to add in a node 2d we're going to call this arrow we are going to right click and attach a script to it we're just going to call it arrow we need this to create our projectile and then we are going to add in an area 2d to do collision we are going to put that underneath arrow we are going to right click and add in a sprite and we're going to right click our area 2d and put in a collision shape so if i zoom in over here and i added a small rectangle like shape and let's just make it something like this for our sprite since we don't actually have an arrow sprite i'm just going to go ahead and use the godot uh little design um icon here because i don't actually have the uh an arrow so we'll just go ahead and use this so we'll scale this down like that so it fits within the little tiny arrow sweet so now that we've got this little arrow we're going to right click and make it into a scene and we're going to make it into an arrow scene then we're going to go ahead and go in to the arrow script here and we are going to go ahead and start coding that so the first thing we're going to need is we're going to need to make a private variable for speed so private int speed and let's just make it default to 150 150 seems fine so once we have this little speed variable what we can do is we can say hey let's uh uncomment our process here and let's come over here and say hey on process let's take my position plus equals transform dot x multiplied by delta multiplied by speed so what this is gonna do is it's going to say okay i'm going to move u plus x by time by the speed at which i'm moving so that allows you to shoot and effectively shoot an arrow so it continuously moves on the x-axis forever so now what we need to do is we need to hook up our little area 2d so we're going to open up our arrow scene we're going to go into our area we're going to click on our node and we are going to say on area body entered object body here and we are going to allow that and we're going to say private paste that and we are going to say object body if you remember we did this before and i forgot my void awesome so now we've got that we can go ahead and delete it just like that so basically he's going to shoot it and when it hits something it gets removed right or what we can do is we can come up here and add in a private float life span and we're going to make that 20 seconds so for some reason it gets shot up off into space or something it will live for 20 seconds and then get deleted and get garbage collected so what we'll do is we'll say lifespan minus equals 1 or delta we'll say and then we'll say if life span is less than zero then we are going to q free and that's just a quick way so we don't destroy our uh memory and we just don't keep keeping all these objects in memory for no reason this allows us to just kind of garbage collect those out as we move so now we need to make our our archer or our little turret guy shoot the arrow right so what we can do is we can come up here and say okay we need to first get a reference to that object right so let's go ahead and do that so let's say export and go public packed scene arrow then we're going to come down here and we are going to say arrow arrow is equal to arrow dot instance arrow dot instance as arrow and what that's going to do is that's going to force this to be cast as an arrow and it's going to allow us to instance our little arrow so now what we need to do is we need to say owner dot add child arrow and the reason why we do this is because if we were to instance this it would be connected to the archer so if the archer were to move that arrow would move with it so for instance like if he turned around the arrow would suddenly just flip going the opposite direction and we don't want that obviously so we're going to go ahead and just allow that to be part of the root of the project and now we're going to do is we're going to say arrow dot global transform is equal to this dot get node position 2d and we're going to grab our position 2d so i'll just go ahead and copy this that way i don't have to worry about spelling dot global transform so now that should allow it to spawn that arrow and shoot it at the player kind of he's not quite facing the player so he's not gonna be shooting it at the player but it'll work so now if we go ahead and save these and we try to run this you'll see our arrow flies by and we've got a hard crash so why did it crash we see here no reference exception object reference not set to an instance of an object so why would that become why would that do that well if we click on our archer enemy and we come over to our inspector you'll see that our arrow is empty so we need to go ahead and grab our arrow here and put it inside of our project now we're going to go ahead and go back to our main scene our arrow scene and make sure that it's zeroed out it looks like it is it just that little picture kind of concerned me but it seems to be okay so we're gonna go ahead and save and try that again and it still crashed so let's see why it crashed this time get node node not found position 2d so if you look we called it projectile spawn not position 2d that was my mistake as well so if we try to run that again you'll see that he is now shooting arrows awesome and if we hit it it gets removed see that so if we come up here ah i'm bad at aiming there we go and i got hit by you see how it removed that arrow that's perfect you can see here that it's also removing the arrows as well when it hits this little uh tile set here so that's great so we've got something moving and something going on so let's go back to our code we now need the character to kinda shoot at the player to an extent so what we can do is we can rotate the arrow to go towards the player if that makes sense so what we'll do is we will go here and we'll say look at player dot position now i know what you're going to say this isn't going to look very good because it's not i can almost guarantee you but i'll show you a way that we can make this work so you see how now he's facing the player so that's great so now we basically have a turret so if you're making a little turret for your game this is exactly what you needed right but obviously he looks very stupid and you can see how he can't shoot us now he can face us but he can't shoot us see that which is perfect but we need to make it so that it's not the the player or the enemy that looks at him we're gonna go ahead and instead grab the projectile spawn and tell it to look at the player so that way it shoots at the player without the guy moving as much see sweet so now that we have all that let's go ahead and shelve what we have right now and let's make sure that our arrow is fully finished right so we're going to do is we're going to say hey uh we need to do damage to the player right so if our body is a kinematic 2d body and the reason why i'm doing this is because instead of doing if it's the player i'm going to allow it to damage anybody that's not some kind of set dressing so if it's just a kinematic 2d it can damage the the character it makes things way more fun especially when there's multiple enemies and you're shooting and the enemies can hit each other it's kind of cool it's a cool little interaction right so we can say if body is player controller then i want to go ahead and say player controller pc is equal to body as player controller so that way it casts it over and pc dot take damage and we're going gonna go ahead and tell it i don't remember if i think it just takes one damage it's been a minute since i've looked at the player controller so let's go ahead and take a look at it yep so now if i get shot see it bounces me well in this case it's bouncing me forward which is kind of strange and also that's kind of a weird bug we'll have to look at that so you'll see that the player is not being respond and his animation has not stopped playing even after he gets hit that's because the first thing we need to do is we check if their health is greater than zero and if it is then we can run all of this code right so now if i come over here and i run this little bit of code here and i run over and i get shot and i get shot again and i get shot again you'll see that now at least the animation is finished playing right but you'll also notice that we're not responding and the reason why we're not responding is if we click on our player here and we look over at our signals because we made it ace because we moved everything into its own scene the signal got disconnected so we need to double click on this and click on our game manager and reconnect that signal on player death so now that we've went through and reconnected that signal if we run in and we run in here and we get shot and we die and we respawn so that's how you fix that small little bug there so now we want the enemy to figure out which direction we are based in relation to it so let's go ahead and take a look as to how to do that so the first thing that we're going to want to do is we are going to want to get the angle of the player in relation to the um character right in relation to the monster so we'll say var angle is equal to global position dot angle two point and then we'll say player dot position or dot global position i'm sorry because we want to get the global position then we can say if math dot abs angle is greater than math f dot pi divided by two and then from there we can say okay if math.abs angle is greater than math f dot pi divided by two i think we could probably get away with math f to be honest with you abs i'm not really sure what the big difference between math f and math is but i'm just gonna go with math f get node animated sprite animated sprite dot flip h is equal to whoops false else we're going to go ahead and do the exact same thing get node and all of that true so what is this doing because there's there's a lot of stuff going on here so what this basically just says is hey get the angle of the player from the global position of the character right so you have the the player and the the end of the player and the enemy right so we're doing we're saying get that angle and then if that angle is greater than 90 degrees then go ahead and flip your animation right so i will show you all right now if we come in here see how he flips and then if i jump over here he flips again see that which is great okay so now that we have this going let's go ahead and set up our basic animations okay so let's go into our animated sprite we already have two of them idle and shooting we set those up earlier so let's go ahead and hook those in first we're gonna say hey if the player is not active right so if they're if they're not shooting i should be saying else go ahead and play or get node like this and well let me just go ahead and grab the animated sprite node it's just easier so if we go ahead and get note animated sprite dot play idle so now if the player or if the um the enemy is not currently attacking you he's gonna play his idol animation right see how he's idling oh i got hit see how he's idling over there which is perfect so now we are going to go ahead and say all right if he's played his or if he's animating and he's he's uh attacking a player right if he's going to be going ahead and shooting a player we're going to go ahead and play our shooting animation so if able to shoot then come over here and play so get our note animated sprite dot play down here shoot i believe i have it a shoot shooting alright so if we come over here but he's not playing his animation right and the reason why is because he is playing his animation but he's only playing it for one frame because this idle animation needs to not happen if he is still playing his shooting animation so if you remember how we did our character controller we're going to do something very similar so we're going to say public bool is shooting and we are going to default that to false and we're going to come down here and we're gonna say if he is not is shooting so if he's not shooting then we're gonna go ahead and do that and if he is shooting and is shooting will be equal to true so now if we come over here we should see him shooting there we go now there are some issues here that we're going to have to figure out mainly being that uh his shooting animation does not match up with his actual shooting see that but what we can do is we can come here and say animation finished and pass that to our archer enemy and go ahead and copy that connect it and then we're going to come down here and we're going to say private void on animation finished right and if we come over to our player controller and we actually take a look at our little animation finished let's just go ahead and copy that because it's way easier just to copy and paste code than it is to actually do it yourself and we'll change this to shooting animated sprite dot stop and instead of doing that we're going to say we are actually going to say let's copy all this actually i want if able to shoot yeah let's go ahead and pull this out and let's put it in here so now he's shooting here and then let's go ahead and grab all of this little bit of code cop cut that out and say private void shoot at player and i'm going to do a lowercase s because that's how it works and then we are going to paste that in there there we go so that's just it's a little bit easier for us to maintain especially if we want to maintain it for a long term and actually we don't need this here anymore we're gonna tell it to do it down here and then if the animation's finished then we are going to say shooting is equal to false and that should throw him back to an uh uh you know standard animation state and then we are also going to say public or i should say private actually private animated sprite animated sprite and then we'll go ahead and set that here as well for some uh consistency sake and so that we're not using so many get nodes it'd just be better off so if we come through here and we just kind of get rid of this stuff here that's a little bit better it's a little cleaner and i'm going to go ahead and format my document because it's just a good idea to format your document it lets you know you let visual studio codes kind of handle it all right so now let's go ahead and see what that did because to be honest with you i'm not sure so let's see what it did whoops i didn't mean to hit that oh that's close see that but we're gonna need to tell it to go ahead and shoot before that right so the question is how are we going to do that so the first thing we're going to have to do to solve this problem unfortunately is by splitting up our animations so if we come over here to our little archer character we can go to our animated sprites and you'll see that he has a shoot animation and if i kind of go over to our animation and i move to our through our frames here you'll see here is where he shoots right so what we're gonna have to do is we're gonna have to separate this into its own little animation these little frames here so what we'll do is we'll remove these frames so now his animation frame is only until he draws back his bow and we'll rename this drawback and then we'll go ahead and hit new and type shoot and then we'll go ahead and click on our little um open file button and we'll go to our archer hero and we will do our i believe it's normal attack and then we'll go ahead and change our horizontal until it matches up and then we're gonna grab these three frames so he goes back to his idle animation so you can see here if i go to drawback he pulls back draws and then shoot he shoots and then retracts back to his original state see that perfect so now that we have these two set up such drawback and shoot now we need to go back to our archer enemy and we need to go down here instead of playing shooting play drawback and i want to make sure that i did that correctly without the capital b and now once the animation is completed we come down here and do drawback we're going to say okay once that animation is completed let's come down here and let's move this over here i believe i just called it shoot yep there we go we will go ahead and grab our animated sprite dot play our shooting animation so what that should do is it should and actually i think we'll have to do it this way and then do it like this there i think that will work and now if we go to our drawback and we go and change our drawback so it goes to our draw we're going to also want to change our projectile spawn location over like this and then up like this so that way it kind of shoots from the correct location so now if we go ahead and test this let's see what it does perfect that's exactly what we wanted awesome that's perfect that's exactly what we wanted awesome so that's all i have for you guys today we talked about creating an archer like enemy we went through the process and created an arrow for that archer enemy we went ahead and coded our arrow so it does damage to the player and we went through the process of coding our archer enemy so he shot at the player and timed his shooting properly so if you like this video go ahead and hit that like button if you dislike this video go ahead and hit that dislike button because i am here to make content for you guys now this little series was an entire user request from you guys so i do look at our comments and i do try to make videos that you guys are interested in so if you guys have any suggestions throw them in the comments below but that's all i have for you guys today so thank you so much for watching and i'll see you all next time thanks [Music] first
Info
Channel: FinePointCGI
Views: 320
Rating: undefined out of 5
Keywords: godot, godot engine, godot game engine, godot tutorial, godot 3.2, godot turret, godot beginner tutorial, turret, godot 3, godot 3.1, make a fps in godot, godot engine tutorial, enemy, godot simple enemy ai, make an enemy attack, make a first person shooter in godot, tutorial godot, godot 2d tutorial, godot gamedev, creating games, godot tutorial for beginners, godot how to detect a hit, godot 2d, tank turret rotation, godot engine getting started, shooting godot, c#
Id: 6k_MyPwwygE
Channel Id: undefined
Length: 49min 44sec (2984 seconds)
Published: Mon Jun 21 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.