Level 6: Challenge 1 - IncrediCoders/Python1 GitHub Wiki
Queen Cobra added this page on June 6, 2025
Let's begin your first challenge for Level 6!
You're going to add in sound files to the game, so that you can hear when Paul and the Cryptic Creeper attack!
To find the Level 6 Challenge 1 code template, open the Level 6 folder, the Challenges folder, and then the Challenge 1 folder. You should already have the files downloaded onto your computer (see Load the IncrediCoders Files). Open the BossBattle_Challenge1.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:
On Line 2, from init import * initializes the program by running 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. This statement allows you to use all the information in that file, for the rest of your program.
On Line 4, def update(delta_time) updates each time a key is pressed or a mouse button is clicked (these are called events). Although the game is only played with the keyboard, we also check for mouse clicks to start the game, to play the game again (after it ends), and to close the window. This function will continuously check for these events while the game is running.
The comment on Line 5 says, # Check if Paul collides with the walls. Lines 6-13 check whether or not the Paul Python sprite collides with the four walls. They make sure the Paul sprite doesn't appear inside of the walls.
On Line 6, if MY.player.location.x < MY.wall_height: checks to see if the current location of the player sprite is less than the maximum height from the dimensions of the wall. This code makes sure that the character is rendered to the right side of the left wall.
On Line 7, MY.player.location.x = MY.wall_height is run if the if statement on Line 6 is true, and it sets the player's location to the maximum height set by the dimensions of the wall.
On Line 8, if MY.player.location.x > WINDOW_WIDTH - MY.wall_height: checks to see if the current location of the player sprite is greater than the width of the window, subtracted by the maximum height from the dimensions of the wall. This code makes sure that the character is rendered to the left side of the right wall.
On Line 9, MY.player.location.x = WINDOW_WIDTH - MY.wall_height is run if the if statement on Line 8 is true, and it sets the player's location to the location that is the width of the window, subtracted by the height of the wall.
On Line 10, if MY.player.location.y < MY.wall_height: checks to see if the current location of the player sprite is less than the maximum height from the dimensions of the wall. This code makes sure that the character is rendered below the top wall.
On Line 11, MY.player.location.y = MY.wall_height is run if the if statement on Line 10 is true, and it sets the player's location to the maximum height set by the dimensions of the wall.
On Line 12, if MY.player.location.y > WINDOW_LENGTH - (MY.wall_height + 15): checks to see if the current location of the player sprite is greater than the length of the window, subtracted by the height of the wall plus 15. This code makes sure that the character is rendered above the bottom wall.
On Line 13, MY.player.location.y = WINDOW_LENGTH - (MY.wall_height + 15) is run if the if statement on Line 12 is true, and it sets the player's location to the length of the window, subtracted by the height of the wall plus 15.
On Line 15, the handle_pillar_collision() function runs when Paul collides with a pillar. There's code in this function that checks to see the location of Paul's sprite.
The comment on Line 17, # Paul loses health if he collides with the Creeper, explains that Lines 18-21 decrement Paul's health if he runs into the Creeper. In other words, it removes one of Paul's health points.
On Line 18, if MY.player.collides_with_boss(): checks to see if Paul has collided with the Creeper, which is the boss. In this code block (Lines 18-21), if Paul does collide with the Creeper, then Paul's pain animation plays, he loses one health, and his hitbox isn't active for a short time (to give the player a chance to run away).
On Line 19, the player_pain_anim() function runs, if the statement is true on Line 18 (if Paul runs into the Creeper). This function displays Paul's pain animation.
On Line 20, MY.player_health -= 1 subtracts one health from the player's current health, so the player's health goes down one hit point from its current value. For example, if Paul had 5 hit points and ran into the Creeper, then he would lose one hit point and would now have 4 hit points.
On Line 21, MY.player_hitbox.active = False allows the player time to recover and move away from the boss by removing the active hitbox for a few seconds.
Next, you should see the comment on Line 23, #TODO: Write code here to play a sound when Paul gets hit.
NEW CODE: On Lines 24-27, you're going to write your own code that plays a sound when Paul gets hit by the Creeper or the Creeper's projectiles. See the next section, "Write Your Own Code", for guidance.
The comment on Line 29, # Add Paul's hitbox depending on his direction, explains what Lines 30-41 do.
On Line 30, if MY.player_dir == UP: checks to see if the direction that the player is facing up. This code block (Lines 30-32) places Paul's hit box above him, when he's facing up.
On Lines 31-32, MY.player_hitbox.location = pygame.math.Vector2(MY.player.location.x + 20, MY.player.location.y - 20) sets the hit box above Paul, since he's facing up (Line 30). We put this code on two lines because it's a long code statement! We want to make sure each line of code is short enough, so that we can refer to it in the book.
On Line 33, elif MY.player_dir == DOWN: checks to see if the direction that the Paul sprite is facing is down.
On Lines 34-35, MY.player_hitbox.location = pygame.math.Vector2(MY.player.location.x - 10, MY.player.location.y + 25) runs if the if statement on Line 33 is true (if Paul is facing down). It sets the hitbox below the character.
On Line 36, elif MY.player_dir == LEFT: checks to see if the direction that the Paul sprite is facing is to the left.
On Lines 37-38, MY.player_hitbox.location = pygame.math.Vector2(MY.player.location.x - 20, MY.player.location.y) checks if Line 36 is true (if Paul is facing left). It so, it sets the hitbox to the left of the Paul sprite.
On Line 39, elif MY.player_dir == RIGHT: checks to see if the direction that the Paul sprite is facing is to the right.
On Lines 40-41, MY.player_hitbox.location = pygame.math.Vector2(MY.player.location.x + 20, MY.player.location.y) runs if Line 39 is true (if Paul is facing right). It sets the hitbox to the right of the Paul Python sprite.
The comment on Line 43, # Reduce Creeper's health when he gets attacked, explains what happens on Lines 44-50.
On Line 44, if MY.player_hitbox.active and MY.boss.collides_with_hitbox(): checks to see if the player attacks the Creeper (the boss).
NEW CODE: On Lines 46-48, you're going to write your own code that plays a sound when Paul attacks the Creeper. See the next section, "Write Your Own Code", for guidance.
On Line 49, MY.boss_health -= 1 runs, after the sound is played that you wrote the code for. The Creeper's health is reduced by one hit point.
On Line 50, MY.player_hitbox.active = False gives the boss time to recover. This prevents the player from hitting the Creeper repeatedly and rapidly, to do a lot of damage at once. That would make the game too easy!
On Line 52, player_attack_update() makes sure we run all of the attack animations for both the player and the Creeper.
On Line 54, update_assets(delta_time) updates all the animations and other information about the level, according to the delta_time variable. This keeps all the animations on the level in sync.
On Line 56, the check_win() function runs. It checks to see if the player has won (if the Creeper ran out of health points) and updates the game state to display the Win or Lose animated overlay. The Win or Lose text animates over the screen.
Line 58 shows the comment, #TODO: Write code here to play a sound when Paul wins or loses.
NEW CODE: On Lines 59-64, you're going to write your own code that plays a sound when Paul wins or loses. See the next section, "Write Your Own Code", for guidance.
On Line 66, check_events() goes through each of the separate coding events, and it runs each event when it comes up in the game.
The comment on Line 68, # Register the game states, explains Lines 69-72.
Lines 69-72 register the game states.
- On Line 69,
Manager.register(sys.modules[__name__])registers the current file. - On Line 70,
Manager.register(GameOver)registers the Game Over screen (at the end of the game). - On Line 71,
Manager.register(PlayAgain), registers the Play Again option. - On Line 72,
Manager.register(Intro), registers the Intro screen. This is the screen that starts the game. It shows the game title and graphic, it tells you how to play the game, and it provides the player a chance to rest and play the game when they're ready.
The comment on Line 74, # Run the game, explains Line 75.
On Line 75, Manager.run(SCREEN, WINDOW, BLACK, "CHALLENGE1") runs the game and opens a new window for the game.
Head back to Line 23, where you'll see the code comment, #TODO: Write code here to play a sound when Paul gets hit.
On Lines 24-27, you're going to write the code that plays a sound when Paul gets hit:
-
On Line 24:
-
Type in
ifto start a statement that checks if Paul has collided with one of Creeper's projectiles. -
Add a space, and then type in the
MY.player.collides_with_projectile()function. - Add a colon at the end of the statement.
-
Type in
-
On Line 25, you're going to load Paul's sound file. If the statement from Line 24 is true, then when Paul gets hit by one of Creeper's projectiles, the
mixerfunction loads the sound file. Follow these instructions:- Make sure you indent this line to the right of Line 24.
-
Type in the
mixer.music.load()function. - In the parentheses, type in the
get_file("Assets/PaulHit.wav")function as the parameter. This points to the "PaulHit.wav" file. - Be sure to include both sets of parentheses.
-
On Line 26, you use the mixer module to play the sound that you just loaded, for Paul getting hit. (In the init.py file, we imported the
mixermodule frompygame.) Follow these instructions:- Make sure you're at the same indentation level as Line 25.
-
Type
mixer, a period,music, another period,play, and end with the double parentheses (since it's a function). You don't have a parameter to include in the parentheses (so they are empty). - The final code is
mixer.music.play()on Line 26.
-
On Line 27, the last step is to set the
MY.player_hitbox.activevariable toFalse. This will turn off Paul's hit box temporarily, so that he doesn't rapidly lose a lot of health. Follow these instructions:- You should be at the same indentation level as on Lines 25-26.
- Type in the MY.player_hitbox.active variable. This variable determines whether the hitbox is active, which means it set whether or not a projectile (or the Creeper) can hurt Paul during this time.
- Add a space, an equal sign, and another space.
-
Type in the
FalseBoolean.
Next, you should see the code comment on Line 45, #TODO: Write code here to play a sound when Creeper is attacked.
On Lines 46-48, you are going to write the code that plays a sound when the Creeper is attacked:
-
On Line 46, you are already inside an
ifblock. The initialifstatement (on Line 44) checks if the Creeper was attacked. On this line (Line 46), you'll load another sound file using the mixer module. Follow these instructions:-
Indent four spaces to the right (from the
ifstatement on Line 44; this should be at the same indentation level as the comment on Line 45). -
Type in the
mixer.music.load()function, like you did on Line 25. - Inside the parentheses,
type intheget_file("Assets/BossHit.wav")function as the parameter. - Be sure to include quotation marks around the file name, inside the parentheses, as well as both sets of parentheses.
-
Indent four spaces to the right (from the
-
On Line 47, you'll set the volume. In this case,
0.4works well. We use the mixer module once again to set the volume of this sound file:- At the same indentation level, type in the
mixer.music.set_volume()function. - Inside the parentheses, enter
0.4as the parameter, to set the volume of our BossHit.wav file.
- At the same indentation level, type in the
-
On Line 48, you're going use the mixer module to play the loaded sound file:
- You should be at the same indentation level as Lines 45-47.
- Enter the same code that you used on Line 26.
We're ready to fill in our final section! Find the code comment on Line 58, #TODO: Write code here to play a sound when Paul wins or loses.
On Lines 59-64, you're going to write the code to play a sound when Paul wins and a different sound when Paul loses:
-
On Line 59, we start by checking to see if the boss health is less than or equal to zero:
-
Type
ifon the line. - In this case, we're going to include the conditional statement in parentheses. This is another way to write an
ifstatement. Type in the two parentheses right after theifkeyword. - Inside the parentheses, type in the
MY.boss_healthvariable. - After the variable, add a space, then type in the "less than or equal to" operator, which looks like
<=in the code. -
Type in another space, and type in
0while you're still inside the parentheses. As mentioned, this will check if Creeper's health is less than or equal to zero, which means the Creeper lost the battle. -
Add a colon at the end of Line 59, because you're starting your
ifblock (Lines 59-61). - The final code on Line 59 is
if(MY.boss_health <= 0):
-
Type
-
On Line 60, if the above statement on Line 59 is true (Creeper lost all his life), then you will now load the sound file that plays the winning music for Paul:
- Indent four spaces to the right of Line 59.
- Copy in the same line of code as what you wrote on Line 46.
-
Replace the previous sound file with the
Assets/Win.wavfile name. - Be sure to include the file name in quotation marks, inside the parentheses. Also, be sure to include both sets of parentheses.
-
On Line 61, using the same mixer module, you'll play the sound for the file you loaded on Line 60:
- Make sure you're indented at the same level as Line 60.
- Enter the same line of code that you wrote on Line 48.
-
On Line 62, you'll write the code to determine what happens if Paul loses (if he runs out of health). You'll use an
elifstatement to check if the player's health is less than or equal to zero:- This line of code is similar to Line 59.
-
Type in
elifto start the line. - Add parentheses.
- Inside the
elif()parentheses, type in theMY.player_healthvariable. - After the variable, add a space, and then type in the "less than or equal to" operator:
<= -
Add another space, then type in
0as the value you check. - After the parentheses, add a colon.
-
On Line 63, if the statement on Line 62 is true (if Paul ran out of health), then the
mixer.musiclibrary loads the sound file for when Paul loses:- Make sure you're indented at the same level as Lines 60-61. You should be indented to the right of Line 62.
-
Type in the
mixer.music.load()function. - Inside the parentheses, type in
get_file("Assets/Lose.wav")(including the quotation marks and parentheses). This will load the Lose.wav file to play the music for Paul losing.
-
On Line 64, at the same indentation level as Line 63, type in
mixer.music.play()function. This is the same line of code as Line 61. You don't need to add anything into the parentheses. This will play the Lose.wav file.
That's it! Run the code and see if it works!
I included a solution file for Level 6: Boss Battle Challenge 1. This file has all the code filled in, so if you run into any issues with your code (for example, it doesn't compile/run, or 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!
Next, you can take on the other challenge to battle the Creeper and learn more! When you're done, you can move on to Level 7, IncrediCards!
Challenge 2: In this challenge, you are going to add in another plasma ball projectile for the Cryptic Creeper to attack with.
In addition to this Online Articles page and the instructions for our Level 6 challenges, we also have a Help Page, a Learning Quiz, an Unplugged Activity, and a Rewards article:
-
Level 6: Help - This page helps you complete the instructions in the book, in case you get stuck.
-
Level 6: 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 6: Unplugged Activity - I wrote this page with more details than what you saw in the book. In this game,
-
Level 6: Rewards - If you completed the Boss Battle program that we talked about, 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 Mech Award digital download, to show off your accomplishment!
After you're completely done with Level 6 (did you do the challenges?), then it's time to move on to Level 7! While you read through Level 7 in your book, you can check out the resources from Grafika & Syntax, as they teach you how to build the IncrediCards program:
I hope you had fun learning about the Boss Battle!
--Queen Cobra