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

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands 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.

Using Pygame to Build an Asteroids Game (Summary)

Congratulations, you just built a clone of the Asteroids game using Python! With Pygame, your Python knowledge can be directly translated into game development projects.

In this course, you’ve learned how to:

  • Load images and display them on the screen
  • Add input handling to your game
  • Implement game logic and collision detection in Python
  • Play sounds
  • Display text on the screen

For more information on concepts covered in this lesson, you can check out:

Download

Sample Code (.zip)

6.3 MB

Download

Course Slides (.pdf)

900.2 KB

00:00 In the previous lesson, I showed you how to add text to the screen. In this lesson, I’ll wrap up the course.

00:07 This course has been all about creating your first game in Python using the Pygame library. By building an Asteroids clone called Space Rocks, you’ve learned about game loops and the main Pygame library methods, what sprites are and how to blit them, rotate them, and move them around.

00:25 You’ve also learned how to respond to keyboard input, how to play sounds, all about loading fonts and displaying text, and general game writing awesomeness.

00:37 Here are some ideas you can try to improve your game even further. In the lesson where ship collisions were added, I pointed out that using None for a destroyed ship meant there was a danger of crashing your code. I walked you through fixing a couple of spots but left one out. If you didn’t find it, I’ll tell you now. Fire the gun after the ship is destroyed, and the code will crash.

00:59 The simple way would be adding a None check inside the keyboard handler that fires the gun. Or, the better long-term way, that involves adding an alive and dead state to the ship class.

01:12 You would then modify the class further to behave correctly after the ship is in the dead state. This method takes a bit more work, but is probably the better solution, particularly if you’re going to… add more lives to the game!

01:27 This can be about more than just allowing the player to restart three times. You can also add a "press space to start" message with the game paused after each time the player respawns. Right now, it is possible if you accelerate in just the right way, for the ship to overtake the bullets. If you manage this, you’ll discover that these are magic bullets that only destroy rocks.

01:48 You could add some code to make them fatal to the ship.

01:52 Or, what’s a game without a score? Add something to track the score and display scoring text. You’ll need to update print_text() to do this, as right now, it only displays text as a centered message on the screen.

02:05 You can also add a play again key. When the game is done, the player should be able to play again without having to close the window and restart the program. And finally, if you want a real challenge, add an instant replay movie. Show the player what happened and how they lost.

02:22 This one could get messy. You could store all the positions of all the objects in order to create the new frames for, say, the last three seconds. Or, in a more memory-intensive version, you could store copies of the frames in buffers. When a user dies or wins, you then create a playback using the position information or the buffers.

02:40 Of course, you’d also want the player to be able to skip past this playback and get on with the game. This one could be fun to code.

02:49 Here are two great sources for more Pygame goodness. This is a link to the Pygame documentation, which is a great way to find all the ins and outs of writing Pygames.

02:59 And this is Christopher Bailey’s course on writing a 2D side-scroller in Pygame. It covers some of the same basics as this course in more detail, and it also talks about sprite groups, playing background music, and more.

03:13 That’s it for Space Rocks. I hope you enjoyed the course. Thanks for your attention. Leave a comment below bragging about any neat features you’ve added to your version of the game and challenge your fellow Pythonistas.

mikesult on Oct. 26, 2021

Thank you Christopher and the Real Python team for this course. I really enjoyed it. I especially appreciated the discussion on choosing to use globals and how that changed the code, the tradeoffs and so on. The little bug to find was a good exercise. I ended up using the first method but not before I had created an infinite looping method that I had to use ‘force quit’ to recover infinity->now. Oops. All along the way you discussed some alternate paths and your reason for coding it this way in this context. That discussion is helpful to me to understand the issues that you are considering. Thanks also for all of the resources, sample code for each video segment, etc.

And lastly, maybe most important these days, it was fun.

Christopher Trudeau RP Team on Oct. 26, 2021

Glad you enjoyed it Mike! It was a fun course to build. ..ct

Rok Kužner on Dec. 31, 2021

Thank you all for making such a great tutorial! I imporove my game by ading sounds for weening anl losing. I also add score: Utils.py:

def print_score_text(surface, text, font, color=Color('green')):
    text_surface = font.render(text, True, color)
    rect = text_surface.get_rect()
    surface.blit(text_surface, rect)

and game.py in function draw:

print_score_text(self.screen, f'Score: {self.score}', pygame.font.Font(None, 40))

I also add Do you like to play again by adding some lines of code in function draw:

if self.message:
            if self.message == 'You lost! Press r to play again.':
                print_text(self.screen, self.message, self.font)
                you_lost_sound_f()

                is_key_pressed = pygame.key.get_pressed()
                if is_key_pressed[pygame.K_r]:
                    from game import SpaceRocks
                    space_rocks = SpaceRocks()
                    space_rocks.main_loop()
            else:
                print_text(self.screen, self.message, self.font, color=Color('green'))
                you_ween_sound_f()

                is_key_pressed = pygame.key.get_pressed()
                if is_key_pressed[pygame.K_r]:
                    from game import SpaceRocks
                    space_rocks = SpaceRocks()
                    space_rocks.main_loop()

I also like to add instant replay but I don’t know how. Can you help me with this?

Thanks for everything Rok.

Christopher Trudeau RP Team on Dec. 31, 2021

Hi Rok,

I haven’t tried it myself, but I can think of two ways it could be done:

1) Keep a list of screen images and each time you do your blit to the screen, store a copy on the list. The list should be limited in size: once it reaches a certain number of items, add one and remove one. The number of images in the list would be related to the amount of time in your replay. If you’re doing 20 frames-per-second and you want 3 seconds of replay, you need to store 60 images.

2) Or, instead of storing the screen images, you can store the state of the system – the positions of all the rocks, bullets, and your ship. I’d create an object that kept this and then keep a list of those storage objects.

The first case is likely easiest to code but would take up more memory. The images to the screen aren’t compressed so each image would take up at least a byte per pixel (it might be more than that) and you have 800x600 pixels. Multiply this by 60 and you’re going to be at least 28MB of memory. Modern computers can handle this fine, but this isn’t how it would have been done in olden times.

The second case will require less memory but more work. You’re only storing the positions of the objects, which of course varies by how many objects, but lets say 50. The positions of them are a couple of bytes, let’s keep the math simple and say 20 bytes per object. Still need 60 frames’ worth, so that’s around 60KB. Much less memory. But, now you have to write code that is similar to the playing code to replay the game using this data instead of what the user input. If you’re careful with your method calls, it shouldn’t be much different than the code you currently have – in addition to move() you might want move_to(pos). Depending on how the code shakes out, move() could call move_to(pos), but I suspect they’re both only a couple of lines each and it might not be worth the extra function call.

(As an aside, if you’re really careful with how your random numbers are generated, you don’t even have to store all 60 positions. There are ways of getting random number generators to spit out the same sequence of random numbers given the same starting seed. If you did it this way, you’d only have to store the position of everything 60 frames ago. Look up random number generators and seeds in the random library if you want to dig into this mechanism).

If you’re going to add a replay, you probably are going to want to react to a keypress during the replay to abort it – I hate having to watch the cinematic in a game I’ve played before, I want a “skip” button. :)

Happy coding!

Rok Kužner on Dec. 31, 2021

Thanks for answer! I will shere my code with you when I’m done with coding.

Rok Kužner on Dec. 31, 2021

Do you meybe know how to take pygame window screenshot and how to display it to the screen?

Christopher Trudeau RP Team on Jan. 1, 2022

Hey Rok,

So I haven’t tried this, you’ll have to play a bit, but looking at the documentation, the pygame.display object has a .get_surface() method, and the pygame.surface object can be copied and blitted to other surfaces, so that would be where I started.

Take a look here:

www.pygame.org/docs/ref/display.html

and

www.pygame.org/docs/ref/surface.html

There’s a chance you might have to change some of your methods to draw to the surface and then blit it to the screen, but if you can get the screen’s surface, it likely would just be two lines of code (get_surface() and copy()).

Good luck with it.

Rok Kužner on Jan. 1, 2022

Thanks! 😀

froyathehen on April 25, 2022

Christopher Trudeau, not only was it educational but a great deal of amusement! Looking forward to getting through some more content of yours ^^ Thanks!

Christopher Trudeau RP Team on April 26, 2022

Glad to hear you enjoyed it @froyathehen and happy that the jokes aren’t falling completely flat.

Become a Member to join the conversation.