TRY THE FINAL PRODUCT HERE: https://replit.com/@ChrisChen42/Story-of-Star-Boy?v=1
Use of global and local variables
On lines 26-27, there are two global variables which are lists containing the ending HPs and fuels after each level. These global variables are then used in the "levelGenerator()" function to add new ending fuels and HPs to the lists after the user wins a level.
Another example of global variables is the font variables. They are declared as shown and can be easily accessed and used to render text.
As you can see, under the comment "Initialize local variables," there are seven local variables for the function "cut_scene1()". They are only used within the function.
"frameRate" controls how many frames should be played per second, preventing overload and lag.
"starBoySize" controls the initial size of Star Boy, and "starBoySizeMax" will control how big he will grow during the animation.
"starBoyInitialY" is where Star Boy starts in the animation, and "starBoyY" is Star Boy's current position, initially set to "starBoyInitialY."
"starBoy_rect" is declared to store the box that outlines Star Boy, allowing control of its size and coordinates.
"starBoy_image" stores the rendered image of Star Boy.
Use of String method
In the "createCaption()" function, a caption is created either at the top or bottom of the screen. However, if there is a paragraph of text, Pygame doesn't have a text wrap feature, so I have to implement my own to prevent the text from going off the screen. Part of this process involves using the ".split()" string method to split every word in the paragraph or provided text. This allows me to check if the words go off the screen, and if they do, they will be placed on the next line.
Use of arithmetic operators
Arithmetic operators are used extensively to calculate the positions of elements in this graphic-intensive game. For example, we need to display starting captions on the starting page. As you can see below on lines 162-163, we are using the "WIDTH" and "HEIGHT" global variables (representing the dimensions of the window) along with the properties of each method to access the width and height. By subtracting the element's dimensions from the window dimensions and performing floor division by 2, we can position the text in the middle of the screen. The second message, being a subtitle, needs to be displayed under the title. Therefore, we add the height of the title to the y-position to display it directly beneath the title.
Use of ELIF decision statement
Here, we are using elif statements because we need to handle the different scenarios where Star Boy either wins or loses the level. The first if statement checks if Star Boy has run out of fuel or if his health is 0 or below. Then, we use an elif statement to handle if Star Boy reaches the altitude goal and wins the level. Finally, the last elif statement checks if the enemy's health is below 0, indicating that Star Boy has completed all the levels, with a separate handler for this scenario. *Note that there is no else statement here because this code is within a loop, and we are only checking for these specific events.
Use of AND/OR operator
An "or operator" is used here to check if the space monkey has touched either side of the screen, which means we have to reverse the direction he is going.
Here, there are several "and operators" used because there are multiple conditions to check before the user is allowed to launch a light pulse. First, the level has to be 3. Then, the event must be a "KEYDOWN" event. Additionally, the event key must be "K_SPACE" (indicating the user pressed the space bar). Finally, there has to be at least one light pulse in storage to launch.
Use of NOT logical operator
The "not operator" is used in this while loop for the function "continuationHandler()". A variable "endLoop" controls when the loop ends. The condition is set so that if "endLoop" is not true, meaning the loop has not ended, it continues looping. When "endLoop" becomes true, it means to end the loop.
Use of nested-if
Here we have an example of several nested if statements. The nesting for this example starts on line 485 where it checks if the energy box collided with Star Boy. Nested within this if statement, another if statement checks if the fuel is less than the max fuel because we don't want to add more fuel if it's already full. Finally, another nested if statement inside the previous nested if checks if adding more fuel would exceed the storage limit. If it doesn't exceed the limit, it adds the fuel amount; otherwise, it sets the fuel to the max limit to prevent overflow.
Use of For Loop
A for loop is used in the "createCaption()" function. As explained before, I had to create my own text wrap. Up to this point of the function, the lines are already calculated and stored in the list variable "lines". The for loop iterates through the list, renders each line of text, positions it, and then increases the current working y position for the next line.
Use of While Loop
The levels are contained within a while loop because the program continuously needs to handle user input and manage ongoing animations in the background. This while loop is governed by the "running" variable, which is set to true while the level is active and false when the level concludes.
Use of Arrays/Lists
This is actually an example of the use of a 2D array or list. There is a list of captions per scene, and within each caption, there is a list of configurations. These configurations will be used by the "createCaption()" function, as you will see on the right.
Use of Arrays/Lists with a loop
This for loop iterates through all the scenes and sets each scene's background by retrieving the corresponding image from the "scenesPictures" list. Using the "scenesText" list, captions for the scenes are fetched along with their configurations, which are then passed as parameters to the function "createCaption()". The "continuationHandler()" function waits for the user to press any key before proceeding to the next scene.
Use of a Function with NO parameters
The "start()" function is used to display the starting cover of the game. It sets the background with the starting image using the "setBackground()" function, and it positions the title and subtitle in the center of the screen. There is no need to return anything because it is purely action-oriented.
Use of a Function with parameters
The "createCaption()" function requires parameters for text, captionHeight, bgColor (background color), textColor, and the position of the
Use of a Function with return
The "calculateTotalScore()" function utilizes the global variables "ending_hps" and "ending_fuels" to compute the final score achieved by the user. The program iterates through all the HPs and fuels, multiplies each by a multiplier corresponding to its score value, and accumulates these values to calculate the final total score.
Event Handling with (keyboard and/or mouse)
On lines 76-82, we have an event handler for handling the user clicking a box in the "createClickBox()" function. Within a while loop, events are iterated through, and if an event of type "MOUSEBUTTONDOWN" occurs, it indicates that the user clicked somewhere on the screen. In that case, we set the position where the mouse clicked. Using this position variable with the ".collidepoint()" method from the "box_rect" object, we check if the user clicked inside the box. If so, we exit the loop and continue with the program.
Display a graphic
Since there are many different scenes in an RPG game, constantly setting the background can be tedious and requires several steps. This leads to repetitive and unnecessarily lengthy code. Therefore, the "setBackground()" function is created to streamline this process. Initially, it retrieves the global variable "background" and loads an image located in the "images" folder using the parameter "imageName". The background variable is global because it may be reused consecutively, and resetting it with "screen.blit(background, (0, 0))" helps reduce flashing during animations. After loading the image, the function scales it to fit the screen using the dimensions stored in "WIDTH" and "HEIGHT". Finally, the background is displayed on the screen using "screen.blit()" at coordinates (0, 0), and the display is updated with "pygame.display.update()".
Animate/move a graphic
Here is a simple movement for Star Boy: he grows larger in perspective and then flies up and out of Earth. A while loop iterates through frames to increase Star Boy's size until he reaches the maximum size specified in the "starBoySizeMax" variable. Using "pygame.transform.scale()", Star Boy's image is scaled to the new size in each frame. Additionally, Star Boy's y position is incremented in each iteration to animate his ascent away from Earth and into outer space. The updated coordinates are set using "scaled_starBoy_image.get_rect()". Finally, Star Boy is rendered on the screen using "screen.blit()", and "pygame.display.flip()" updates the screen, allowing the user to see Star Boy's movement.
Collision detection
Collision detection is used here between the energy box and Star Boy. When a collision occurs, the energy box is removed from the list, and its fuel is added to Star Boy.
Collision detection is also used here for when Star Boy touches an explosive banana. Upon collision, the banana is replaced with a quick explosion image (visible if there is no lag), and HP is deducted from Star Boy.