Make a 3D Top Down Shooter with Godot - Part 1.2 Gun System

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello folks welcome to the age of asparagus and part two of making a 3d top-down shooter in godot by the end of this episode our character will have a basic weapon system that can equip a gun and fire bullets okay let's roll i just opened up godot again i'm going to open my level scene one thing we didn't do last time is add wasd movement controls so let's do that now so we're going to go up into the project settings and on the input mat tab we're going to scroll down in here where we see ui left since that's the action we're using hit this little plus icon we'll click the key and for left i want a click a on the keyboard and hit ok and we'll do the same thing for right hit the plus key d for up we'll use w and for down s okay let's run that again oh yeah that's nicer wasd good so before we can shoot some bullets we'll probably want to make a gun so i'll go up to the scene menu and hit new scene 3d scene so we'll have a spatial node that will be the root and under the spatial we'll add some meshes so hit the plus here let's add a mesh instance and we're just going to add a couple cubes as we do a little bit of modeling and tweaking moving around in the 3d viewport it's nice to get used to these shortcut keys which are w e and r so w will move into translation mode so you can translate your objects ctrl z to undo those translations and e the next one over matches this rotation mode and then r will go into scale mode so i'm going to be hitting these keys so i'm going to hit r and we're going to scale this in and down a little bit we're just kind of visualizing it here it is snapping a little bit because i have this snap button on i also have i can see this use local space is on i'm not sure that's gonna that's not gonna affect us until we rotate anything but just in case make a note of that okay let's we'll go down something like that and before we duplicate it actually let's give it a material so over here in the inspector material click new spatial material we'll select that spherey thing and in the albedo let's pick some sort of like gray gunmetally type thing sure ctrl d to duplicate it and in the next message since here now i'm going to hit e to go to rotate and i'm going to rotate it a little bit i'm going to hit r to go back into scale i'm going to scale it down this way and if you used blender before godot uses the same 3d view so i can hit one on the number pad to look in front view three for side view and seven for top view so i'm hitting one on the number pad and it's going to send us into orthographic view and as i come out here it'll go back into perspective so and i can use just like blender the numpad five to go toggle between them so i'm hitting one here and i'm going to hit w to grab it and we'll move now when we're grabbing i do not want it snapping because those snaps are too big so we'll put this up somewhere like here for a handle and then i'm going to ctrl d duplicate it again and the duplicate i'm going to move over here and this can kind of be our magazine so i'll hit e to go into rotation mode something like that w to go back into grab mode sure okay let's uh i'm going to double click the spatial we'll call it gun and we have a gun let's control s that i'm going to save the scene as gun.tscn and like the horribly organized person i am at the moment i'm just going to save it here in the root of our project we'll organize that up later when things start to get a little bigger let's go back to our level scene and under the player i'm going to create a new node that's going to act as our weapon controller so let's hit plus i just want this base node good because it's not going to have a position or rotation it's only going to use to hold a script so let's double click that and we'll call it gun controller so the gun controller is going to control which weapons are equipped and it can fire the gun for us can do other stuff like that the benefit of having it as its own node is we can then save it as its own scene and we can plop a gun controller onto bad guys or anything else we want to have a gun turret whatever right so we're going to keep it separate from the player script and it also groups the code for us nicely so our player script doesn't get so massive so i'm going to add a new script here we'll sure right in the root so what are some variables we might have here well we might want a starting weapon let's create a new exported variable called starting weapon but we have a problem because we need to tell what type of variable starting weapon is so this is going to be a packed scene so we can drop a scene in there and we can just check let's just check right away to make sure that works so there's our starting weapon it's empty and i can go down to my gun.tscn gun scene and drop it in cool so we have a starting weapon we're also going to want to know where we have to position the gun in the scene when we equip it so let's create a variable called i don't know hand sure hand because he's going to hold the gun and we'll create another variable called equipped weapon so the equipped weapon will hold which weapon we are currently using so to start when this gun controller loads in the ready function we're gonna check if there is a starting weapon so if we provided a starting button then we want to equip it so we'll use a function that doesn't exist yet let's call it equip weapon and we'll pass it the starting weapon so let's create that function now funk equip weapon and it's going to take a variable which will be the weapon to equip so when we equip a weapon we'll let's first check if there already is a weapon equipped and if there is we'll delete it so if equipped weapon and gd script similar to python which is kind of nice is it's just going to check if equipped weapon is a truthy value so if it doesn't exist if it's null it's going to consider that false and if there's something there then it will consider it too true so just i like to do a lot of print statements sorry about that but let's just give ourselves some feedback it's kind of a sanity check and we can delete all these later but if that happens we'll give us some feedback that we're deleting the current weapon now let's actually delete that weapon and remember how to delete nodes there in the scene tree we're going to use free notice how cue free doesn't pop up here as an autocomplete and that's because the editor here doesn't know what equip weapon is it doesn't know that it's a node that has a method called cue free so when we create the variable equipped weapon we can give it a what's called a type hint and that lets the editor know what we're expecting the equipped weapon to be right so for now although we know it's going to be a gun let's just we can just say it's going to be some kind of node right so let's just leave it for that for now because nodes should have a cue free method all right later on we can make this more specific to what kind of node the equipped weapon is actually what is it it's a spatial right we already know so why don't we just go ahead and let's say it's some sort of spatial for now so that should delete the weapon else so if we don't have a weapon equipped then well first i'm just going to print something here no weapon equipped and now we want to equip it so let's go equipped weapon equals the weapon to equip and that's the weapon that we passed this method so when the gun controller scene loads when we load our level which loads our player gun controller when we start if a starting weapon was provided over here which we did then it'll find that starting weapon and it will equip it for us so why don't we just run this now just to make sure our logic is working because although we don't actually add the gun yet to the scene or to the player it should say no weapon equipped so let's just run our our level okay so we have an error here trying to assign a value of type paczine to a variable of type spatial and that is occurring here i can see in my stack frames in this in the trace of where the air comes from it's coming from this line so equipped weapon you can see we say equipped weapon and we want it to be a spatial variable and we're trying to give it this weapon to equip well the weapon to equip is the starting weapon and the starting weapon is a packed scene so scenes and nodes are not the same thing although we turn scenes into nodes when we instance them before they're instanced they're not the same type so what we need to do is weapon to equip we need to actually instance the weapon and turn it into a node so our packed scene is kind of like a template or another programming it might be like a class that defines what the starting weapon would be but you still have to actually create the starting weapon so we're going to do that here so we'll instance it now this equipped weapon is going to be a node and now we want to add the node to the tree so the normal way to add a node would be to add child and if i just type add child it's going to add it as a child to whatever node we're in right now and the node we're in is the gun controller forget that because we don't want it there anyway where do we want it we want it to appear on the hand but our player doesn't have a hand yet so let's make a hand ctrl s let's save this uh gun controller script so far let's go back to our player and somewhere in his body let's add a hand and with the body selected i'm going to hit ctrl a and i'm going to add a position 3d position 3d is just a spatial node the only difference is it appears as a cross in the viewport at all times so even if i've selected around somewhere my position 3d will still appear which you can't see it because it's behind this guy but if i move it out here you see the little see that little cross hair right there so when i select something else the little crosshair just remains so that's the only difference between the position 3d but i actually want that there in the editor so i'm moving it to where our hand would be i can hit seven to go to top view and move it out one and i'm going to turn off snap just so i can position the hand right where i want it maybe about there and then hit one to go three to go to side view and that looks good yeah okay so that's the hand let's double click the position 3d and i'll call it the hand ctrl s save that let's go back into our gun controller script and we need to tell the hand the hand variable what it is so in the ready function we're going to tell the hand variable that it is this node right here okay how do we do that well let's get parent assuming that the gun controller is always going to be a child of the thing that's moving around and shooting this should be fine so even if we give it to an enemy or anything the gun controller will be there and then in the parent we're going to wherever that hand is in the tree we're going to use fine node that's find underscore node and we're going to find the node called hand so now we've set the hand we can go back down to our equip weapon and using the hand node we can add a child to it and that will be our equip weapon control save that let's run the scene again do we hey we have it it's a little far out it's hard to see it looks like it's rotated sideways okay let's go check out the hand well let's check out the gun first so i'm going to double click on the gun.tscn and we'll go to the 3d view that looks okay oh actually you know what that's the positive red remember is the positive x direction so generally forward we want forward to be the positive z direction so i'm going to rotate the gun uh so i'm going to hit e here and i'm going to rotate the gun 90 degrees make sure snap is on and we'll just rotate it boom 90 degrees or you can go to the transform and just make sure it's rotated about the y axis for 90 degrees okay ctrl s save that and close the gun and is that all we needed to do no okay right on he's using the gun as a snorkel cocaine let's go check out what the hand is doing hand how are you doing let's go uh w back into moving okay the hand's like upside down or something okay let's let's let's go to the transform it's not rotated but let's make the hand get back to normal actually we're going to go to the universal transform because i want to see those arrows and i want that blue arrow pointing forward and i probably want the red arrow pointing down so the white because green is our yellow so that's up okay that looks like how we want the hand right like positive z is forward generally is what we're going for how about now okay it worked but it's a little far back even though our hand is i can't do that our hand seems to be in the right position it's right there in front of the character if we go back to our gun scene you'll notice that the origin of the gun scene is in the middle of the gun so that's the part that is going to match up to the hand so if i click the gun let's move the whole thing forward there why don't we set a main scene so i can just hit the play button so let's confirm a main scene we'll select our level and now hey that's pretty good it's still back a little far i kind of want it to look like it's floating ahead so i'm gonna turn off snap and just move it a little bit forward and that's kind of probably what i want oh yeah we want to hit the play button now good okay now to make some pew pews uh just a quick note if we go back to the uh the gun controller script when i did add child dot add child notice how it didn't auto complete for me so i'm going to give another hint here and let it know that it is a position 3d and that's going to help us to auto complete stuff later on right so now if i do it i can go it knows it's a node and all nodes will have this add child that didn't work add child up enter good and we'll give it this one right here okay let's do projectiles we're going to add another new scene in it from the scene menu new scene let's go to 3d view and create a little bullet so control a let's make this let's just do another spatial node so we can click spatial or you can click 3d scene over there which is actually a spatial we'll call this bullet all it's going to be is we're going to give it a mesh we'll give it a mesh instance which will be a you can give it whatever you want i'm just going to do a little cube that's pretty big but let's make it look nicer so we'll make it a new spatial material click on the sphere in albedo we're going to choose pretty dark color not quite black i'll just mostly black okay that's probably huge we could scale it in our script but let's go i think it's going to be something like point one so i'm just gonna type point one down here in the transform in the inspector on all the values and that's all we need i'm going to hit ctrl s and save this as a bullet.tsen we have a bullet now let's fire it and let's create that bullet so let's open our gun scene and we're going to give our gun a script we can just call it gun we're going to provide it a bullet so we'll do the same thing in our gum controller and we'll let uh we'll export a a packed scene but this time instead of starting weapon it's going to be the bullet and if i go to my gun now i should have this option here to drag a bullet so i'll take my bullet scene i didn't want to open the bullet scene i wanted to click and drag that bullet here let's we need some more variables here and i'm going to export them as well because it's kind of fun just to quickly change them in the editor itself let's export a variable we need to know how fast the bullet's going so we'll call it muzzle velocity really this should be muzzle speed because we're just uh this is just a scalar value of how fast things are going i'm going to use 30 to start we're going and let's export another variable called millies between shots and we'll set that to be about 100. so this is going to be how many millis milliseconds there are between consecutive shots so like if you're holding down whatever fire button is it would go one tenth of a second or 100 milliseconds so you'll basically get 10 shots per second at this but we can go edit these values quickly and change them and just see how that affects our game to find the right values these will just be the defaults okay so we will shoot so let's do this in our process we could do this in physics process maybe um i don't think we need to because we're gonna have to use some sort of timer somehow to determine when the next shot is being fired so the frame rate i'm not sure will matter here basically in the process we're gonna try and shoot we're gonna create our own function shoot and um so when we shoot first thing we need to do is we need to create a bullet so let's go var we'll call it new bullet and we're going to take our our bullet and we're going to instance it so this is going to create a new bullet node that we can put into our scene but it's not there yet and before we put it there we want to give it the right location so how are we going to do that well we don't want to put the bullet let's go back to the 3d view here for our level we don't want the bullet to be a child of the gun because then as we move the character and the gun around the bullets will actually move with the character once they're fired we just want them to go right so we want them to be children of the root node of the entire level so where am i what's going on here let's go back to our gun script and we will set our new bullets global transform gullible so the global transform includes its scale rotation and translation right um really we're only worried about the translation at this point which is the position and we're going to set it to the muzzles global transform muzzle dot global transform globe doesn't know why doesn't it no that's because muzzle doesn't exist our gun doesn't have a muzzle it doesn't know where it's shooting the bullet out of okay let's control k that to comment it i'm going to control s to save and let's go back to the 3d and add a muzzle so and the muzzle is just going to be a position so we'll uh control a at a position node position 3d there it is you can barely see it and i'm going to move it forward right there actually i'm going to move it out a tiny bit just so we can see it in our scene even when we're not clicked there you see that little crosshair okay and we'll call this the muzzle ctrl s there save it let's go back to oops gun scene our gun script i'm going to control k that back again and now we have a muzzle do we yes global transform so the we're just going to basically make the bullets transform match that muzzle's transform which is pretty straightforward especially since our bullet's just a cube it doesn't even have any direction now we're going to give the bullet some speed so new bullet dot speed and that's we're going to set that to be the muzzle speed does new bullet have speed what is bullet i don't think new bullet has a speed variable right because our bullet doesn't have a script yet hmm okay maybe we'll have to come back to adding speed once we give the bullet a script and some variables so finally we want to add the bullet as a child to our scene and we want to like i said we want to add it as a child to the level itself not to the player or anything underneath that can be moving around so this is a little complicated here but we're going to get the scene create a new variable called the scene root and we're going to get the tree so that's getting the this tree here the whole tree where the gun exists and the gun doesn't actually exist in this tree yet but you know when the game starts we create a gun and it start it appears under the hand so we're going to get the tree and then we're going to in the tree we're going to get the root of the tree going to the root of the tree all right and now we're going to get all the children of the tree here and then this is going to be a list of some sort of iterable and so we're going to you get the zeroth element or the first element of the list because that's going to be our root node i feel like there should be a nicer cleaner easier way to do this to get the root node but it works and now to our scene root uh not equals dot add child child you're not letting me add a child probably because i don't think it knows we're getting the first element of this thing it has no idea what the scene root what kind of variable the senior it is add child and we're going to add the new bullet so does it work the gun is going to shoot constantly so right now it should just create a whole bunch of bullets did it oh oh yeah it's creating bullets they're not moving but they're being created at the right spot it looks like hey i just made a drawing program we can draw with bullets okay um great i forgot the most important part especially for debugging purposes in our gun script every time we shoot we need to say pew uh what oh p tiny is um print in another language i speak which i can't tell you what it is right now uh i just played the scene which is why nothing popped up instead of playing the level but now all we get we have all our pews whoa okay not gonna waste your time playing around with that so let's give the bullet some speed and make it go places so the bullet scene let's open that there's the 3d bullet and it has no script by itself yet so we'll click the bullets root node there and add a script so this is a spatial we need a variable obviously called speed i'm just going to export it and speed is going to be an integer we can give it a default value actually let's give it a 70. we don't need to do anything to get it ready but we will need the physics process and we want physics process instead of process here because this is frame if you your frame rate is different we don't want the bullets to go faster or slower we always want them to go the same speed whether whether you're having lag or whether you're just running 30 60 or 120 fps so we can move the bullet we're going to use global global translate to translate it in the global coordinate system what do we do we need it looks like we need to give it a vector 3. that's going to be the distance we're going to move it so we're going to translate it forward somehow i wonder if we just go vector 3 dot forward that's always going to be the same direction but okay we can multiply that by the speed and of course we don't want it to go the speed every frame we want it to take into account the frame rate so we'll go times delta this is going to happen when it instances it's just going to move itself when it fires so we should be able to just run the game and there we go yeah look it is definitely always shooting forward okay so we need the proper forward direction so we'll create a new variable called forward direction and this is going to be our bullets forward direction at the time that it instances so we're going to get the bullets global transform from the global transform we're going to get the basis vector and we're going to take its z direction and we want to normalize it that's a lot of stuff and i'm not going to explain that now we can do that later on this should be in the proper direction if our bullet isn't rotated weirdly and so instead of going vector three forward let's just go in the actual bullets forward direction when it's instant how about that forward dd for ward hey there we go uh it's definitely turning however it's forward direction appears to be not in the forward direction i was expecting okay let's go back to the gun and the muzzle since you remember we just give the exact same transform to the bullet and we take that transform right from the muzzle and the muzzles forward z direction is pointing sideways which is why we're shooting sideways so let's i'm going to turn snap on and grab the green rotate about the y-axis so our muzzle is pointing the same direction as the gun okay control s does that fix it yay it fixes it okay so we have bullets uh this is gonna start lagging soon because our bullets never die they just go on forever and ever we better stop that before my computer crashes let's make sure the bullets die after a certain amount of time so in our bullet scenes or bullet script i think the easiest way is to just do a simple timer and just kill it when the time is up so if it hits something later on we'll cue free it and destroy it but if it doesn't hit anything it'll go until we just say kill it so i'm going to create a constant here called kill time and we're going to kill it after 2 seconds so it might go off the screen a little bit but it won't go on forever and we're going to create a new variable called timer and it's going to start at 0 and this is pretty pretty easy what we'll do is each frame will add the delta which after one second regardless of your frame rate should add up to one i think and we'll just say if timer is greater than the kill time let's kill it so we'll queue free thank you q free is that gonna work you know what uh i think it's gonna work but because it's shooting off the frame we don't it's not totally obvious is it unless i shoot way off can i see it disappear no so what if we just set the kill time to um 0.2 seconds is that more obvious there we go yeah yeah see they don't even make it off the screen now after 0.2 seconds and still shooting one per frame so let's two seconds that should be good obviously we need to add some sort of rate of fire to our gun so that it doesn't just keep shooting at its maximum once per frame so we'll go back to the gun script we already set a variable milliseconds between shots so we just got to use this i'm going to use a timer so in the gun with the gun selected let's add a new node a child node we'll just add a timer and we want it to be a one shot timer so it just doesn't it doesn't reset itself it only will start when we in our code say start the timer so over in the inspector for the timer timer selected i'm going to turn it on one shot let's go to the gun script let's get a reference to our timer at the top here so i'll go we'll create an on ready var we'll which will be our i'm going to call it an rof timer rof underscore timer and actually yeah that's probably good and we'll just go like this so our rate of fire timer will be this timer node and when it the timer runs out we're gonna call a function to tell us hey we can shoot again because the timer ran out so actually we should probably get one more variable here which is can we shoot and we'll start it out as true true and then after we shoot we will set can shoot to false and it won't be able to shoot again it won't actually do it again until it's true well actually now it'll keep going instead what we need to do is say if we can shoot then shoot and i'm going to highlight all this code and hit tab there to indent it what happens let's run it uh pew i see the pew see it worked because it was too fast to see but pew pew we got one bullet shot and then it set the can shoot to false and then it didn't matter even though the process was trying to shoot every frame uh it didn't because we have to set it to true also we're not using the muzzle speed are we so let's do that so we can slow the bullet down and actually see that one shoot so the new bullet dot speed we're going to set to be the muzzle speed did we give our bullet uh here let's ctrl s save that the bullet script did we give it a speed we did okay so we have a speed and it's 70. so we could we could set the bullet speed in the inspector of our bullet scene there's the speed there or we can our bullet itself and our bullet script sorry our gun script we can set the bullet speed so the speed could be based on what weapons loaded for example in this case so we'll do that so here it's saying this gun's muzzle speed is 30. we're setting the new bullet speed to b30 for the moment and is that too fast no it's not too fast did you see that bullet go i can make it even slower so we can see so let's go to the gun and we'll set the muzzle speed to be like three [Music] okay good it works let's go back to the gun script what were we doing oh yeah the timer so we have a timer uh here it's a one shot we want to call a function when the time is up and when the time is up we're going to set can shoot to true again so let's do that so the timer in the beside the inspector here the other tab is the node tab so we're going to go to the node and we're going to create a timeout signal for the timer so i can click connect down at the bottom here i'm going to double click timeout and i'm going to go with the default method on timer timeout and i want to collect connect it to my gun script yes that's what we're in right now so it created this for us and when the timer times out all we have to do is go can shoot equals true run that and why did you not work okay well first off let's go just for my sanity okay timer timer timer oh my gosh can you believe it we gotta start the timer so when we start the timer let's start the timer um after we shoot right of course let's start the timer after we shoot so you shoot let's go rof timer and let's start it start so every time you shoot the timer will start you won't be able to shoot again until the timer finishes it sets can shoot to true and then you can shoot again and this should happen every 100 milliseconds so one tenth of a second yay cool that's not very rapid fire though is it let's set that to like 10 um wait a second that's not every hundred milliseconds one mississippi two mississippi three miss that's every one second okay silly issue here um we don't actually use millies between shots the timer has a default if i go back up to the inspector a default wait time of one second and uh we never actually set it so let's do that in our ready function we'll go to the rof timer rof timer and there's probably a wait time this is just going to be the same name as this property here and we're going to set it to be the millies between shots so we want to wait let's go back to 100 and see if that works 100 milliseconds between shots oh my gosh that's not going to work this the wait time is in seconds and this is in milliseconds so we want to divide it by a thousand 100 divided by 1000 will be 0.1 however this is an integer and this is an integer so it's going to try and divide an integer by an integer and it's just going to make it 0 or 1 or something so let's divide it by 1000.0 just so gdscript actually results in a float value of 0.1 which is what we want here so there we go that's every tenth of a second right so in our gun we should be able to drop that milliseconds down a little bit oh not that low not that low to um 47 what's that look like and actually the fastest we can shoot is once per frame and since by default godot is going to run at 60 frames per second a thousand divided by 60 is what something like 16.7 maybe so if we go to 20 it'll still be blasting cool and you see the little flicker there i don't know if you'll be able to see that in the video but as soon as we get below 16 like 15 it's just gonna look like that's it it's just gonna look like a whip because we have maxed out how fast we can go even if we did one which should shoot a thousand per second it will not it will shoot um 60 per second okay let's reset that to 100 actually 50 looked way cooler for now i can move around uh but it's always shooting i should probably have a button to shoot right okay let's uh let's add that so let's go to our player script we're gonna need a reference to the gun controller so let's go on ready var gun controller equals gun controller um actually i'm going to use a lower case here gun controller so we have our gun controller here and here is our this is some movement code movement right and now we're going to do some shoot shoot code so what do we want to do we're going to add another is action pressed here and this time i'm just going to create let's create our own and i'm going to call it the primary action button so in our game during this phase of our game maybe super advanced later on there's like more than just click the primary action to shoot we're going to shoot when we click the primary action we're going to tell the gun controller to shoot now i don't think that method exists yet so we'll have to create it we'll also have to create the primary action let's do that now so in the project project settings input map we're going to go create a new by up here in the action typing primary action and remember these are case sensitive so if you put a capital here you need to make sure you type the exact same text there so we now have a primary action and i'm going to add the mouse button the left button for all devices and i'm also going to add a key for the space bar to shoot okay now it should recognize the primary action we just need to get the gun controller to shoot so let's go to our gun controller script and control s save this and create a shoot method and here the gun controller is going to make sure we have a weapon equipped so if we have an equipped weapon then we're going to use that equipped weapon and call it's shoot method and this shoot method will be the one we created on the gun right here that handles all the timing and stuff how's that work um hello yeah so we got a problem because our gun is still saying hey i'm going to shoot every frame so let's just let's just put a pass there so that function does nothing and now space bar all right okay let's reduce the speed there i think i actually changed it in the gun scene right over here yeah so let's change it back to 100 and run it yeah and i'm limited to 100 no matter how fast i click all right i guess now we just need some things to kill
Info
Channel: Age of Asparagus
Views: 3,400
Rating: undefined out of 5
Keywords: AgeOfAsparagus
Id: mDYaJa6txwc
Channel Id: undefined
Length: 37min 48sec (2268 seconds)
Published: Mon Mar 01 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.