Level 4: Challenge 2 - IncrediCoders/Python1 GitHub Wiki

SW_avatar2

SideWinder added this page on June 6, 2025

Let's begin your second challenge for Level 4!

You are going to write code that will add asteroids to the game. You can even hide behind the asteroids and use them as a shield!!

To find the Level 4 Challenge 2 code template, open the Level 4 folder, the Challenges folder, and then the Challenge 2 folder. You should already have the files downloaded onto your computer (see Load the IncrediCoders Files). Open the SpaceWarsChallenge2.py file in Visual Studio Code to build the program by following along with my instructions below!

I broke these instructions down into a few sections:

Explaining the Code

On Line 1, you will see the comment, #Runs the init.py file and imports the libraries. This tells you what Line 2 does.

On Line 2, from init import *, initializes the program with the init.py file. This includes code that sets up the file path for the images and text file, gets the fonts ready for this game, sets the window size, and loads the images. It also imports a few different modules into the program, including pygame, sys, match, time, random, path, and os. It sets the global color valuables and the global variables (like the direction variables). It also creates a framework for the general classes and functions that the game uses.

This Line 2 statement allows you to use all the code in that file, for the rest of your program.

NEW CODE: On Line 4, you'll find the code definition, def update_asteroids(delta_time): Line 5 explains with the comment, #TODO: Write code to update the position of the asteroids in the game window. You're going to write this block of code (Lines 6-13) to define the update_asteroids() function. You'll use the delta_time argument to update the position of the asteroids in your game window. See the next section, "Write Your Own Code", for guidance.

On Line 15, you'll see the comment, #The Update method checks for all the key presses and button clicks. That's what most of the rest of the game code does! Lines 16-67 check for all your key presses and button clicks. It then takes action, based on the mouse and keyboard input.

On Line 16, def update(delta_time): updates each time that a user presses a key or clicks a button with the mouse.

On Line 17, for event in pygame.event.get(): starts a for loop that runs for every event (keyboard press or mouse click) in this program file.

On Line 18, you'll see the comment, #Checks if you click the Replay button to play again.

On Line 19, check_replay_click(event) checks to see if the user clicked the Replay button after the game ends.

On Line 20, you'll see the comment, #Checks if you closed the window. This comment describes Lines 21.

On Line 21, if event.type == pygame.QUIT: checks to see if the user clicked the Exit button (a red X on PCs) to close the window. If so, then Line 22 runs.

On Line 22, stop() stops the program from running. Line 22 only runs if the previous Line 21 is true.

On Line 23, the code comment, #Fires the two ships' weapons, explains that Lines 24-31 contain the code that checks if the attack buttons are pressed (Spacebar and Return), and then the code loads the related sound effects, plays them, and then fires the projectiles.

On Line 24, elif key_down(event, pygame.K_SPACE): checks to see if the space key has been pressed. If it has, then the program runs the indented code in this elif block (Lines 25-27).

On Line 25, the code pygame.mixer.music.load("Solutions/Level4/Challenges/Assets/LaserShoot1.wav") runs if the user presses the Spacebar on the keyboard. This line loads LaserShoot1.wav sound file for the program to use.

On Line 26, pygame.mixer.music.play() plays the sound that the program loaded.

On Line 27, fire_bullet(1) fires the projectile for Player 1.

On Line 28, elif key_down(event, pygame.K_RETURN): checks to see if the player presses the Return key. If so, then the program runs the indented code on Lines 29-31.

Line 29 is almost the exact same as Line 25. The code pygame.mixer.music.load("Solutions/Level4/Challenges/Assets/LaserShoot2.wav") loads the LaserShoot2.wav file for Player 2's attack. The only difference is the file name. The two files sound the same, but we kept them separate for a reason. You can skip ahead to the "Bonus Challenge" section below, for a little challenge for you to come up with your own projectile sounds!

On Line 30, pygame.mixer.music.play() plays the sound that the program loaded. This is the exact same line of code as on Line 26.

On Line 31, fire_bullet(2) fires the projectile for Player 2.

On Line 33, #Rotates the Player 1 ship explains that Lines 34-37 are going to rotate the Player 1 ship, both clockwise and counter clockwise!

On Line 34, if key_held_down(pygame.K_a): checks to see if the A button has been pressed. If it has, then the game runs the indented code on Line 35.

On Line 35, MY.player1.add_rotation(ship_rotate * delta_time) rotates Player 1's ship counter-clockwise.

On Line 36, elif key_held_down(pygame.K_d): checks to see if the D key has been pressed. If it has, then the game runs the indented code on Line 37.

On Line 37, MY.player1.add_rotation(-ship_rotate * delta_time) rotates Player 1's ships clockwise, since there is a - symbol before the ship_rotate variable.

On Line 39, you'll see the code comment, #Moves the Player 1 ship forward and backward. This comment explains that Lines 40-43 move Player 1's ship forward (with the W key) and backward (with the S key).

On Line 40, if key_held_down(pygame.K_w): checks to see if the W key has been pressed. If it has, the program runs Line 41.

On Line 41, MY.player1.add_velocity(MY.player1.rotation, ship_accel, ship_max_speed) moves Player 1's ship forward, using the acceleration and maximum speed variables.

On Line 42, elif key_held_down(pygame.K_s): checks to see if the S key has been pressed. If it has, then Line 43 runs.

On Line 43, MY.player1.add_velocity(MY.player1.rotation, -ship_accel, ship_max_speed) moves Player 1's ship backward, since there is a - symbol before the ship_accel variable.

On Line 45, the code comment #Rotates the Player 2 ship explains that Lines 46-49 will rotate Player 2's Nocturn ship counterclockwise (to the left) and clockwise (to the right).

On Line 46, if key_held_down(pygame.K_LEFT): checks if Player 2 presses and holds the left arrow on the keyboard. If so, Line 47 runs.

On Line 47, MY.player2.add_rotation(ship_rotate * delta_time) rotates Player 2's ship counter-clockwise. When we write code in an if block like this, we always make sure to indent to the right (so that the line is seen by Python as part of the 'if' block).

On Line 48, elif key_held_down(pygame.K_RIGHT): checks if Player 2 presses and holds the right arrow on the keyboard. If so, the indented code on Line 49 runs.

On Line 49, MY.player2.add_rotation(-ship_rotate * delta_time) rotates Player 2's ship clockwise, since there is a - symbol before the ship_rotate variable.

On Line 51, the comment #Moves the Player 2 ship forward and backward, describes that Lines 52-55 move Player 2's ship forward (with the Up arrow) and backward (with the Down arrow).

On Line 52, if key_held_down(pygame.K_UP): checks to see if the Up arrow on the keyboard is being pressed by Player 2. If so, the program runs the following indented code that's on Line 53.

On Line 53, MY.player2.add_velocity(MY.player2.rotation, ship_accel, ship_max_speed) moves the Player 2 ship forward. Again, this happens because the player presses the Up arrow, which Line 52 checks for.

On Line 54, elif key_held_down(pygame.K_DOWN): checks to see if Player 2 is pressing the down arrow on the keyboard. If so, the game runs the indented code on Line 55.

On Line 55, MY.player2.add_velocity(MY.player2.rotation, -ship_accel, ship_max_speed) runs, since the Down arrow is being pressed by Player 2. This line moves Player 2's ship backwards, since there is a - symbol before the ship_accel variable.

On Line 57, you'll find the code comment, #Updates player objects on screen.

On Line 58, update_players(delta_time) updates the player objects (the ships) on the screen.

On Line 60, you'll see the comment, #Checks if bullets have been fired and updates their behavior on screen. This tells you what Line 61 does. It's helpful to write comments in your code like this, so that other programmers can understand what you're doing!

On Line 61, update_bullets(delta_time) checks if the bullets have been fired and updates the behavior of those bullets.

NEW CODE: On Line 63, you'll see the code comment, #TODO: Call the method that updates the position of the asteroids in the game window. Since this is related to the new asteroids feature that we added into the game for Challenge 2, you're going to write a new line of code on Line 64. See the next section, "Write Your Own Code", for guidance.

On Line 66, # Checks win condition describes Line 67. It's going to show you which of the players won the game.

On Line 67, check_win() displays who won based on the win condition.

On Line 70, #Registers the states describes Lines 71-72.

On Line 71, Manager.register(sys.modules[__name__]) # The current file registers the current file and the main game state.

On Line 72, Manager.register(GameOver) registers the end screen when the game is over.

On Line 66, Manager.register(GameOver), this is the code that tells the program that the game is over, and to restart the program which is what Lines 68 and 69 will do.

On Line 74, # Runs the game is a commented-out line that describes Line 74.

On Line 75, Manager.run(SCREEN, WINDOW, BLACK, "CHALLENGE2") resets the game back to beginning of the program, allowing the players to play Challenge 2 again.

Write Your Own Code

First, you're going to write the new code for Lines 6-13. See the code comment on Line 5, #TODO: Write code to update the position of the asteroids in the game window. You're adding the asteroids to the game for Challenge 2! The players are stopped by these asteroids, and they can hide behind the asteroids, to block the projectile attacks from the other player. They can't destroy or take damage from the asteroids.

On Line 6, you're going to start with a for statement. Type in the code, for asteroid in MY.asteroids: This for statement runs the for block loop for each asteroid. The for block (Lines 6-13) makes sure the asteroids are on the screen (wrapping to the other side), and it checks to see if the players run into the asteroids.

On Line 7, you'll see the comment, # Updates the state of each asteroid. This comment explains to the developer what the next lines of code do. Comments like these help developers understand the logic used in your code files.

On Line 8, make sure the code is indented at the same level as Line 7 (so that it runs as part of the for block that starts on Line 6). Type in the asteroid.update() function. Inside the parentheses, type in the delta_time variable as the argument for the function. This function checks all the events that happen with each asteroid (such as movement and collisions) and makes sure the asteroid is displayed correctly.

On Line 9, at the same indentation level, type in the screen_wrap() function. Type in the arguments asteroid and My.window in the parentheses. Add a comma after the asteroid variable, to separate the two arguments. In this argument, the screen_wrap() function moves the asteroid to the other side of the screen when it goes off screen.

On Line 10, write an if statement that just checks if the My.player1.collides_with() function is true. After you write the if keyword, add a space, and then type in the function. Inside the parentheses, type in the asteroid variable as the argument. After the end parenthesis, type in the : colon symbol. This if statement checks to see if Player 1 flies into the asteroid. If so, then the function returns True to the program, and the program runs Line 11.

On Line 11, type in the My.player1.velocity variable. Then, add a space, type in the = symbol, and add another space. Next, type in the pygame.math.Vector2() function. Add the arguments 0, 0 in the parentheses. As I mentioned, this line only runs if Line 10 is true, which means that Player 1 ran into the asteroid. This line of code stops the Player 1 ship from moving. The pygame.math.Vector2(0, 0) code on the right of the = symbol, is going to change the Player 1's ship movement to 0 in both the X and Y axes. This value is then set into the MY.player1.velocity variable to the left of the = symbol, so that the ship stops moving.

On Line 12, write the code that checks if Player 2 collided with the asteroid. This is the same code as Line 10 (which checks if the Player 1 ship ran into the asteroid), but you'll replace the 1 with a 2 instead. So, the function is MY.player2.collides_with() instead. Both functions use the same asteroid variable as the argument (inside the parentheses). Just like Line 10, if this function is true, then the lines in the if block run. In this case, if Line 12 is true, then Line 13 runs.

On Line 13, write the code that stops the Player 2 ship from moving. This is the same code as Line 11 (which stops the Player 1 ship from moving), but you'll replace the 1 with a 2 instead. So, the variable on the left is MY.player2.velocity instead. This line only runs if Line 12 is true, which means that Player 2 ran into the asteroid. This line of code stops the Player 2 ship from moving. The pygame.math.Vector2(0, 0) code on the right of the = symbol, is going to change the Player 2's ship movement to 0 in both the X and Y axes. This value is then set into the MY.player2.velocity variable to the left of the = symbol, so that the ship stops moving.

Next, you're going to go down to Line 64. On Line 64, make sure you're aligned at the same indentation level as the comment on Line 63. Then, type in the update_asteroids() function. In the parentheses, type in the delta_time variable as the argument. Just like Line 58 updates the player ships on the screen (with each movement) and Line 61 updates the projectiles on the screen, Line 64 updates the asteroids on the screen, also after each movement and collision.

You did it! You have successfully added asteroids to the Space Wars game! Try it out, and note how the game is different. Now you get stopped by the asteroids. You can use asteroids as shields (to block the other player's projectiles, or you can even use an asteroid to slow down if you're going fast!

Also, the game has the sounds you added in Challenge 1, so you might be surprised by the sounds if your volume is turned up.

The Final Code

I included a solution file for Level 4, Challenge 2. This file has all the code filled in, so if you run into any issues with your code (for example, if it doesn't compile/run, or if something isn't working correctly in your program), then you can take a look at the final code file to see what you did differently:

IMPORTANT: Please don't cheat yourself! Finish the game first!

Bonus Challenge: Customizing the Laser Sounds

We have yet another challenge for you! This is just to play with the code a little to get familiar with it and to see how you can make the game your own!

We mentioned earlier that we load the sound file on Line 25 (for Player 1's attack) and Line 29 (for Player 2's attack). The sound files (LaserShoot1.wav and LaserShoot2.wav are actually two copies of the same file!

Your challenge is to:

  1. Look online and see if you can find a sound file that you like better for each of the ships (the Monarch and the Nocturn). Download the files.
  2. If the files are both WAV files, then rename your new sound files to "LaserShoot1.wav" (for Player 1's attack sound) and "LaserShoot2.wav" (for Player 2's attack sound).
  3. Add the new sound files to the Level4/Challenges/Challenge2/Assets folder (on your computer) and save over the other files. (You can find the original files on GitHub still, if you want them back.)
  4. Then, run the game and listen to your new sounds!

Or, if they aren't WAV files (or if you don't want to save over them), then:

  1. Save the audio files in the Assets folder, using whatever file name you want.
  2. Then update the name of the files in your code.
    • Update the name of the Player 1 sound file on Line 25. Replace LaserShoot1.wav with the name of your sound file.
    • Update the name of the Player 2 sound file on Line 29. Replace LaserShoot2.wav with the name of your sound file.
    • Make sure the code still includes the quotes and parentheses as part of the argument in the function.
  3. Then run the code and listen to your new sounds!

Next Steps

More Level 4 Resources

In addition to this page, we also have Level 4 Help (for the main game, in the book), Online Articles, a Learning Quiz, an Unplugged Activity, and a Rewards article:

  • Level 4: Help - This page helps you complete the instructions in the book, in case you get stuck.

  • Level 4: Online Articles - I made you a list of different web pages I found, which will help you learn more about creating Turtle Graphics.

  • Level 4: Learning Quiz - I wrote some questions in case you want to quiz yourself about what you learned. Or you can teach others and quiz them!

  • Level 4: Unplugged Activity - I wrote this page with more details than what you saw in the book. In this game!

  • Level 4: Rewards - If you completed the Space Wars project that we talked about in the car, then I set up this page to act as a reward. You can see some illustrations of me and learn more about who I am! You'll also find the Space Wars Award digital download, to show off your accomplishment!

Level 5

After you're completely done with Level 4 (did you do Challenge 1?), then it's time to move on to Level 5! While you read through Level 5 in your book, you can check out the resources from WHO?, as he teaches you how to build the Creeper Chase program:

You better be amazing by now at making a Space Wars game! I do have a reputation to uphold.

-- SideWinder