From 96c113fc059fdd334f9cf1a5c190b3b02e01bc29 Mon Sep 17 00:00:00 2001 From: Pratyush Kumar Date: Sun, 19 Nov 2023 13:29:43 +0530 Subject: [PATCH] Powerups have been added --- globals.py | 8 +++- main.py | 89 +++++++++++++++++++++++++++-------------- movinglist.py | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ notes.py | 1 + obstacles.py | 78 +----------------------------------- powerups.py | 8 ++-- 6 files changed, 182 insertions(+), 111 deletions(-) create mode 100644 movinglist.py diff --git a/globals.py b/globals.py index 3a0f9b7..bbf4f74 100644 --- a/globals.py +++ b/globals.py @@ -10,11 +10,14 @@ STAFFPOS = (175, 275, 375, 475, 575) FPS = 60 -probability = 10 +obstacle_probability = 10 +powerup_probability = 1 # FIXME: Determine the best values for these constants SPEED_LEVEL = 15 PROB_LEVEL = 30 +START_SPEED = 2 +BLANK_SPACE = 200 # Staff change sounds pygame.mixer.init() @@ -30,6 +33,7 @@ TOTAL_STAFFS = len(STAFFSOUNDS) TOTAL_NOTES = 6 +TOTAL_POWERUPS = 2 class Direction(Enum): @@ -37,4 +41,4 @@ class Direction(Enum): DOWN = 1 -obstacles_group = pygame.sprite.Group() +moving_group = pygame.sprite.Group() diff --git a/main.py b/main.py index 16f6bf1..ddfd0f5 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,8 @@ import globals import obstacles import logging +import movinglist +import powerups from pygame.locals import * from textcontent import * @@ -18,7 +20,7 @@ FramePerSec = pygame.time.Clock() # Setup player and obstacles -game_obstacles = obstacles.ObstacleList() +game_objects = movinglist.MovingList() player = notes.Player() # Setup logging @@ -42,27 +44,49 @@ def check_collision(): Check for collisions between the player and obstacles. If there is a collision, convert the player sprite to that of the obstacle. After 3 collisions, the game ends. """ hits = pygame.sprite.spritecollide( - player, globals.obstacles_group, False, collided=pygame.sprite.collide_mask + player, globals.moving_group, False, collided=pygame.sprite.collide_mask ) if hits: - logger.info("Collision detected:") - pygame.draw.rect(DISPLAYSURF, (0, 0, 0), (0, 50, globals.WIDTH, 50)) - if player.hit_count < 3: - # Increase hit count and display it - player.hit_count += 1 - logger.debug("Hit count: " + str(player.hit_count)) - - # Remove the obstacles from the list + # check if the player is colliding with an obstacle + if isinstance(hits[0], obstacles.Obstacle): + logger.info("Collision detected with obstacle.") + pygame.draw.rect(DISPLAYSURF, (0, 0, 0), (0, 50, globals.WIDTH, 50)) + if player.hit_count < 3: + # Increase hit count and display it + player.hit_count += 1 + logger.debug("Hit count: " + str(player.hit_count)) + + # Remove the obstacles from the list + for obj in hits: + game_objects.remove_object(obj) + obj.hide(DISPLAYSURF) + + # Convert the player sprite to that of the obstacle + player.convert_to_obstacle(DISPLAYSURF, hits[0]) + else: + logger.debug("Game over") + pygame.quit() + sys.exit() + + # check if the player is colliding with a powerup + elif isinstance(hits[0], powerups.Powerup): + logger.info("Collision detected with powerup.") + # Remove the powerup from the list for obj in hits: - game_obstacles.remove_obstacle(obj) - obj.hide_obstacle(DISPLAYSURF) + game_objects.remove_object(obj) + obj.hide(DISPLAYSURF) - # Convert the player sprite to that of the obstacle - player.convert_to_obstacle(DISPLAYSURF, hits[0]) - else: - logger.debug("Game over") - pygame.quit() - sys.exit() + # If powerup of type 0, increase the hit count + if hits[0].powerup_type == 0 and player.hit_count > 0: + player.hit_count -= 1 + pygame.draw.rect(DISPLAYSURF, (0, 0, 0), (0, 50, globals.WIDTH, 50)) + logger.debug("New hit count: " + str(player.hit_count)) + + # If powerup of type 1, increase the score + elif hits[0].powerup_type == 1: + player.prev_score = player.score + player.score += 10 + logger.debug("New score: " + str(player.score)) while True: # main game loop @@ -123,30 +147,37 @@ def check_collision(): score_text, score_text_rect = scores_text(player.score) DISPLAYSURF.blit(score_text, score_text_rect) - prev_score = player.score - player.score += 0.01 # Remove the score from the screen if it changes - if int(prev_score) != int(player.score): + if int(player.prev_score) != int(player.score): pygame.draw.rect(DISPLAYSURF, (0, 0, 0), (globals.WIDTH - 200, 50, 200, 50)) # Increase the speed of the obstacles every SPEED_LEVEL points - if int(prev_score / globals.SPEED_LEVEL) != int( + if int(player.prev_score / globals.SPEED_LEVEL) != int( player.score / globals.SPEED_LEVEL ): - game_obstacles.speed += 1 + game_objects.speed += 1 + globals.obstacle_probability += 1 # Increase the probability of adding an obstacle every PROB_LEVEL points - if int(prev_score / globals.PROB_LEVEL) != int( + if int(player.prev_score / globals.PROB_LEVEL) != int( player.score / globals.PROB_LEVEL ): - globals.probability += 1 + globals.obstacle_probability += 5 # Display and move the obstacles - # Starting probability of adding an obstacle is 10 / 1000 - if random.randint(0, 1000) < globals.probability: - game_obstacles.add_obstacle() - game_obstacles.move_obstacles(DISPLAYSURF) + # Starting probability of adding an obstacle is 10% + if random.randint(0, 100) < globals.obstacle_probability: + game_objects.add_obstacle() + + # Starting probability of adding a powerup is 1% + if random.randint(0, 100) < globals.powerup_probability: + game_objects.add_powerup() + + game_objects.move_objects(DISPLAYSURF) + + player.prev_score = player.score + player.score += 0.01 # Display the 5 staff lines at equal intervals in the y direction staff_lines = [ diff --git a/movinglist.py b/movinglist.py new file mode 100644 index 0000000..9baf613 --- /dev/null +++ b/movinglist.py @@ -0,0 +1,109 @@ +import random +import pygame +import sys +import notes +import globals +from obstacles import Obstacle +from powerups import Powerup + +from pygame.locals import * + + +class MovingList: + """ + Class for a list of moving objects (obstacles or powerups) + + Attributes: + obj_list : list of Obstacle/Powerup objects + rightmost_occupied_px: list of int (rightmost pixel occupied by an obstacle on each staff line) + + Methods: + add_obstacle() : adds an obstacle to the list + add_powerup() : adds a powerup to the list + remove_object(): removes an obstacle/powerup from the list + move_objects() : moves all objects in the list + """ + + RIGHT_LIMIT = globals.WIDTH - globals.BLANK_SPACE + + def __init__(self): + """ + Initialize an empty list of moving objects + """ + self.obj_list = [] + self.rightmost_occupied_px = [0, 0, 0, 0, 0] + self.speed = globals.START_SPEED + + def add_obstacle(self): + """ + Add an obstacle to the list to an empty position on the staff + """ + # Out of all unoccupied staff lines, randomly choose one. + # If any 4 or all are occupied, return False + unoccupied_cnt = self.rightmost_occupied_px.count(0) + if unoccupied_cnt == 0 or unoccupied_cnt == 1: + return False + + unoccupied = [i for i, x in enumerate(self.rightmost_occupied_px) if x == 0] + s_loc = random.choice(unoccupied) + + # randomly generate a number + n_type = random.randint(0, globals.TOTAL_NOTES - 1) + + obstacle = Obstacle(note_type=n_type, staff_loc=s_loc) + # print("Adding obstacle at staff line", s_loc) + self.obj_list.append(obstacle) + globals.moving_group.add(obstacle) + self.rightmost_occupied_px[s_loc] = obstacle.x + obstacle.rect.width / 2 + + return True + + def add_powerup(self): + """ + Add a powerup to the list to an empty position on the staff + """ + # Out of staff lines 1 and 2, randomly choose one which is not occupied. + # If both are occupied, return False + if self.rightmost_occupied_px[1] == 0 and self.rightmost_occupied_px[2] == 0: + s_loc = random.randint(1, 2) + elif self.rightmost_occupied_px[1] == 0: + s_loc = 1 + elif self.rightmost_occupied_px[2] == 0: + s_loc = 2 + else: + return False + + n_type = s_loc - 1 + powerup = Powerup(powerup_type=n_type) + # print("Adding obstacle at staff line", s_loc) + self.obj_list.append(powerup) + globals.moving_group.add(powerup) + self.rightmost_occupied_px[s_loc] = powerup.x + powerup.rect.width / 2 + + return True + + def remove_object(self, moving_object): + """ + Remove the moving object from the list + """ + self.obj_list.remove(moving_object) + globals.moving_group.remove(moving_object) + + def move_objects(self, surface): + """ + Move all objects in the list, while updating the occupied staff lines + """ + for moving_object in self.obj_list: + moving_object.move_left(surface, self.speed) + w = moving_object.rect.width + if moving_object.x + moving_object.offset_x + w / 2 < 0: + self.remove_object(moving_object) + + for i in range(0, 5): + if self.rightmost_occupied_px[i] != 0: + self.rightmost_occupied_px[i] -= 1 + if ( + self.rightmost_occupied_px[i] < self.RIGHT_LIMIT + and self.rightmost_occupied_px[i] != 0 + ): + self.rightmost_occupied_px[i] = 0 diff --git a/notes.py b/notes.py index f4439cc..0b35f14 100644 --- a/notes.py +++ b/notes.py @@ -71,6 +71,7 @@ def __init__( self.color_player() self.hit_count = 0 self.score = 0 + self.prev_score = 0 def color_player(self): colorImage = pygame.Surface(self.orig_image.get_size()).convert_alpha() diff --git a/obstacles.py b/obstacles.py index d7ea547..53c5c90 100644 --- a/obstacles.py +++ b/obstacles.py @@ -17,6 +17,7 @@ class Obstacle(notes.Note): Methods: move_left() : moves obstacles across the screen + hide() : hides the obstacle by drawing a black rectangle over it """ def __init__( @@ -64,83 +65,8 @@ def move_left(self, surface, speed=1): # draw the obstacle at its new position self.draw(surface) - def hide_obstacle(self, surface): + def hide(self, surface): """ Hide the obstacle """ pygame.draw.rect(surface, (0, 0, 0), self.rect) - - -class ObstacleList: - """ - Class for a list of obstacles - - Attributes: - obstacles : list of Obstacle objects - rightmost_occupied_px: list of int (rightmost pixel occupied by an obstacle on each staff line) - - Methods: - add_obstacle() : adds an obstacle to the list - remove_obstacle(): removes an obstacle from the list - move_obstacles() : moves all obstacles in the list - """ - - RIGHT_LIMIT = globals.WIDTH / 2 - - def __init__(self): - """ - Initialize an empty list of obstacles - """ - self.obstacles = [] - self.rightmost_occupied_px = [0, 0, 0, 0, 0] - self.speed = 1 - - def add_obstacle(self): - """ - Add an obstacle to the list to an empty position on the staff - """ - # if no staff line has righmost pixel as zero, that means all staff lines are occupied, so return False - if all(x != 0 for x in self.rightmost_occupied_px): - return False - - # randomly generate a number - n_type = random.randint(0, globals.TOTAL_NOTES - 1) - # randomly generate a staff location - while True: - s_loc = random.randint(0, globals.TOTAL_STAFFS - 1) - if self.rightmost_occupied_px[s_loc] == 0: - break - - obstacle = Obstacle(note_type=n_type, staff_loc=s_loc) - # print("Adding obstacle at staff line", s_loc) - self.obstacles.append(obstacle) - globals.obstacles_group.add(obstacle) - self.rightmost_occupied_px[s_loc] = obstacle.x + obstacle.rect.width / 2 - - return True - - def remove_obstacle(self, obstacle): - """ - Remove an obstacle from the list - """ - self.obstacles.remove(obstacle) - globals.obstacles_group.remove(obstacle) - - def move_obstacles(self, surface): - """ - Move all obstacles in the list, while updating the occupied staff lines - """ - for obstacle in self.obstacles: - obstacle.move_left(surface, self.speed) - w = obstacle.rect.width - if obstacle.x + obstacle.offset_x + w / 2 < 0: - self.remove_obstacle(obstacle) - - for i in range(0, 5): - if self.rightmost_occupied_px[i] != 0: - self.rightmost_occupied_px[i] -= 1 - if ( - self.rightmost_occupied_px[i] < self.RIGHT_LIMIT - and self.rightmost_occupied_px[i] != 0 - ): - self.rightmost_occupied_px[i] = 0 diff --git a/powerups.py b/powerups.py index dabc46a..7105213 100644 --- a/powerups.py +++ b/powerups.py @@ -22,10 +22,10 @@ class Powerup(notes.Note): Methods: color_powerup(): colors the powerup blue move_left() : moves powerups across the screen - hide_powerup() : hides the powerup by drawing a black rectangle over it + hide() : hides the powerup by drawing a black rectangle over it """ - def __init__(self, powerup_type, x=globals.WIDTH - 20, offset_x=0): + def __init__(self, powerup_type, x=globals.WIDTH - 20, offset_x=0, offset_y=0): """ Assign a powerup based upon a powerup_type argument provided. This is done so we can randomly generate powerups later on in the game @@ -38,7 +38,7 @@ def __init__(self, powerup_type, x=globals.WIDTH - 20, offset_x=0): self.staff_loc = 1 elif powerup_type == 1: image += "half-rest.png" - self.offset_y = -7 + offset_y = -7 self.staff_loc = 2 image = pygame.image.load(image) @@ -67,7 +67,7 @@ def move_left(self, surface, speed=1): # draw the powerup in its new position self.draw(surface) - def hide_powerup(self, surface): + def hide(self, surface): """ Hide the powerup by drawing a black rectangle over it """