import pygame, math, random import sys import pygame.freetype import pygame.font # Initialize pygame pygame.init() # Clock for controlling FPS clock = pygame.time.Clock() FPS = 60 # Screen Variables SCREEN_WIDTH = 1920 SCREEN_HEIGHT = 1080 # Define colors WHITE = (255, 255, 255) GRAY = (150, 150, 150) # Screen initialization + Title screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('Blobby') # SCORE SCORE = 0 #Laser init laser_spawn_interval = 2000 # Initial spawn interval in milliseconds laser_speed = 5 # Initial speed HIGHSCORE = 0 SCORE = 0 wordfont = pygame.font.SysFont("sans", 40) # Load sounds button_press = pygame.mixer.Sound("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/assets/sounds/button_press.mp3") def title_screen(): # Music for menu pygame.mixer.music.load('W:/12/liam.henderson/Programming/91896 - Assignment/blobby/assets/sounds/music/Stream Loops 2023-11-29.ogg') pygame.mixer.music.play(-1) # Load images pine1_img = pygame.image.load('W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/background/pine1.png').convert_alpha() pine2_img = pygame.image.load('W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/background/pine2.png').convert_alpha() mountain_img = pygame.image.load('W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/background/mountain.png').convert_alpha() sky_img = pygame.image.load('W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/background/sky_cloud.png').convert_alpha() sky_img2 = pygame.image.load('W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/background/sky_cloud.png').convert_alpha() sky_img2 = pygame.transform.flip(sky_img2, False, True) # Scrolling background variables scroll_left = False scroll_right = False scroll = 0 scroll_speed = 1 # Function - draw background def draw_bg(): width = sky_img.get_width() for x in range(100): screen.blit(sky_img2, ((x * width) - scroll / 5, -180)) screen.blit(sky_img, ((x * width) - scroll / 5, 240)) screen.blit(mountain_img, ((x * width) - scroll / 4, SCREEN_HEIGHT - mountain_img.get_height() - 300)) screen.blit(pine1_img, ((x * width) - scroll / 3, SCREEN_HEIGHT - pine1_img.get_height() - 150)) screen.blit(pine2_img, ((x * width) - scroll / 2, SCREEN_HEIGHT - pine2_img.get_height())) # The exit button class ExitButton(pygame.sprite.Sprite): def __init__(self, image): super().__init__() # Load the image and scale it up by 50 pixels original_image = pygame.image.load(image).convert_alpha() scaled_image = pygame.transform.scale(original_image, (original_image.get_width() + 100, original_image.get_height() + 40)) self.original_image = scaled_image self.image = self.original_image.copy() self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2) + 300)) # Set center of the rect self.base_rect = self.rect.copy() # Store the original rect self.original_center = self.rect.center def update(self): # Check if mouse is hovering over the button if self.rect.collidepoint(pygame.mouse.get_pos()): # Scale the image self.image = pygame.transform.scale(self.original_image, (self.base_rect.width + 10, self.base_rect.height + 7.5)) # Update the rect position self.rect = self.image.get_rect(center=self.base_rect.center) else: self.image = self.original_image self.rect = self.image.get_rect(center=self.original_center) # The play button class PlayButton(pygame.sprite.Sprite): def __init__(self, image): super().__init__() # Load the image and scale it up by 50 pixels original_image = pygame.image.load(image).convert_alpha() scaled_image = pygame.transform.scale(original_image, (original_image.get_width() + 200, original_image.get_height() + 80)) self.original_image = scaled_image self.image = self.original_image.copy() self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2))) # Set center of the rect self.base_rect = self.rect.copy() # Store the original rect self.original_center = self.rect.center def update(self): # Check if mouse is hovering over the button if self.rect.collidepoint(pygame.mouse.get_pos()): # Scale the image self.image = pygame.transform.scale(self.original_image, (self.base_rect.width + 20, self.base_rect.height + 15)) # Update the rect position self.rect = self.image.get_rect(center=self.base_rect.center) else: self.image = self.original_image self.rect = self.image.get_rect(center=self.original_center) # Create a sprite group for buttons button_group = pygame.sprite.Group() # Create buttons exit_button = ExitButton("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/exit.png") button_group.add(exit_button) play_button = PlayButton("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/play.png") button_group.add(play_button) # Game loop running = True while running: # Limit frame rate clock.tick(FPS) # Handle events for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.MOUSEBUTTONDOWN: if exit_button.rect.collidepoint(pygame.mouse.get_pos()): pygame.mixer.Sound.play(button_press) running = False pygame.quit() sys.exit() if play_button.rect.collidepoint(pygame.mouse.get_pos()): running = False pygame.mixer.Sound.play(button_press) # Update sprites button_group.update() # Draw everything screen.fill(WHITE) # Background draw_bg() # Scroll map if scroll_left and scroll > 0: scroll -= scroll_speed * 5 if scroll_right: scroll += scroll_speed * 5 button_group.draw(screen) # Update display scroll_right = True scroll_speed = 1 pygame.display.flip() # The entire game def stage_1(): # Load music and play pygame.mixer.music.load("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/assets/sounds/music/Stream Loops 2024-02-14_L01.ogg") pygame.mixer.music.play(-1) # Level background class class Level1(pygame.sprite.Sprite): def __init__(self, image): super().__init__() original_image = pygame.image.load(image).convert_alpha() self.image = original_image.copy() self.rect = self.image.get_rect() self.base_rect = self.rect.copy() # The laser sprite class Laser(pygame.sprite.Sprite): def __init__(self, x, y, target_x, target_y): super().__init__() original_image = pygame.image.load("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/laser.png") self.image = original_image.copy() self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # Calculate the direction towards the player dx = target_x - x dy = target_y - y self.angle = math.atan2(dy, dx) def update(self, speed): # Move the laser in the direction of the angle self.rect.x += speed * math.cos(self.angle) self.rect.y += speed * math.sin(self.angle) # Remove the laser when it goes off-screen if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT: self.kill() # The player sprite class Player(pygame.sprite.Sprite): def __init__(self, image, x, y): super().__init__() original_image = pygame.image.load(image).convert_alpha() self.image = original_image.copy() self.rect = self.image.get_rect(center=(SCREEN_WIDTH / 2, (SCREEN_HEIGHT / 2))) self.base_rect = self.rect.copy() self.original_center = self.rect.center self.movex = 0 self.movey = 0 def update(self): self.movex = xvel self.movey = yvel self.rect.x += self.movex self.rect.y += self.movey return self.rect.x, self.rect.y # The copy of the player that scales with the player's velocity class Trail(pygame.sprite.Sprite): def __init__(self, image): super().__init__() original_image = pygame.image.load(image).convert_alpha() self.image = original_image self.rect = self.image.get_rect() self.base_rect = self.rect.copy() self.rotation = 0 self.player_center_offset = [0, 0] # Offset from player's center self.update_position(player.rect.center) # Initialize position def update_position(self, player_center): self.rect.center = (player_center[0] + self.player_center_offset[0], player_center[1] + self.player_center_offset[1]) def update(self): global trail_size player_speed = (xvel ** 2 + yvel ** 2) ** 0.5 # Calculate the total speed using Pythagorean theorem trail_size = player_speed * 4 # Adjust for trail length self.update_position(player.rect.center) if trail_size == 0: self.image = pygame.Surface((0, 0)) # Set the image to an empty surface when trail size is zero else: scaled_image = pygame.transform.scale(self.image, (int(trail_size), int(trail_size))) self.image = scaled_image.copy() if xvel == 0 and yvel == 0: self.image.set_alpha(0) # Make the sprite invisible else: self.image.set_alpha(255) # Make the sprite visible if xvel < 0: self.rotation = -90 elif xvel > 0: self.rotation = 90 elif yvel != 0: self.rotation = 180 self.image = pygame.transform.rotate(self.image, self.rotation) self.rect = self.image.get_rect(center=self.rect.center) # Set initial x and y values x = SCREEN_WIDTH / 2 y = SCREEN_HEIGHT / 2 global xvel xvel = 0 global yvel yvel = 0 left = False right = False up = False down = False # All other sprite groups player = Player("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/player.png", x, y) player_group = pygame.sprite.Group() player_group.add(player) level1 = Level1("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/level1.png") level_group = pygame.sprite.Group() trail = Trail("W:/12/liam.henderson/Programming/91896 - Assignment/blobby/images/trail.png") trail_group = pygame.sprite.Group() trail_group.add(trail) laser_group = pygame.sprite.Group() # Timer for laser spawning laser_spawn_timer = pygame.USEREVENT + 1 pygame.time.set_timer(laser_spawn_timer, 2000) # Set timer to spawn laser every 2 seconds time_alive = 0 laser_speed = 1 laser_spawn_interval = 2000 # Game loop running = True while running: # Limit frame rate clock.tick(FPS) time_alive += 1 if time_alive % 600 == 0: # Every 10 seconds laser_speed += 1 # Increase laser speed laser_spawn_interval = max(500, laser_spawn_interval - 200) # Decrease spawn interval, minimum 500ms pygame.time.set_timer(laser_spawn_timer, laser_spawn_interval) # Update timer with new interval xvel *= 0.9 yvel *= 0.9 if abs(xvel) < 0.1: xvel = 0 if abs(yvel) < 0.1: yvel = 0 if left: xvel -= 3 if right: xvel += 3 if up: yvel -= 3 if down: yvel += 3 if player.rect.x < 0: player.rect.x = 0 xvel = 0 if player.rect.x > 1830: player.rect.x = 1830 xvel = 0 if player.rect.y > 1000: player.rect.y = 1000 yvel = 0 if player.rect.y < 0: player.rect.y = 0 yvel = 0 SCORE = 0 if pygame.sprite.spritecollideany(player, laser_group): if SCORE > HIGHSCORE: HIGHSCORE = SCORE SCORE = 0 running = False return SCORE # Handle events for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: left = True if event.key == pygame.K_RIGHT: right = True if event.key == pygame.K_UP: up = True if event.key == pygame.K_DOWN: down = True if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT: left = False if event.key == pygame.K_RIGHT: right = False if event.key == pygame.K_UP: up = False if event.key == pygame.K_DOWN: down = False if event.type == laser_spawn_timer: edge = random.choice(['top', 'bottom', 'left', 'right']) if edge == 'top': laser_x = random.randint(0, SCREEN_WIDTH) laser_y = 0 elif edge == 'bottom': laser_x = random.randint(0, SCREEN_WIDTH) laser_y = SCREEN_HEIGHT elif edge == 'left': laser_x = 0 laser_y = random.randint(0, SCREEN_HEIGHT) elif edge == 'right': laser_x = SCREEN_WIDTH laser_y = random.randint(0, SCREEN_HEIGHT) laser = Laser(laser_x, laser_y, player.rect.centerx, player.rect.centery) laser_group.add(laser) # Score text SCORE += 0.05 score = wordfont.render("Score - {0}".format(round(SCORE)), 1, (0, 0, 0)) # Update sprites player_group.update() level_group.update() trail_group.update() laser_group.update(laser_speed) # Draw everything screen.fill(GRAY) screen.blit(level1.image, level1.rect) trail_group.draw(screen) player_group.draw(screen) laser_group.draw(screen) screen.blit(score, (45, 40)) # Update display pygame.display.flip() return SCORE forever = True while forever == True: title_screen() pygame.mixer.music.stop() stage_1() pygame.mixer.music.stop() # Quit pygame pygame.quit() sys.exit()