Level 5: Challenge 1 - IncrediCoders/Python1 GitHub Wiki

Intelli_Avatar_2

Intelli-Scents added this page on March 14, 2025


Let's begin your first challenge for Level 5!

You are going to write code that will add a time limit for 45 seconds for each stage of the game!

To find the Level 5 Challenge 1 code template, open the Level 5 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 CreeperChase_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:

Explaining the Code

On Line 2, from init import * initializes the program (by importing the code from the init.py file). This includes code that imports other modules. It sets variables for colors, directions, and the time limit. It creates classes and functions for pressing and holding the keyboard keys, drawing shapes on the screen, getting the image files from the Assets folder, and a lot more! It also sets up the window and game screen for the Creeper Chase game. It loads the stages and tile images. This import statement allows you to use all the init.py code in your CreeperChase_Challenge1.py file, for the rest of your program.

NEW CODE: On Line 5, you are going to write your own code to set the timer for 45 seconds. See the next section, "Write Your Own Code", for guidance.

On Line 10, def update(delta_time): updates each time a key is pressed or a button is clicked (these are called events). This function will continuously check for these events while the game is running.

In Python, the keyword def creates (or defines) a named function object, stores it in memory, defines the function's parameters, defines the function's body (the code that runs when you call it), and allows you to reuse the code anywhere in your program.

On Line 11, for event in pygame.event.get(): starts a for loop that runs for every event in the Pygame file.

On Line 12, the statement if event.type == pygame.QUIT: checks if the player has clicked the X in the corner (on Windows) to close the game window.

On Line 13, if the if statement above it is true (if the player clicks the exit button on the window), then the stop() function closes the game window.

On Line 14, elif key_down(event, " ") and (MY.grounded or MY.level_num > 3): checks three conditions. It checks if the spacebar has been pressed and if the player is on the ground (MY.grounded) or if the current level (which we're calling a stage) is 4 or higher (MY.level_num > 3). Basically, this checks if Paul has jumped or has flown (in stages 4-6).

On Line 15, MY.player.velocity.y = -700 allows Paul to use his jetpack to jump. The -700 number is the distance of the jump.

On Line 16, MY.grounded = False lets the program know that Paul is no longer on the ground. This will affect the animations and Paul's velocity later on in the code.

On Line 17, the function jetpack_up_animation() animates Paul's jetpack while he's moving through the air.

On Line 19, if key_held_down(pygame.K_LEFT): checks if the user presses the Left arrow key. Obviously, the user is doing this to move Paul to the left.

On Line 21, the code MY.player.velocity.x = max(MY.player.velocity.x - PLAYER_ACCEL, -PLAYER_MAX_SPEED) sets Paul's velocity when he is moving to the left. Paul's velocity is a combination of his acceleration and max speed to determine how fast he's moving.

On Line 23, MY.player.sprite = MY.paul_run_left sets Paul's sprite to the animation that shows Paul running to the left.

On Line 25, key presses are checked again, this time to see if it the user is pressing the Right arrow. The statement elif key_held_down(pygame.K_RIGHT): is an elif statement, which means that it's the next if statement in a sequence of checking conditions. In other words, if the player is pressing the Left arrow key (Line 19), then we set Paul's velocity to the left (Line 21), and we change his animation sprite to show him running to the left. Else if (or elif) the user presses the Right arrow key, then we run Lines 26-29.

On Line 27, the code MY.player.velocity.x = max(MY.player.velocity.x - PLAYER_ACCEL, -PLAYER_MAX_SPEED) sets Paul's velocity when he is moving to the right.

On Line 29, MY.player.sprite = MY.paul_run_right is almost exactly like Line 23; this time we set Paul's sprite to show the animation of him running to the right instead.

On Line 30, we have an else: statement, which runs if the user doesn't press the Left or Right arrow keys. As you'd expect, the code on Lines 31-44 are going to slow Paul down and stop him. And then the program will play an idle animation for Paul.

On Line 31, we check if Paul is currently on the ground with the if MY.grounded: statement.

On Line 33, if MY.player.velocity.x > 0: checks if Paul is idle and facing the right while on the ground.

On Line 34, the variable MY.player.velocity.x is Paul's speed when he is moving to the right. It is set to max(0, MY.player.velocity.x - PLAYER_DECEL) to stop Paul from moving.

On Line 35, MY.player.sprite = MY.paul_idle_right sets Paul's sprite to the right-facing idle animation.

On Line 36, which is similar to Line 33 but with a < rather than a >, we check if Paul is idle and facing the left: elif MY.player.velocity.x < 0:

One Line 37, we set the velocity of Paul to be idle in a similar way as we did on Line 34, but with some key changes. The variable MY.player.velocity.x is the same, but this time it's set equal to min(0, MY.player.velocity.x + PLAYER_DECEL) instead. The key differences between this line and Line 34 is min rather than max is used, and PLAYER_DECEL is added rather that subtracted. These changes are for stopping Paul as he moves to the left (rather than to the right, like on Line 34).

On Line 38, Paul's MY.player.sprite variable is set to face the left and include an idle animation. The variable is set to be equal to the value of the MY.paul_idle_left variable.

On Line 40, this else: statement means that Paul is falling and not yet on the ground.

On Line 41, if MY.player.velocity.x > 0: checks if Paul is facing the right, like Line 33 does.

On Line 42, the code MY.player.velocity.x = max(0, MY.player.velocity.x - PLAYER_AIR_DECEL) is similar to Line 34. The only difference between the two lines is that the PLAYER_AIR_DECEL variable is used as the argument instead of PLAYER_DECEL on Line 34. As Paul falls through the air, he slows down at a slower rate than if he were touching the ground. This way the player can move Paul still while he's falling.

On Line 43, if MY.player.velocity.x < 0: checks if Paul is facing the left, like Line 36 does.

Line 44 is like Line 37, except it replaces the PLAYER_DECEL argument with PLAYER_AIR_DECEL instead. The final statement is MY.player.velocity.x = min(0, MY.player.velocity.x + PLAYER_AIR_DECEL) on Line 44.

On Line 46, the code comment, # Track and control velocity when flying, explains Lines 47-51.

On Line 47, if not MY.grounded: runs Lines 48-51, if Paul is not on the ground (this is when he is jumping or flying).

On Line 48, if MY.player.velocity.x > 0: is used to check if Paul is facing right, exactly like it is on Lines 33 and 41.

On Line 49, we display Paul's jetpack animation, where he is facing the right. MY.player.sprite = MY.paul_jetpack_right sets the new animation.

On Line 50, elif MY.player.velocity.x < 0: checks if Paul is facing the left, like Lines 36 and 43 do.

On Line 51, MY.player.sprite = MY.paul_jetpack_left sets the sprite animation for Paul's left-hand jetpack movement.

On Line 53, the code comment, # Gravity, implies that Line 54 sets the gravity for Paul.

On Line 54, MY.player.velocity.y = min(MY.player.velocity.y + GRAVITY_ACCEL, PLAYER_TERMINAL_VEL) calculates and sets the game's gravity.

On Line 57, for hazard in MY.hazards: is the first line that starts the _for_ block of code, which checks for a hazard collision. It loops through all hazards in the stage to see whether Paul has run into one of them.

Line 58 contains the code comment, # Check if the player has touched a hazard. That explains what the if statement on Line 59 does.

On Line 59, if MY.player.collides_with(hazard): checks if Paul has touched a hazard tile while moving through the stage. If so, the program runs Lines 60-65.

Line 60 contains the code comment, # Show the animation for Paul getting injured, which explains Line 61.

On Line 61, MY.player.sprite = MY.paul_pain_right displays the sprite animation that flashes, showing that Paul is hurt after he runs into the hazard tile. This is Paul's pain animation.

On Line 62, you'll see the code comment, # Reset the location to the starting point, which explains Line 63.

On Line 63, MY.player.location = MY.player_start_position moves Paul back to the entrance portal of the current stage for the player to try the stage again.

On Line 64, you'll see the code comment, # Set the speed to 0 in both directions, which explains Line 65.

On Line 65, MY.player.set_velocity(0, 0) resets Paul's velocity back to zero. So even if Paul is moving when he touches the hazard tile, then we stop him. When Paul reappears back at the beginning of the stage he drops down and is no longer moving in either direction.

The comment on Line 67, # Update Paul's location, explains Line 68.

On Line 68, MY.player.update(delta_time) updates the movement and animations of Paul. The variable delta_time is used as the parameter to keep all the updates in sync.

You should see the code comment on Line 70: # Check for wall collisions. This comment explains that Lines 71-91 are going to check each wall to see if Paul's sprite collides with it.

Line 71 sets the touching variable equal to the False Boolean. We set touching = False before we check for wall collisions. Later on, if Paul does collide with a wall, the touching variable will be set to the True Boolean instead.

Boolean

In programming, a Boolean is a data type that can only hold one of two possible values: True or False. It's a yes/no or on/off switch (also called a condition). Programs use Booleans to make decisions and control the flow of the code. We use the Boolean to say whether or not Paul is colliding with a wall. Other examples might be whether a user is logged into an application, whether a number is greater than 10, or if a player won a game.

On Line 72, the loop for wall in MY.walls: checks each wall in the current stage.

On Line 73, if a player collides with any wall, it is caught by the statement, if MY.player.collides_with(wall):

On Line 74, if MY.player.collision[DOWN]: checks to see if Paul is moving downward when he collided with the wall. If he has, Lines 75-77 will run.

On Line 75, MY.player.snap_to_object_y(wall, DOWN) is used to make Paul land on the floor.

On Line 76, MY.player.velocity.y = 0 sets Paul's vertical speed to 0 to stop him from falling further.

On Line 77, MY.grounded = touching = True sets both variables to the True Boolean, since Paul is now on the ground and touching a tile.

On Line 78, if MY.player.collision[LEFT]: checks if Paul has hit a wall on the left.

On Line 79, MY.player.snap_to_object_x(wall, LEFT) places Paul's sprite up against the wall he hit.

On Line 80, MY.player.velocity.x = 0 sets Paul's speed to 0, while he is moving horizontally. This stops him from moving through the wall.

On Line 81, touching = True updates the touching variable so that the game knows Paul has hit a wall.

On Line 82, if MY.player.collision[RIGHT]: checks if Paul has collided with a wall to our right.

On Line 83, MY.player.snap_to_object_x(wall, RIGHT) is just like Line 79, but with a different parameter. We use the RIGHT variable as our parameter instead of the LEFT variable. This function snaps Paul's sprite up against the wall when he runs into it.

On Line 84, MY.player.velocity.x = 0 sets Paul's horizontal movement speed to 0 so that he does not move through the wall that he just collided with.

On Line 85, since Paul has now touched a wall, touching = True updates the touching variable so that the game knows Paul has hit a wall.

On Line 86, if MY.player.collision[UP]: checks if Paul has hit a tile above him. If so, our program runs Lines 87-89.

On Line 87, like with the other collisions, if Paul has hit the wall above him, the function MY.player.snap_to_object_y(wall, UP) is used to snap Paul's sprite into its proper place against the ceiling.

On Line 88, MY.player.velocity.y = 0 makes sure Paul is no longer moving and doesn't go through the wall above him.

On Line 89, like when Paul collides with any other wall, touching = True lets the program know that Paul is touching a wall.

On Line 90, if not touching: checks if the touching variable is set to the False Boolean. If so, the program runs Line 91.

On Line 91, MY.grounded = False is set if he has not collided with anything, meaning he is in the air and not touching the ground.

NEW CODE: On Line 94, you will write code to make the timer count down. See the next section, "Write Your Own Code," for some guidance.

NEW CODE: On Lines 97-98, you will write code that checks if the timer has reached 0 and has run out. If so, you will display the Lose screen. See the next section, "Write Your Own Code," for some guidance.

Line 100 shows the comment, # Check for exit portal collision. Lines 101-120 make up an if block that checks if Paul touches the exit portal. If so, then it updates several aspects of the game.

On Line 101, if MY.player.collides_with(MY.exit_portal): checks if Paul has collided with the exit portal to move to the next stage, or to win the game.

On Line 102, the if statement if MY.level_num <= 2: checks if the current stage is 1 or 2. If the stage is 1 or 2, then Paul will move to the next stage, as another stage where Paul runs and jumps. It's basically checking to see if Paul completed the stage and if it's before stage 4. Once you get to stage 4, the game changes to a flying game instead. That gets checked by the elif statement on Line 110.

If Line 102 is true (you just completed stage 1 or 2), then Lines 103-109 run. Several of those lines are comments.

On Line 103, you'll see the comment, # Load and run the next level. Lines 104-107 load the next stage, for stages 2 and 3.

On Line 104, MY.level_num = MY.level_num + 1 increases the variable MY.level_num by one. It increments the value of the variable, adding one to the variable each time the if statement (on Line 102) runs.

On Line 105, level_name_as_string = 'Level' + str(MY.level_num) updates the number of the stage name as well, by writing .

On Line 106, the variable tilemap is the layout of the stage and is loaded by using the read_file() function. This function has the file location as its parameter to load and read a file. In this case the parameter is "Assets/" + level_name_as_string + ".txt".

On Line 107, the function load_level(tilemap) takes the stage information stored in the tilemap variable, passes it as a parameter into the function, and updates the game to show this new stage.

Line 108 shows the comment, # Reset timer, to tell you what Line 109 does. Developers use comments like this a lot so that other coders know what their code does.

NEW CODE: On Line 109, you will write code that resets the timer to be at 45 seconds again. See the next section, "Write Your Own Code," for some guidance.

On Line 110, elif MY.level_num >= 3 and MY.level_num < 6: checks if the stage you're entering into is greater than 3 and less than 6, which means you'd be about to start stage 4 or 5. Also, keep in mind that this whole if block (Lines 101-120) only runs if Paul touches an exit portal at the end of a stage.

On Line 111, you'll see the code comment, # Load and run the next stage. Lines 112-115 are going to do that.

On Line 112, MY.level_num = MY.level_num + 1 increments the stage number by one. This is the exact same line of code as Line 104. For example, if you just finished stage 5, then it increments the stage number up to stage 6. It uses this variable in the string name in Line 113 and then the file name on Line 114, in order to load the next stage into the game screen.

On Line 113, level_name_as_string = 'Level' + str(MY.level_num) uses the MY.level_num variable that you just updated (to the next stage), and then it passes that variable as a parameter into the str() function. That function turns the stage number value into a string so that it can concatenate the 'Level' string in with the stage number. That creates the filename that you're going to assign to a variable in Line 114.

Concatenate

In programming, concatenation is not a cat mutation serum (nice try though). It's when you essentially glue two strings together to make a new string.

On Line 113, we took the 'Level' string value and concatenated the number as a string. We glued them together. So, if you were on stage 5 and moved to stage 6 (in Line 112), then Line 113 passes the number 6 through the str() function to make it a string. The + operator does the concatenation. And then we set that new string (Level6) into the level_name_as_string variable. We use that variable on Line 114.

On Line 114, tilemap = read_file("Assets/" + level_name_as_string + ".txt") concatenates the file path as your parameter (for example, it might become Assets/Level6.txt) and passes it into the read_file() function. In other words, you're setting the path for the next stage file into the tilemap variable. This is the exact same line of code as Line 106.

On Line 115, load_level(tilemap) passes the file path into the load_level() function to get the next stage ready to go! This is the same line of code as Line 107.

Line 116 shows the comment, # Reset the timer. That's what you're going to write on Line 117.

NEW CODE: On Line 117, you will write code that resets the timer to be at 23 seconds. See the next section, "Write Your Own Code," for some guidance.

On Line 118, elif MY.level_num == 6: runs only if Paul is currently on the last stage, number 6, and has collided with the exit portal. If that's the case, then he has won the game!

Line 119 displays the code comment, # Show the Win screen. This is what Line 120 does.

On Line 120, shows the Win screen with the same function you used before on Line 98 to show the Lose screen. This time the parameter is 3, making the function change(3) instead.

Line 122 shows the comment, # Update the stage assets. That's what Line 123 does.

On Line 123, the function update_level(delta_time) updates all the animations and other information about the stage according to the delta_time variable, which keeps all the animations on the stage in sync.

Line 125 includes the comment, # Register the states. Lines 126-129 register the different states, which act like modes of the game.

On Line 126, Manager.register(Intro) registers the starting screen.

On Line 127, Manager.register(sys.modules[__name__]) registers the name of the current file and stores that in the manager module. This file runs the main game.

On Line 128, Manager.register(Lose) registers the game state when the player loses the game. This is the screen that says, "You Lose!" The player sees this screen if the time runs out on any stage. They then have to start the game over on stage 1 again.

On Line 129, Manager.register(Win) registers the game state when the player wins the game. This is the screen that says, "You Win!" The player sees this screen if they complete stage 6 without having run out of time on any of the stages.

The comment on Line 131 says, # Run the game. The code on Line 132 runs your game!

On Line 132, Manager.run(SCREEN, WINDOW, BLUE, "CHALLENGE1") runs the game, with "CHALLENGE1" as one of the parameters so that it knows which Level 5 challenge to run.

Write Your Own Code

On Line 5, you are going to make the timer last 45 seconds.

  • Write in MY.timer as the timer variable.
  • Add a space, and then type in the equal (=) operator. Add another space.
  • Write 45 to set the timer to 45 seconds. When you start the first stage, you have 45 seconds to complete the stage.

On Line 6, you're going to check if the stage is 4 or more:

  • Type in if to begin this if statement.
  • Add a space and then type in the MY.level_num variable.
  • Add another space and then type in the >= (greater than or equal to) operator.
  • Add another space and then type in 4 as our value.
  • Add a colon at the end of the line. There should be no spaces between the 4 and the : symbol.

You do this in order to change the timer to 23 seconds, starting on stage 4. This is to add a little more of a challenge to the game.

On Line 7, make sure you're indented to the right of Line 6. This line runs if Line 6 is true (if you're on stage 4 or higher). Here's what you'll write:

  • Type in the MY.timer variable.
  • Add a space, type in the = operator, and then add another space.
  • Type in the number 23 at the end of this line.

Line 7 reduces your timer down to give you more of a challenge in the second half of the game.

On Line 94, you are going to write code that makes the timer count down.

  • Type in the MY.timer variable.
  • Add a space, and then type in the -= operator. This operator is going to subtract delta_time from the timer variable and then save the results back into the MY.timer variable.
  • Add another space, and then type in the delta_time variable.

On Line 97, you will write an if statement that checks if the timer has reached 0:

  • Type in if to start the line. You should be at the same indentation level as Line 96.
  • Next, add a space, and then type in the MY.timer variable.
  • Add another space and then type in the less-than-or-equal-to (<=) operator.
  • Add another space and type in the number zero (0).
  • Add a colon at the end of the line, after the 0. This is part of the Python syntax, to add a colon at the end of all if, elif, for, and while statements. It signifies that there should be a block of code indented under (and to the right of) the statement.

On Line 98, you will write the same function that is on Line 120. Line 120 shows the Win screen, but here we will show the Lose screen instead. On Line 98:

  • Type in the change() function.
  • In the parentheses, type in the number 2 as your parameter.

On Line 109, you will write code that sets the timer to 45 seconds. Look back at Line 5 where you set the MY.timer variable equal to 45. Make sure your code is indented at the same level as Lines 103-108, and then write the same code as Line 5 on this line (Line 109).

You can either delete the code comment that's on Line 109 or write the code to the left of the code comment. Any code to the left of a comment will still run. Any comments to the right of the code should explain the line of code.

On Line 117, you will write code that sets the timer to 23 seconds. Write the same line of code as you did on Line 109. This time, change the value (to the right of the equal sign) to 23 instead. This makes the last three stages more difficult by giving you less time to complete them.

Just like on Line 109, you'll either need to replace the code comment or make sure the code is to the left of the code comment (so that it runs).

The Final Code

I included a solution file for Level 5: Creeper Chase 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 Steps

Next, you can take on the other challenge to chase the Creeper and learn more! When you're done, you can move on to Level 6, the Boss Battle!

Take the other Challenges!

Challenge 2: In this challenge, you are going to add batteries to the game. Paul collects the batteries to regain his health.

Bonus Challenge: In this extra challenge, you'll see how to make your own stages for Paul to run and jump (and fly) through! Practice your game design skills!

More Level 5 Resources

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

  • Level 5: Rewards - If you completed the Creeper Chase 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 **WHAT **Award digital download, to show off your accomplishment!

  • Level 5: Creeper Chase: All Online Articles - Return back to the main Level 5 page, with all our online resources!

Level 6

After you're completely done with Level 5 (did you do the challenges?), then it's time to move on to Level 6! While you read through Level 6 in your book, you can check out the resources from Paul Python, as he teaches you how to build the Boss Battle program:

I hope you had fun learning about the Creeper Chase!

--

⚠️ **GitHub.com Fallback** ⚠️