Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Adding Laser Bullets to Your Game

00:00 In the previous lesson, I showed you how to add rocks to your space rocks game. In this lesson, I’ll show you how to shoot those rocks with your space laser.

00:09 Things are coming along quite nicely. You’ve got a ship, you’ve got some rocks, now let’s add your ship’s gun. The bullets in the game will be treated like any other object, so once again, you’ll be extending GameObject, this time to create a bullet specific class.

00:25 The bullets need to come out of your ship and then continue along their original trajectory in a straight line. So once you’ve got the Bullet object, you’ll need to add some code to make the shooting happen and management of the bullet into the game logic code.

00:41 I’m inside of models.py, scrolling all the way to the bottom. Not much of a surprise here. New lesson, new child of GameObject.

00:50 One small change is that new parameter on the end of the call to .__init__(). Let’s look at what’s happening here. I’m going to go back to the top of the file.

01:00 Notice the new optional parameter to GameObject. Sometimes you want objects to wrap when they hit the edge of the screen, and sometimes you don’t. This parameter and a bit of extra code will take care of that choice. Line 15 stores the .wraps variable for later use.

01:20 Inside of the .move() method, if .wraps is on, use the wrap_position() utility function when calculating the new position.

01:28 Or just take the new position.

01:31 It is time to start figuring out how to shoot things with your brand spanking new Bullet objects. Bullets come out of the spaceship, so let’s take a look at the Spaceship object code. First off, I’ve added a constant to specify how fast bullets go.

01:47 There are going to be multiple bullets on the screen at a time, and you’re going to need somewhere to store them. There are a couple of different ways you can do this.

01:55 Both the ship and the game logic are going to need access to this container. Let’s have the container live outside the ship but pass in a reference. And, of course, store it for later use.

02:08 Now, to add a function on the ship that shoots the bullets. The first thing you need to do is calculate the velocity of the bullet. Take the current direction of the ship, multiply that by a bullet speed, and add it to the velocity of the ship.

02:23 With the velocity determined, you create the bullet object and add it to the container. And just below that on line 55, I’m going to add a bit of print debugging for now.

02:33 Every time you shoot, a message will show up in the terminal telling you how many bullets are in the container. With the model in place, it’s time to make changes to the game file. Switching over to game.py.

02:49 Inside of the .__init__() method on line 16, I create a list to store the bullets. On line 18, I update the creation call to the Spaceship object, passing in that newly created bullet container. Next up, I’m going to add shooting to the input handling code.

03:06 Let me just scroll down. Here, I’m looking for the KEYDOWN event. Remember that when you press a key, the KEYDOWN event triggers only once. This is different from the .get_pressed() dictionary that contains True for as long as the key is held down. For accelerating the ship, holding the button keeps accelerating. For shooting, it is different. It doesn’t matter how long you hold the key, it only fires once.

03:32 When I first coded this out, I used .get_pressed() for shooting by accident, and instead of getting a single bullet, I was getting five or six in a row, creating a little line.

03:42 Understand when to use KEYDOWN versus .get_pressed() as it changes the dynamic of how your user interacts with the game. Okay, with that cleared up, what KEYDOWN am I listening for?

03:54 The Spacebar is a common key to use for shooting things, and who am I to buck with tradition? Spacebar key is down, call the ship’s .shoot() method.

04:04 Scrolling down to the .game_objects() property. You’ve got more objects in the game now, so this property needs to be updated so that it returns all the rocks, all the bullets, and the ship. Now ask yourself a question.

04:17 What should happen to a bullet when it goes off the screen? The rocks and ship wrap their positions. That might be a bit crazy with bullets. It might lead you to having to deal with the fact that you could shoot yourself.

04:29 Instead, as you might’ve guessed when I changed the wrap handling code in the GameObject base class, let’s have bullets disappear when they go off the screen. To do that, the first thing you have to do is detect when they leave. Some changes to the game object method will handle that. Line 54 gets the bounding rectangle of the screen. Line 55 iterates through all of the bullets. Python gets wonky if you try to modify a list while you’re iterating over it.

04:58 As the desired result of the bullet being off the screen is to remove it, you’re going to need to iterate and remove at the same time. There are two ways to handle this in code: Either create a temporary list of objects to remove and remove all of them after you’re done iterating, or what I’m doing here, which is using a copy of the list.

05:18 The [:] notation here is using list slicing, but saying, “Give me a slice that is the whole list.” This gives you a copy of the list. Line 55 is actually iterating through that copy of the bullet container.

05:34 There are pros and cons to doing this. Keeping a separate remove list requires extra code. Iterating over a copy means a bit of extra memory in use. Our list of bullets is so small, but that isn’t really a problem in this case, so I’ve gone with the second choice. For each bullet in the copy of the bullet container, I’m checking if it collides with the screen. If it doesn’t, that means it has gone off the edge of space.

05:59 Therefore, it can be removed from the bullet container. You’re all set. You’ve created bullets, you’ve added code to shoot them, you’ve added code to handle when to delete them. Time to see it all in action.

06:12 And here you go. Let me shoot a couple of times.

06:18 Watch the bullets go off the screen. I’m going to shoot a bit more. See how the total bullet counter in the terminal has changed? That’s great. It means our bullet removal code has worked. Our bullets aren’t perfect.

06:31 Just like our ship and rocks, they don’t hit anything yet, but that’s for the next lesson.

06:38 Enough ghostly objects passing through each other. Let’s crash stuff together.

06:45 “Hulk smash!”

Become a Member to join the conversation.