Learn to Make Games By Making Asteroids with Godot | Michael Mcguire | Skillshare
Search

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Learn to Make Games By Making Asteroids with Godot

teacher avatar Michael Mcguire, Author | Programmer

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      Skillshare Introduction

      0:55

    • 2.

      What is Asteroids

      1:24

    • 3.

      Project Setup

      1:13

    • 4.

      Creating the Player

      9:49

    • 5.

      Creating the Projectile

      7:26

    • 6.

      Creating the Asteroids

      2:49

    • 7.

      Asteroid Spawning

      6:09

    • 8.

      Asteroid Destruction

      11:24

    • 9.

      Spawn Timer and Memory Leaks

      7:14

    • 10.

      Update Score

      9:11

    • 11.

      Update Lives

      16:26

    • 12.

      Game Over and Restart

      7:19

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

2

Students

--

Projects

About This Class

Relive arcade history while building real game dev skills — one asteroid at a time.

In this hands-on class, you’ll recreate the iconic 1979 arcade game Asteroids using the modern and beginner-friendly Godot Engine. Whether you're just getting started or looking to sharpen your skills, this project-based course will walk you step-by-step through designing, coding, and polishing a complete retro-style space shooter — no prior experience required.

By the end of this course, you’ll have:

Meet Your Teacher

Teacher Profile Image

Michael Mcguire

Author | Programmer

Teacher
Level: Beginner

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Skillshare Introduction: Right, throughout this course, we're going to go ahead and we're going to learn to make ease by creating a classic game from 1979, asteroids. Now with asteroids, you get this little ship here that can shoot little projectiles and fly around on the screen. And what happens is you shoot these asteroids that are floating around that randomly spawn. The big ones spawn medium ones, you destroy the medium ones, they spawn smaller ones, smaller ones move faster than the larger ones. And each one that you destroy gains you some points towards your total score. All right. This is a simple game, but is important to both the history of games as well as a nice little beginner project where you get to remake an actual game that you can have fun with and always add on to and make your own. Alright, let's get started. 2. What is Asteroids: All right. Today we're going to go ahead and we'll be creating the classic game asteroids, as you're seeing here on the screen here in this YouTube video. What we can see from this is that asteroids, aside from being a really old and classic game. It should be fairly simple for us, but another step up because now we have player movement going on, as you can see with our little player here in the middle. He's rotating, he's moving, he's shooting. We have these asteroids floating around, and every time they get shot, they break off into extra pieces. And we can see we've got this little alien brill that kind of spawns in every now and then. And as for UI, we've got points and health up here at the top. And effectively, this game just continues on until you either well, I wouldn't say until you either. It continues until you lose all your lives. And whatever score you have, that's your high score. And as you can see there, the asteroid went off screen, and then it appeared back on the other side and continued going in the same direction it was moving in. But in short, that is asteroids. That's what we are going to be creating here. So in the next section, we'll go ahead and we'll start setting up a project, which shouldn't be too much for us to get ahold of. 3. Project Setup: Let's go ahead and set up our project. We can come on down. If you're creating this in separate in its own project, of course, go ahead and create a new project, name it asteroids. If you're creating inside of an existing projects, then just come on in to your file system, right click, create new, create a folder, and name it asteroids, and we can go ahead and do a Toti scene. I'm going to rename mine to say Main. We're going to add a canvas layer for our Guy, which I will, of course, rename to be Guy. And what we're going to need is a label for the top right here, and this is going to be our representation of our score. I'll rename this to say score label. All right. And I'll go ahead and save this into my asteroids folder and save. And really, that's about all we really need in order for setting up our project. Most of the work is going to be inside of the player and the asteroids. 4. Creating the Player: So let's go ahead and create our player and set up the movement. So you're just going to come in at the top, click on a new tab to create a new scene, hit other node. Search for a character body two D and select it. Now, I already have this setup right over here. That's just a character body two D. I'm going to rename it a player, and I'm going to hit Control S, and I'm going to save it inside of my asteroids folder. Now from here, since I don't have any sprites to give you for this, what we're going to do is we're going to create our player sprite since it is so simple anyway for us, and we're going to create that with a line two D, since it's mostly just a triangle with a little notch out taken out of it. Alright. So numbers I'm going to use for this. Now, if you wanted to go online and look around, I'm sure you can find the sprites, if you wanted to go about it that way. I'm going to go to the Line two D and properties. I'm going to tick closed, turn that on. And I'm going to open up the points by clicking on packed vector two array. And I'm going to add until we have a size of five. My first point is going to be at ten and zero. My second point is going to be at negative five and negative six. Index two is going to be zero on the X, negative two for the Y. The three is going to be zero on the X and positive two on the Y. And our fourth index here is going to be negative five on the X and six on the Y. Now, that doesn't look like the sprite we saw earlier. That's because the width is too big. Now, because I'm using the default size that I've been using in this, again, I'll open it up and show you here. Ah, where's this at? Display Window that's 335 by 255. Now, if you want to use an authentic size for this, I believe, I think it's 640 by 800 is the authentic size for this. In which case, you'll be able to get away with making your ship a little bigger, right? So, for example, you could pull the XL maybe to 20 instead of ten. And again, you can just kind of increase solid the. So instead of negative five, you can do negative ten. So you can play around with those, and you can deal with a wider line. But since I'm using this smaller screen, I'm going to change my width of my line down to one, and we can see it here. Now, you might wonder, what about two? Well, we could do two, but we're going to have a smaller empty space in the middle. And maybe that's something you like. Go to go ahead and play that. We can't really see it here at the moment. I'm going to go ahead and just drag it in view and play it and you can see it there, how it looks on the screen. So you might like it like that. But I'm going to go ahead and change my width to one. I prefer more like this. It feels a little more authentic to me, but that's up to you. And again, you can always change those points. If you want to make it bigger, then you can have a wider lined width, or you can always go online and Google around, and I'm sure you'll find the sprites somewhere for you to get ahold of. Alright. Now you might notice that we are getting a little warning here, and that's because we do need a collision shape for us for ourselves that it's asking for. So we can go ahead and we can do a collision shape. We can come in, we can pick a shape. We can do a circle. We can do a rectangle. We can do one of the polygon shapes. Really, it doesn't matter a whole lot. And if you want to be even more exact, which would probably be a little less authentic is a collision polygon. And then it's the same setup here where you can just set the points. So you would just set them just like you did with the players, for example, ten, here, negative five, negative six, and you can see it starts lining up. With our setup. So I just need to add a couple more here. And it would be zero, negative two, and one is zero positive two, then negative five and six. And then we would have our shape all set up for us. Alright, so if you wanted to go that route, you can, and you can always come in and kind of play with your points here. No create, but if you want to hit, click on Edit points, and then you can just kind of click it and drag it around. So if you wanted to edit it that way. Also, if you didn't want to type in the points, you click on the plus or the Add Points button up here at the top. And, you can just come in and create points like that. So, you do have options. I just went with the inside the inspector because I find it to be easier because you can just translate your points directly over. And again, if you wanted to go this route, you certainly can. It's a little more a little more exact. However, less I'm going to drag down a little bit less probably less accurate to the actual thing in the grand scheme of it. All right. So however you want to go about that, is going to be up to you, whether you want to use a polygon or a shape. Let's get into the actual movement of our player. So let's go ahead. Click on player, hit ADScript, add it and make sure you're adding it into our asteroids folder. And we're going to create a physics process. And we're going to have a couple variables for us here. We're going to have a speed variable for how fast we're moving. We're going to have a rotation speed for how fast we well, rotate and then our rotation direction. And before we jump into this next piece, make sure you go up into project settings, input map and set up your controls. I'm just going to use what I've used in the past year. I'm just going to use the up down left and right since I've already got that setup to WASD. Those are the ones I'm going to use. All right, so let's go ahead and we'll say rotation direction equals input dot G axis. Now, we have to put in the negative action, and then the positive action. These are going to be in the form of the string names. So this is going to be left. And then right. Because left is going to give us our negative direction and right, it's going to give us our positive direction for rotation. And then we're going to change the velocity to be equal to transform dot X times then exactly what we just did here, input dot, axis, and same thing. We're going to put in our negative and positive, so it's going to be down, followed by up. And then we'll multiply that by our speed. Now, we're almost set here. We need to do rotation. Plus equals rotation direction times rotation speed times Delta. All right. And at this point, you should be used to the idea. We have to use either moving collide or moving slide. I'm going to use move and slide in this case. And if we go ahead and run this, we should now be able to move our player around. So if I just hold W, it's going to go forward. If I hold S, it's going to go backwards. I I hold A, it's going to rotate left. I hold D, it's going to rotate right and now we have something that's a lot similar, a lot more similar to what we saw inside of asteroids. Now, you can go ahead and you can tweak those numbers. So you can tweak speed if you want your ship to move faster or slower than this. I'm using 100 by default. Rotation speed is using 1.5. You could increase that to rotate faster or decrease it to rotate slower. That's going to be completely up to you. But regardless of what you choose to do, That's just one of the small things that you're going to decide to make your game feel more just a little personalized for you. Right? And for a player, that's really all we need to get ourselves up and going for that up until we need to start shooting. Alright. So we'll see you in the next part. 5. Creating the Projectile: Alright, so let's go ahead and create our projectile for our player. So in my player scene here, I've gone ahead and added a Marker two D, and this is just so we have a specific location that we're going to spawn our projectile at that's going to be just a little bit in front of our ship. And the only thing Marker two D does is gives us a position somewhere in the world. That's its entire purpose. All right, so you can go ahead, come up and create a new scene, hit other node, and select the area two D. And hit Create, that's going to be our projectile. And in here, I've created a collision shape, which is just a rectangle and a sprite two D. For the texture, I've gone ahead and from the drop down, use new gradient texture two D. And when you do that, you'll open the first thing up. You'll see this big section. You'll find gradient in the inspector, open that up, and you'll have two points like this. One point will be black by default. So it'll look something like that. Just go ahead and right click on the point that's in the black to get rid of it, and now it's just all white. Right. So that's all you have to do, and then you'll have a projectile. I'll set up. Go ahead and save that scene as its own so that we can use it. And go ahead and give the area two D. I've named my projectile a script. And here we're going to have a two functions and a variable. All right. The first variable we're going to have here is we're going to create a velocity for this. It's a vector two, and of course, it's going to be set to vector 20 by default. We're going to create a function for this called set velocity. It's going to have one argument of a vector two. It returns nothing, so avoid. And all we're doing is going to set velocity is equal to V, right? The argument that we pass in. And then last, we need the actual movement to happen for our projectile. So in our physics process, we'll go ahead and do position plus equals our velocity times Delta. And our projectile itself is done. We now have to head over to player. And if you don't have an input mapping setup already, come on up to our project settings input map and create a button for you to shoot with. Myself, I have my space bar setup. And before we continue, first thing I'm going to do is create a new variable called projectile. So it'll be a packed scene that we can bring in. And this way, we can load it in when we need it or create an instance of it when we need it, I should say. And that'll be equal to load and just find that scene and drag it in. There we go. So we're going to load that scene. It'll be loaded as a pack scene and stored in the variable called projectile. All right. So let's go ahead and create the input function. For our player. This is just funk underscore input. This has one argument called event. It is an input event type. It returns nothing so void. And we're just going to check if input is action just press, so we can't hold the button now. We have to press it every time we want. And the action we're looking for is shoot. So whenever we hit the shoot button, what are we going to do? Well, we're going to create an instance of our projectile. So PI for projectile instance, it's an area two D. That's equal to projectile dot instantiate. Now we need to use that Marker two D for us here. So PI Global position is equal to dollar sign Marker two D. So we're just getting that Marker two D no that we added into our player dot global position. So we're setting that up. And if we just take a look at that the way it is, if we go around and we shoot. Now, we might not really be able to see it, but if we turn and move away, uh, well, we can see we're not actually getting anything. Why is that? Because we haven't added it to the scene yet. It does exist, though, and we'll check that in just a second. What I'm going to do is I'm going to set the rotation I set the rotation now based off of our ship. So PI dot rotation equals rotation. And I'm going to use Get parent Ad child PI. So I'm using Get parent. That way, the projectile does not stick to us because if we just use ADCild, it will stick to us, and if we keep turning our ship, then it's going to keep turning. This This would be useful for something like a laser beam, but not for a projectile. So we're using get parent so we can stick it to the game and not the player itself. Right? So if we come in and shoot, you can see it is now spawned into the game, it's just not moving anywhere. And this will happen every time we hit our shoot button. So if you got this happening, then congratulations. Your projectile is working. We just need to get it to actually be moving for us now. All right. So check if it or to get it moving, we're going to run a quick I check here. We're going to say, I PI has methods set velocity, and we could safely assume this. But we're going to make sure that it does have this function just to be safe. And we're going to save our direction. But we're creating a new direction here. Is equal to vector two dot right, dot rotated and pass in the rotation. So this is going to get us whatever the right direction is, which would be on the positive X based off of how much it's rotated effectively, right? So this way we always have a specific direction it's moving. Whoops. Whoops, whoops, whoops. There we go. We're going to give it a speeds a var speed equals to 200. You can always tweak this later if you would like. And now we have to do is call that function that we check for here. So pi dot set velocity, direction times speed. And with that, our projectile now move in whatever direction we're shooting. Just like that? Even if we stop moving altogether. Great. Now we have our projectile working with our ship. Now we just need some asteroids to shoot and some points to gather. Alright. I'll see you guys in the next one. 6. Creating the Asteroids: So let's go ahead and create our three asteroids. We're going to create a large, a medium, and a small. These are all going to be created the same way. The only difference is going to be the size of the collision shape and the actual point numbers because obviously, they're going to start large and they're going to get smaller and smaller. Now, all of these are created through a character body two D, a line two D, and a collision shape. So I'm just going to give you the points for line two D. So go ahead and pause and when you've got that setup, then we can go ahead and advance. I'm going to go ahead and start now by reading out the points for the line two D on the large asteroid, remember to save your scenes. Closed, should we set to on. And the width I'm using on these is two. All of these have eight points. And these are going to starting with the large asteroid here, 40, zero, 30, negative 25, ten negative 35, negative 15, negative 30, negative 35, negative ten, negative 30, 20, negative ten, 35, 25, and 30. Moving over to the media mastoid. I've got again, eight points going down the list, 25, zero, 20, negative 15, five negative 22, negative ten, negative 18, negative 20, negative five, negative 18, 12, negative five, 22, 15, 18. Moving on to the points for the small asteroid, 15, zero, 12, negative eight, three, negative 13, negative seven, negative ten, negative 13, negative two, negative 12, seven, negative three, 13, and 1010. Those are the points that we're using for all of these. And once you have all three of those set up, make sure you've saved all three scenes and you'll have your asteroids set up and ready to go. And the only thing they'll be missing is their rotation. Of course, they need to be spawned in and spawning the smaller asteroid when they get destroyed. So the large ones will spawn medium ones, and medium ones will spawn small ones. 7. Asteroid Spawning: So let's go ahead and allow our asteroids to spawn off screen, move into view. They're going to be able to have different speeds, and we're going to use the same script on all three sizes. So go ahead and create a script, and you can attach it to all three of your asteroids, the large, medium and small, and open up that script. And the first thing we're going to do is we're going to create a rotation speed and I'll create an X four speed. I'll go ahead and save that right now. So if I click on my small asteroid, you'll see we have speed here in the inspector, I'm going to leave that at 100 for small. For medium, I'll turn it down to 50, and for large, I'll make it 20. Now, you can always come back and tweak these numbers later, right? That's always possible. I'm just going to go ahead and set that for now. Now, inside of our ready function, in order to spawn off screen, what we're going to do is we're going to get the screen size from Get VportRc dot SHE. And we're going to get a credit variable for spawn edge. Everyone s Randy percent four, so that's going to get us either a zero, one, two, or three. And based off of this, we're going to determine whether we're going to assign each number or associate each number to be top, bottom, left and right. So we're going to use something called a match statement. And all you do is type in match. The thing you want to match, in this case, would be spawn edge. Colon come down, and we'll say zero because that's an option. Colon drop in, and you have a block of text. Then you can match it with a one, and a block of text, two, and a block of text, and so on. That's how we match statement works. So we're basically saying, Okay, we're going to match this. So if this matches this, do this, it matches this, we do this block, if it matches this, we do this block, and so on. So what we're going to do with that, I'm just going to go ahead and copy this in of course. But we're going on all of these, we're going to go spawn edge. If it's zero, we're going to take its position is equal to a vector two, and that vector two is a random float range, so rand F onto square range between zero and screen size dot X, and then the Y is negative 50. So since it's negative you can assume here that the position here, that the match of zero is going to be up or the top screen. So if we're spawning above our screen, this is where we're going to place our asteroid. And then our velocity is going to be vector 20 on the X, and then our Y is just going to be our speed, right? So with that being a positive number, that means we're going to be moving down and we're going to continue this pattern all the way. So if it's a one, position is going to be a vector two of screen size dot X plus 50. So that means we're spawning on the right side of our screen here, Rand F underscore range, and that's going to give us between zero and screen size dot Y. So we're spawning on the right hand side at any point vertically, as long as we're on the right hand side of our screen. Then our velocity is going to be a vector two. It's got a zero on the Y and a negative speed on the X, so that is moving to the left. All right. And if we match with a two, we're basically going to do the same thing that we did with zero here. So our position is a vector two, rand F on the square range, zero, screensizet X. So we're on the far left side right now. Screensizet Y plus 50. Since we're adding it, we're spawning at the bottom, right, bottom of our screen. Vector two X is zero for our velocity, and it's negative speed, which means our asteroid is going to be moving up. And last but not least, we have a match for three. Vector two is going to be a negative 50 because negative 50 is already going to be off screen as it is, so it's off to the left. Random F range of zero, and of course, screen size dot Y, anywhere on the left hand side, and the velocity is going to be positive speeds that it moves to the right and zero on the Y. All right. So if you have that we actually need to do one more thing because we can't move, and you might have noticed it is we have to go into our physics process, and we need to call move and slide. And I'm also going to add rotation plus equals our rotation speed times Delta. If we test that, you're on my small asteroid. Well, there we go. We saw it across the top. I'll run it again. No, I came from the right hand side this time. I'll try it again. I came from the right hand side again. So we can see it's always completely random, came from the bottom, and it's consistently working. And if we move over to say, my large asteroid where I've made the speed 20 and I test it, again, it's rotating. It's coming from a random direction, and it's just moving slower because we adjust the speed. Alright, so with that, it is now working perfectly fine for us. Our asteroids can spawn and rotate, and they all have different speeds. We now have to get to the shooting and destroying section so that they can spawn smaller pieces of them. 8. Asteroid Destruction: Let's go ahead and we're going to set up our projectile to be able to destroy our asteroids so that it can spawn a smaller one. So the large ones are going to spawn medium, mediums will spawn smalls. So the first thing we need to do is we need to go to our projectile scene, select our projectile, the area two D, look for the collision section under collision object two D and set the mask to two. So layer is the layer that the object is on, and mask is basically the layer it can interact with. So we're going to set mask to two, and then we're going to go to each of our asteroids. And select it and set our layer on the asteroid to two and our mask to one. So this way with mask being one on the asteroid, it can interact with our projectile and with it being on layer two. And the mask two is not selected. The asteroids should not interact with each other, so they should go through each other and not smack each other. All right. And you can do the same thing on the medium and the small asteroid. All right. In my main scene, I just put I moved my player into it and I just pulled in two my medium asteroids for this for us to use as testing here. And if we were to play it, we asteroids are spawning, they come from different direction. In this case, they both came from the right. And there we had one from the right, one from the bottom. Oh, and you can see we didn't kind of smack into it there, which is fine because when it comes to it later, that's going to end up killing our player. So it doesn't matter that we can interact with it right now. All right, so how do we get our asteroids to work up? Well, first, let's go to our projectile. Let's look to the node tab at the signals. And we're going to select body entered. And what this is going to do we connect the signal, just double click it and connect to projectile. This is going to go off anytime a physics body touches our asteroid, because it's a character body two D enters our projectiles area. So body is going to represent whatever has entered this area. So what we can easily do is say, I asteroid. Wow, I really messed that one up. I asteroid and body dot name. Because remember, mine are all large asteroid medium asteroid, small asteroid. So if asteroid is in body dot name, then we must be hitting the asteroid. I'm going to do body dot D asteroid, which the custom function we're going to create here in a moment. And then I'm going to do self.q3. That way, my projectile can destroy itself. Alright. Now, if we were to run it now, of course, this isn't going to work. We're gonna come into an error and somebody like, Hey, destroy doesn't exist. Boom. There we go. Oh, and I haven't pulled this out yet. So I guess that's a good thing. So what I'm going to do is we're going to go to asteroid script, and I'm going to create a variable here called New spawn. This is going to be a bull, which is a true or false. And by default, I'm going to set this to true. I'm going to go down to that match statement that we had, and right above it, I'm going to say I, new spawn, and then I'm going to grab that entire match statement. So from line 13 to 25, highlight them all and hit tab to move it in. And outside of that if statement, I'm going to say se. And what I'm going to do is I'm actually going to select that match statement, and I'm going to paste it inside of my se. But what I'm going to do is I'm going to delete the position changes. So I have all I'm modifying in these matches are the velocity because we don't want to change the position. We just want it to have a random direction that it's going. All right. Now for that destroy function. Now for that destroy function, what we're going to do is, in this case, I have a variable called ST, and I'm loading, in this case, my small asteroid because we're testing with the medium one right now. And I want to spawn two of them, so I'm running a four loop. So four I in range of two, right? So we're going to run through this twice. All right. So running into this fore loop, we're going to create an instance of our small asteroid. We're going to set the global position of our instanced asteroid to whatever our current asteroids global position is. We're going to set new spawn to false. That way we don't run into our match statement to change the position. We only run into it to set the velocity. And we called GparenttAd Child to add it into the scene. And once we've run through that twice, then our big asteroid is going to cue for itself. Now if we run that and give it a test, boom, we can see it works perfectly fine here. And if you're curious about all those red errors down there in the debugger, it's just telling us that we should use call deferred here during our on body enter for what we call body dot destroy. So instead of body dot destroy, what we do is we do body call deferred and pass in Destroy as a screen. And now if you run that, you'll see all those debuggers just disappear. Alright. Perfect. Now we have it destroying and spawning. The medium ones, sorry, the medium ones are destroying and spawning these small ones. So now we need a way for our asteroid to know what it should be spawning or which version it should be spawning and what it is. So if it's medium, it should spawn small, and if it's small, it should just destroy itself. If it's large, it should spawn to medium. So how can we go about this? Well, go up to the top. Let's create ourselves a new variable. Well, to start off, we'll create an enum called the eyes, and this is going to have large medium small. We're going to have an export, so we can change this. So export of our size. And the type here is going to be size from our Enum so all cap size. And we can just leave that blank. If we come in onto any of our asteroids and in the inspector, we should see it. So make sure large is set to large. Medium is set to medium, and the small one is set to small. If I check my main scene, these should automatically be set, but they are not, so I'm just going to delete them and bring in medium one as well. Probably because I just didn't save them. Oh well, not a problem. I'll just bring in two medium ones anyway. All right? Off our asteroid script, we can now come on down. And inside of our destroy, we can go ahead and do a match, right? So we can say match size. It's going to be a sized large There you go. We're going to have a size dot medium, and of course, a size dot small. So this is what we're going to do on all of these. Now, of course, we can basically just copy everything that we have here, cut it out, and basically paste that inside of our medium. Because this is all of our code for that. Yeah. So if we were to test this with our medium asteroid here, it should work exactly the same. Fantastic. We did only spawn two of them, though. I'm sorry, one, which is interesting here. No, there we go. There's two. And I'll test it again. There's two and two. Okay, so it is working, right? So that's working perfectly. Now what I'm going to do is I'm going to copy this and paste it inside of my large. Only obviously, instead of loading the small asteroid scene, I'm going to drag in my medium asteroid scene. So now if we destroy a large one, it should spawn a medium, and we destroy the medium. It should spawn a small. So let's go ahead and take a look. I'll delete both of those out of my scene, and I'll drag in a large asteroid. And let's test it. There's a large medio, he left when he had to come towards us. All right. Time here, store the large. We get a medium, store the medium, we got a small. Alright, so that's working perfectly fine. Awesome. Now for the small, yeah, we don't really need to do anything but just kind of pass on it because that just needs to destroy itself. At the end of the day, we don't need to spawn anything else. But for now, we can leave it like this because we will use this for updating our points later. So we do still need to have our small section here. So now we have our asteroids that not only spawn in different directions, but we can also destroy them, and they spawn the next thighs smaller. Now would be a good time to go in and test it and decide if you want to maybe change up the speed numbers a bit because maybe they move a little too fast for your liking. There we go. We have our asteroid destruction set 9. Spawn Timer and Memory Leaks: Let's set up the full spawning because now that we have the destruction working, we have our asteroids spawning correctly out of the screen area. So let's have it so that it's continuously spawning for us. So what I'm going to do is I'm going to go to my main scene here. I'm going to do plus or add a node. I'm going to add a timer. I want to call this spawn timer. Okay. And this spawner is going to have a wait time of m. Sure. Let's do 2 seconds. Maybe we'll change it. We can always again tweak it later. This gonna start automatically. And I'm going to go ahead and add a script to my main note here. And I'm going to connect a signal, so I'm going to click on my timer, go to the node tab, double click timeout. Make sure Mina is selected, hit Connect. And when it connects, we're going to get a random number, just like we did with our sides. We're going to create a variable called asteroid equals Randy and percent three, so we're going to get zero, one or two, and we can match asteroid 01 and two. And what we're going to do is I'm just going to click into my asteroid script here because we can actually take a piece of this. And it's going to be this long set that we have here. Base off of this, we're either going to spawn the small asteroid, large or medium. So for zero, I'm going to set that as my large. There it is. So one is going to be my medium, and three can be my small. Then all I'm going to do is just do add Child and just do ast dot instantiate. And that should work on all of these lines. All right. So basically going to pick a random number to spawn a random asteroid and then either load up our large, medium or small, and then add it to the scene. All right. Let's go take a look and see if that works every 2 seconds. Boom, boom. Well, oh, here we go. Why can not be destroyed. That is curious. Okay, so the small ones looks like we have an error, some of these. The issue with that is if we were to run this, and if we click on the remote tab, right, you can see all the asteroids that are coming and we take a look, and we see some of them are just getting assigned like character body two D, for example. So it's not always running because obviously they don't have asteroid in their name if they get reassigned a generic name like this, as you can see here. So, what we actually need to do is we need to go inside of our script. Let's go to our projectile. Instead of using if asteroid and body dot name. Let's do I Body dot has method Destroy. Now, if it has the destroyed method, then we're going to call it. And that one change should completely fix this for us. All right. There we go. Right now we don't have any issues with this. Oh, detection. No, it's going. It's going. Now, you can see that we are getting an unlimited amount of asteroids here, so we are creating a bit of memory leak. So we do need to clean that up as well. So in our asteroid scenes, let's go ahead to all three of them and add a visible on screen Notifier two dende. We're going to go over and we'll have the TreenEited signal. And we can connect that to our asteroid script, hit Connect. And all we're going to do in that is do self cute free and save it and we can go over to medium again. Screen exited, connect it. I should have the same name by default, so we should have one function covering all three of these and small at the node, screen exited, connect. So what this is going to do is this is basically going to say when the asteroid goes off screen, then destroy. Alright. So now if we were to take a look at this, and I'll click on remote, so we can see. Who let's actually go to the main scene to play and click on remote. You can take a look. And we can see when they go off screen, they automatically get destroyed, so we're not creating this infinite memory leak for ourselves. All right, so you can see the game is cleaning up after itself, just fine. Alright, fantastic. Now, what we're seeing here is we have a similar issue, right? We see all these area two Ds. These are our projectiles. So we should probably clean up those as well. So we can do a similar thing, right? We can go to our projectile, add a visible on screen Notifier two D, screen exited, connect to our projectile script, and just call Qqare. So if we don't shoot anything and we miss when our projectile goes off screen, that should clean itself up. Let's go over to remote, take a look. And we should see all these projectiles delete themselves. So we got everything nice and cleaned out. Everything keeps deleting itself. All right. Fantastic. All that's left is we need to update our score with giving ourselves some points every time we destroy an asteroid. All right. And, of course, then we need to take a look at our player death, right? Losing our lives for the player. All right. So we can start tackling that next time. 10. Update Score: Let's go ahead and update our score whenever we distore our asteroids. Now, we could use things like get parent and get child, then call methods on that, but a better way to do this is to actually use signals, right? So these things here that we have on the side, only we're going to create our own custom signal and send it to the Guy to tell it to update the score for us, and we'll tell it how many points. Now, firstly, make sure your Guy has a script on it. Mine's completely empty. And then we can head over to our asteroid script, and we're going to create a new exported variable because we need a new each asteroid has a different amount of points, and coincidentally these actually line up with the speed that I have set up. So if we just go through, large asteroids in the game, I believe, give 20 points, the medium ones give 50, and the small ones give 100. So coincidentally it is exactly the same numbers that I gave for my speed for all of these. And the next variable we're going to need here is actually going to be a signal. So we type in the word signal, and then the name of the signal. So I'm going to say destroyed. And I'm going to use open and closed parentheses just like a function because I want to add a parameter. I'm going to call this PTS and cast it as an int. So if we were now to look at our asteroid and go and take a look at the signals, we can see our custom one here called destroyed, and it has an argument called points site PTS, that is an integer that gets passed in with the signal. So for us, whenever we send this signal, we're going to send this points variable with it. So first, we need to actually connect our signal, so I'm going to go to my main scene here for a second and load up my asteroid script. So we're going to do Destroyed because that's the name of the signal. Make sure you get the one with the signal icon here, the one that looks like a Wi Fi symbol. I do dot connect. Now this takes a callable, and all this is saying is who we're connecting to and what function we're calling. So we can just say callable open and close parentheses. The first argument is what we want to attach to. So this is our parent yet child and pass in Index is zero when getting child. Coma the name of the function that you want to call. So for me, I'm just going to call it Update SCORE. And if you're confused on how we got Get parent and get child zero, if we take a look, we have an asteroid in here as an example in our scene. If we follow this line, we do get parent. That takes us up one branch. So up one and up that takes us to Maine. And we want to get to Guy from Main. So for that we have to get a child, and that's going to be its first child, right? It's first branch up there. So from the large asteroid, we get parent to go up and then get child to come back down. So we're connecting to the Guy. And when that signal emits, we're going to look for a function called Update score. All right. Now, I'm going to copy that entire line because we're going to do something a little similar down here when we come down to our destroy function. Only instead of connect, I'm going to call disconnect. Right? That's the only thing I'd change is we're just adding three more letters, right? So disconnect instead of connect inside of our destroy function. This way, we can just kind of clean up the signal. We shouldn't have to, and you'll probably be fine without doing this, but just for a little bit of a better practice, I'm going to go ahead and just throw it in there. Now, when it gets destroyed, we also need to emit our signal because we haven't done that yet. So before we disconnect the signal, we're going to do destroyed, emit, and we need to pass in the argument, which in our case, it's expecting a number to get passed in. So we're going to pass in our points variable. All right, go ahead and save that. So now if we go over to our GUI, actually, you know, at first, let's go ahead and play it, and you'll see we'll have an issue. Right? Well, it looks like our issue isn't actually going to show itself, which is a little interesting, but nothing's going to happen because that function doesn't exist. Eustly no function is being called here. So if we head on over into our Guy and we create this function, so I believe I called an update score like that, and we have one argument, right? Points, so I'm just going to go PTS, and that is an integer. And we can go ahead and we can just print that PTS that it's passed in. And if we run that we should see all of our points getting printed out every time we destroy one. There we go. We've got 100 points there. 20, 50, 100, 50 right, so it looks like this is all working fine. We just need to actually update it visually. But now that we know this is working, we need to keep track of our points, and we need to update the actual label. So I'm going to create a variable here in our Guy. This is going to be our score. This of course, will be an integer and start at zero. So the first thing we're going to do is we're going to do score plus equals PTS. That's why we can add the points to our score. And then we need to actually update the label itself. So let's go ahead and we can use our dollar sign here and get our score label. Dot text. And we can set that equal to a string of our score. Now, this is going to look a little weird. If you take a look at the top left at our points. Come on, spin around a little hippy. And you see all those zeros disappeared, and the numbers kind of change on their own, of course, but you see they're constantly growing, right. So when we get to 1,000, we're just going to have another random another random one here. Should I get that? There we go. So we've grown out an extra number. And you might like that. I don't, especially when I'm doing a classic game like this. So what I'm actually going to do on the end of this. So when we convert this score to a string, I'm going to do Dot pad zeros, and I'm going to put a number in there. Now, if I were to put in nine, for example, we take a look. We can go ahead and update the score. Hey, go ahead and bonk me. That was rude. Boom, you can see we have all these zeros by deva, right? And every time we update it, it looks a little nicer, especially on a retro system, especially when you have a max score as well that could be attained. All right. Now, I'm not 100% sure what the maximum score is, but This does always look nicer when you pad out the zero. So I just went ahead and checked, and the maximum score is 99,990, so that's going to give us one, two, three, four, five, so that gives us five slots. So let's go ahead and turn this down, and we'll check that. Double check those numbers. If we pad it with five, that was a quick one. We just need to get something on the board here. There we go. And that would give us 99,990 as a possible max. All right, so there we go. So if you want to be authentic, pad it with five zeros. There we go. And there goes our little score. Little at it go. Peep peep. And Bank, that would have been a lost life for us, but there we go. Whoops. Still holding the A button. But there we go. We have our score updating every time we destroy our asteroids. 11. Update Lives: Early. So we're going to take a look at adding health, right? So we're going to add player lives here to our game. I know. And since we don't have sprites to use here, we went ahead and drew out our player character. We're gonna have to do things a little different, but that's fine. It won't be too difficult for us. The first thing I want to do is inside of my Goey here. Because things are going to change a little bit. I'm going to go inside my Guy script. I'm going to create an export, and this is going to be my score label variable. This is going to be a type label. And I'll just replace this in my code so I don't have to grab that variable. So I can click on Guy and I'll see score label in my inspector. Click on that and I can assign it my score label node. Alright. Now, I did that because I think I'm going to move this around a little bit when we're setting up our lives. So by doing it this way, we shouldn't have to update it in our code. All right, so I'm going to go to my Buy. I'm going to add a VBox container. Now, a VBox just allows us to vertically stack different things. So, for example, if I add in a label, add in whatever text, and you'll see if I keep duplicating that. You'll see it's all going to be perfectly spaced out vertically, all nice and neat for us, right? And all evenly spaced. So a VBox is really nice. Alright, so I'm going to go ahead and take the score label and stick it inside of the VBox. All right. And if we were to take a look at the Guy, we can see the score label is still set. And because that we don't have to edit our code. And if we go ahead and test it, we can see that ourselves. There's one all the way down there, and we can see our score and everything still works perfectly fine. We don't need to update anything. So it's nice using exports like that at times, especially when you don't know if you're going to be moving things around when designing your I like this. All right. So the next thing I need to do is inside of my VBox, I need to create an H box. Now, an HBox works the exact same way, HBox container, only it's for things going horizontally, side to side instead of up and down vertically. And inside of this HBox, I'm going to add a control. Actually, I'm not going to add the control yet because I'm going to show you why. So I'm going to click on my player. I'm going to grab the line two D where we're drawing our spaceship. I'm going to control C and copy that. Go back to my main scene and inside of the Sage box container. I'm going to hit Control V to copy it in. And you'll notice Whoops. If we just have a bunch of these, nothing is getting organized horizontally like you saw with the V box. And that's because it has to be a control type, right? So it has to be a green node. So that's why we're actually going to come in and inside of Ace box, we're going to add a regular control, and I'm just going to give that control a size here, one lower H box actually needs one, too. But my control, I'm going to go ahead and set it's custom min here to be 15 by 20. I don't know. That might be a little munch. I'm going to take my line two D here and just pull it down and stick it inside of control. Double. All right. So just so I can see things a little clear, I'm going to select my control. I'm going to turn on clip contents in the inspector, and now I'm going to select my line two D, and that's going to allow me to move it in a little better, find out where those limits are. And I'm going to go down to my rotation, and I'm going to put -90 degrees just so I can rotate it up, and I can see I need to move it down more. Whoops, down one right there. Alright. Now I can turn clip contents off here. And I can see my Y is a little too much, so maybe 15 there as well. That might be a little short. 16. Once I'm happy with that. Before I'm putting it, I can take a look at my H box, and if I just copy this control now, I'm going to select it and do Control D. We can see now because it's inside of a control, they're getting all nice and evenly spaced. O so if we go ahead and play it, we can see it looks nice up there, right? Just like our ship, and it's part of our UI. So since we didn't have any sprite to go up there, we're just taking advantage of the line two D that we already used to draw our ship. And now that we have our ship working, and you see it's going to be in front of us here, just like the rest of the UI, just as a shod. So now we need the actual lives working. So we need to subtract lives whenever we get hit by one of these asteroids instead of being able to push it around like this. For that, our player needs live. So let's go to my player script. And do you want to put our lives there? No, you know, I think I'm going to put it my Gui. And I'm also going to create another export for my HBox. I'm going to say export of our Lives container, and that's going to be an HBox. And I'm going to create another variable here for Lives, which of course is going to be an int, and the starting amount here is three. And we'll go ahead and create another function called Update Lives. Alright, and we'll just pass for now. All right. So the question is, how are we going to detect when we run into the player or when the player runs into an asteroid? To do the collision to subtract from our lives and pass up our signals, let's head over to our asteroid and inside of our physics process. We're going to check if our asteroid is colliding with anything. So say bar collision count equals slide, collision count. All right? So we're going to see if we're colliding with anything, and if so, right? So we'll say if collision count, which means we're colliding with at least one item in order for this to be true, right? It's the same thing of saying if collision count greater than zero, right? It's the same thing, less words. So if collision count, then we're going to get the collision, and we're going to assign that to slide collision, and we're going to pass in index zero so we can get the first item we're colliding with. Then we're going to get the collider itself. So far, collider equals collision dot et collider. And if we were to just print this out to see what we have, here we go. Let's go ahead and run this, and we'll see when our asteroids show up when we run into it with our ship. We can see a character body two D is being hit and it has the name player. So we are definitely detecting when the player gets hit by the asteroids. Alright. So so far so good. We know we're hitting something and that something is our player. So in this case, it has to be the player. There's no way it isn't. But to be safe, again, we could be like, I collider dot name is equal to players. So if we just want to make that double check, we could do something like this. And we've already checked that it is hitting the players. What we can do here is self dot free, right? So we can destroy the asteroid when we run into it. And we can test that working. Always test your code. B, p, p, p, boom. Alright, so so far so good. Every time we get smack an asteroid, the asteroid gets destroyed. Boom. And we can still shoot and destroy them. All that still works. But boom, boom. All right. Now, what we also want to do here is we need to emit a signal here, right? Because we need this signal to go with updating our lives from the player and the asteroid. So we need a new signal from our asteroid here. So we're going to say signal, asteroid hit. And we don't need to pass in any arguments for this. We just need to know that the asteroid has been hit. So we're going to take that, come on down. And once we connect with the player before we u free ourselves, we're going to emit this signal. So asteroid hit dot emit. And then we can disconnect. Asteroid hit disconnect. Now I'm aware we haven't connected it yet, but we are going to here. And this is actually going to be very similar to our connect. So I'm just going to go ahead and copy the argument there from the callable. So we're going to connect to the GUI and pass in this function to disconnect from. And in this case, mine is called Update Lives. All right, so I'll pass that in. Well, it looks like I'm missing a parenthesis here. Let's see. You're part of that set, you're part of that set. And I have one too many. There we go. All right. So I'll copy that whole line. I'll move up to my ready function. And just like the destroyed signal, I'll connect this one. So connect instead of disconnect. There we go. Then we have two signals that we're connecting and ready, and one that we emit and disconnect when we get destroyed, and one that we emit and disconnect when we hit the player. Alright, so now we need this function to actually do something. So in our Gooey script, we can take a look at this and we update our lives. So we can do lives minus Sequals one. And then we need to update our lives label. Do I need to update that? Because I changed the name? I do. Go because I had a typo in there. So I'm going to get my Lives Container dot get children or Get Child Count. What do we want to go with? I'm basically going to set this with what we want to remove. We do down to two. So I'm going to do Lives Container dot, get child. I'm going to pass in our Lives count here. So it's going to start at three, and then once we get hit, that'll become two. So two is going to grab our newest our latest one here, latest life because we only have three, and it comes up at index 01, two, and I'm going to call Dot Hyde. We' call Hyde on it? No, probably because it's with that control. So what we do instead, Just because it doesn't know what child is, we'll say Dot visible, equals false. Stuff if we try that we should see our lives. We see the first one here on the far right disappear once we get hit with an asteroid. Boom, there we go. And it looks like we somehow got hit with a second one. That right? Everything seems to be working. I'm not sure what that was. Maybe one spawned when I looked away. But there we go. We have this working, of course, this is gonna air out now. Or at least it should, but it doesn't. A little curious should be telling us that this isn't working because of the index. That's kind of curious. I guess we're getting negative, maybe it's coming back around. Anyway, coming through here. So we have our lives disappearing. We have our lives updating. And based on that, we would need a lives to go into a game over or not. But first, I do want to set a minimum number here or maximum number just so that we can't go below zero in our lives. So what I'm going to do is I'm actually going to say lives equal to. And we want the max number here between lives minus one and the second argument is zero. Even though we shouldn't need this, I'm just going to put this in just in case to ensure that we don't have some kind of bug that happens there. So our lives should never go below zero. And there we have it. We have that issuing, and all we would do now is we could call game over if we hit zero and restart the scene. All right. Now we'll do it here because all we want to do is update the lives. We've done that. And next time, we'll go ahead and set up the game over and restart. 12. Game Over and Restart: Before I game over, I'm going to go ahead and go into my Guy. I'm going to add another note here. I'm going to add a label. This will be my game over label. This text, it's just going to say game over. I'm going to put this anchor it, right here at the top. I'm going to put it in the sender of the screen to say game over whenever we lose. We can go into our code and with our update lives, create a new function. Game over and we'll simply do a check after we've updated the screen. I will say, I lives equals zero, then we call our game over function. And the game over function Well, I don't need that to be showing. I'll put that pass back in. I'm going to go ahead and create an export here for my game label, GameOver label. I'll assign that and inspector here real quick. GameOver label. So what do. GameOver label dot Vsb equals crew We can pause the tree, right? So it's a G tree. And actually, I'm not gonna pause the tree this time. I think we want to get the player from the Goey. I think the player can handle the second. Right. How do I want to do this? Alright, so I'm going to click on my player here in my main. I'm going to left click it, and I'm going to drag it in. And I'm going to release, and this should give me the path to my player. So I'm just going to say dot Qu free to delete my player. Once you've run out of Lives and go to a game over, I'm going to say, I'll wait. Get Tree, create timer. This way, we can go ahead and wait 3 seconds or something. You can go ahead and play with that timer and see what you like. Dot TO, right? We've done this before. And then we're just gonna say Get dot. Reload Current scene. So let's take a look when we get a game over. To do. We can go in. We can play. We can shoot, get points. But, but, bah. It's all fine. Boom, we got hit, we lost one life. Boom, we lost two lives. Was our little ship. There is, and we're going to lose our last life. Boom, game over. Wait 3 seconds. Game reloads and we can keep playing. Alright. So there we have it. We've got our game over simply set. And we're all set to just start playing with our game here. Now, if you want this to be a little more authentic to have the black screen, you can either go into your project settings and I just search the word color and go in a rendering environment. Default color. You can come in here and you can change this color if you want. This is the default color of the background. You can do that if you wish. But since I usually prefer keeping the default color here, what you can do instead is you could just come in and do a color wreck, set your anchors to be full. Well, it looks like it's not going to because we don't have control as the main. I see. Alright. So we'll just have to go in and set this up ourselves. So you can just set the size to be whatever size you want. As long as it's big enough to cover the blue area, you should be fine. And come in and change it to black. And since we're only going to show what's in the blue area, it doesn't matter that it's bigger. So we'll go ahead and play Oh, and I need to change the ordering. So I need to grab the color retire and actually pull it up all the way up that way my player is on top of it so we can see. And there you go. We have something that looks even more closer to the original by having the black background. But again, that's just a personal choice on if you want to have that. B, boom, but, p, p, p. And it actually looks like a Our game. Oh, and if you're just wondering why the scoring that isn't working. It's probably just because I pulled Color Rect up to be the first child. So Index zero, I'm trying to connect my signals to color rect instead of the GUI. So if I just pull it down so that the GUI Come on, get out of there. There we go. So that the Guy is first, then that should fix our issue here. See, boom, Lives now connecting and our score. So that's just an ordering layer in the scene hierarchy. So that's just something to keep in mind if you were to, of course, do it this way and not do your project settings. Alright, there you go. We have our points. We have lives. We have GameOver. We have to restart. And we've made once again, another full game without needing any resources. We've made everything from within the engine. All right, that'll do it. We now have asteroids. And if you want to take it a step further, you can go ahead and again, you can find sprites online, or you can use the Line two D and go ahead and create those spaceships that you've seen and assign them some points. And the same thing, give them a signal, connect it up to your GUI, send the points with it, just like we do with the asteroids.