""" *---------------------*---------------------* Project: Dodger Assesment: Te Punga - Assesment 2 School: Tauranga Boys College Author: Kayden Franz-Kwan Date: 24/6/2024 Python: 3.11.9 *---------------------*---------------------* """ #Imports import pygame import random import time import os import sys import math #Initialize Pygame pygame.init() #Set up screen infoObject = pygame.display.Info() #Gets Screen Dimensions width = infoObject.current_w height = infoObject.current_h screen = pygame.display.set_mode((infoObject.current_w, infoObject.current_h)) pygame.mouse.set_visible(False) pygame.display.set_caption("Dodger") #Define Colours BLACK = (0, 0, 0) RED = (255, 0, 0) YELLOW = (255, 255, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) WHITE = (255, 255, 255) #Score Score = 0 #Font font = pygame.font.Font('Silkscreen\Silkscreen-Regular.ttf', 32) #General Font used in most Text select = pygame.font.Font('Silkscreen\Silkscreen-Bold.ttf', 40) #Font used when the EXIT Button is selected titlefont = pygame.font.Font('Silkscreen\Silkscreen-Bold.ttf', 100) #Font used for the Title #Define Player class Player(): def __init__(self, x, y): self.x = x #X Position of the Player self.y = y #Y Position of the Player self.size = 30 #Size of the Player self.speed = 10 #Speed of the Player #Allows the Player to move Up def move_U(self): self.y -= self.speed #Allows the Player to move Right def move_R(self): self.x += self.speed ##Allows the Player to move Down def move_D(self): self.y += self.speed #Allows the Player to move Left def move_L(self): self.x -= self.speed def draw(self): #Draws the Player pygame.draw.rect(screen, BLUE, (self.x, self.y, self.size, self.size)) #Define Cube class Cube(): def __init__(self, x, y, colour): self.x = x #X Position of the Enemy self.y = y #Y Position of the Enemy self.size = 30 #Size of the Enemy speedReload = True #Allows for the Speed to be Non-Zero #Loop to ensure that the Speed of the Enemy is Non-Zero while speedReload: self.speed_x = random.randint(-10, 10) self.speed_y = random.randint(-10, 10) if self.speed_x != 0: if self.speed_y != 0: speedReload = False self.colour = colour def move(self): #Changes the x and y postion of the enemies self.x += self.speed_x self.y += self.speed_y def draw(self): #Draws the standard enemies pygame.draw.rect(screen, self.colour, (self.x, self.y, self.size, self.size)) #Define Boss class Boss(): def __init__(self, x, y): self.x = x #X Position of the Boss self.y = y #Y Position of the Boss self.size = 40 #Size of the Boss self.speed_x = 0 #Speed of the Boss in the X Direction self.speed_y = 0 #Speed of the Boss in the Y Direction self.accel_x = 0 #Acceleration of the Boss in the X Direction self.accel_y = 0 #Acceleration of the Boss in the Y Direction def move(self): #Change the x and y of the Boss self.x += self.speed_x self.y += self.speed_y def target(self, player): #Find the change in x and y from the player DeltaX = player.x - self.x DeltaY = player.y - self.y #Find the angle which the player is from the Boss direction = math.atan(DeltaY / DeltaX) #Change Xdir and Ydir based on which quadrant the player is in relative to the Boss if DeltaX >= 0: #Player is right of the Boss Xdir = 1 else: #Player is left of the Boss Xdir = -1 if DeltaY >= 0: #Player is below the Boss Ydir = 1 else: #Player is above the Boss Ydir = -1 #change acceleration so that the Boss facing the direction of the player self.accel_x = BOSS_ACCEL * abs(math.cos(direction)) * Xdir self.accel_y = BOSS_ACCEL * abs(math.sin(direction)) * Ydir def accelerate(self): #Accelerate Boss enemies self.speed_x += self.accel_x self.speed_y += self.accel_y #If speed is greater than the MAX_SPEED, speed becomes MAX_SPEED if self.speed_x > MAX_SPEED: self.speed_x = MAX_SPEED if self.speed_y > MAX_SPEED: self.speed_y = MAX_SPEED def draw(self): #Draw Boss enemies pygame.draw.rect(screen, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), (self.x, self.y, self.size, self.size)) #Create Player player = Player(width / 2, height / 2) #Create Cubes enemies = [] friends = [] #Create the Minimum Distance the Cubes can Spawn away from the Player SafeRad = player.size + 15 #Check For collision def check_collision(player, enemy): return (player.x < enemy.x + enemy.size and player.x + player.size > enemy.x and player.y < enemy.y + enemy.size and player.y + player.size > enemy.y) #Music Locations menuMusic = r"[Errortale Original] SharaX - Psychostasia (mp3).mp3" #Music that plays on the menu gameMusic = r"[Errortale Original] SharaX - Electrostatic (mp3) (1).mp3" #Music that plays while playing a level ErrorMusic = r"[Aftertale Original] SharaX - Hello World (Fatal Error) (mp3).mp3" #Music that plays while playing _ERR_OR__ screen.fill(BLACK) #Resets screen running = True #Checks if the game should be running menu = False #Checks if the difficulty menu/general menu should be open usernameSelection = True #Checks if the username selection menu should be open username = "" #Stores username DifficultyInt = 0 #Determines the difficulty selected exitButton = 0 #Checks if the exit button is selected Hscore = [0, 0, 0, 0, 0, 0] #Stores High Score Data Lscore = [0, 0, 0, 0, 0, 0] #Stores Previous score Data keyInput = True #Checks if the key is down or not spawnRate = 0 #Sets the Rate at which the Cubes Spawn at UpdateScores = True #Checks to see if scores need updating WIN = False #Determining if the Player has won #Game Loop while running: #Checks all events occouring for event in pygame.event.get(): #Exit the Game if the Window Exit Button is Clicked if event.type == pygame.QUIT: running = False #Allows for a username to be inputted if usernameSelection: #If the username menu is open if event.type == pygame.KEYDOWN: #Checks if a key is pressed if event.key == pygame.K_BACKSPACE: username = username[:-1] #Remove a Character from the Username if the Backspace Key is Pressed elif event.key == pygame.K_RETURN: #If the Enter Button is Pressed, then move from the Username Selection Menu to the General Menu usernameSelection = False keyInput = False menu = True elif event.type == pygame.TEXTINPUT: #Add the Characters Inputted to the Username username += event.text #Create Start Menu if usernameSelection: screen.fill(BLACK) #Resets screen #Music Settup if pygame.mixer.music.get_busy() == False: pygame.mixer.music.load(menuMusic) pygame.mixer.music.play(-1) #Displays the Username as it's being Inputted usernameInputText = font.render(username, True, WHITE, BLACK) usernameInputRect = usernameInputText.get_rect() usernameInputRect.center = (width / 2, height / 2) screen.blit(usernameInputText, usernameInputRect) #Displays a Prompt Asking for a Username to be Inputted usernamePromptText = titlefont.render("Please Input a Username", True, WHITE, BLACK) usernamePromptRect = usernamePromptText.get_rect() usernamePromptRect.center = (width / 2, 100) screen.blit(usernamePromptText, usernamePromptRect) #Updates the screen pygame.display.update() pygame.time.delay(33) #General Menu elif menu: #Lives Lives = 3 #Music Settup if pygame.mixer.music.get_busy() == False: pygame.mixer.music.load(menuMusic) pygame.mixer.music.play(-1) #Displays the Title title = titlefont.render('Dodger', True, WHITE, BLACK) titleRect = title.get_rect() titleRect.center = (width / 2, 60) screen.blit(title, titleRect) #Change Difficulty with arrows keys = pygame.key.get_pressed() if keys[pygame.K_RIGHT] and keyInput: DifficultyInt += 1 keyInput = False elif keys[pygame.K_LEFT] and keyInput: DifficultyInt -= 1 keyInput = False elif keys[pygame.K_DOWN] and keyInput or keys[pygame.K_UP] and keyInput: exitButton += 1 keyInput = False #Diffuculty Settings if keys[pygame.K_RETURN] and exitButton == 0 and keyInput: #Easy Difficulty if DifficultyInt == 0: MAX_SPAWN_RATE = 10 #Max Spawn Rate MAX_SPEED = 7 #Maximum Speed BOSS_ACCEL = 0.1 #Acceleration of the Bosses FRIEND_PERCENT = 10 #Percent that a Cube Spawn will be a Friend BOSS_PERCENT = 1 #Percent that a Cube Spawn will be a Boss SPAWNRATEACCEL = 2 #Rate that the Spawn Rate will Increase menu = False #Exits the menu pygame.mixer.music.stop() #Resets the Music #Medium Difficulty elif DifficultyInt == 1: MAX_SPAWN_RATE = 20 #Max Spawn Rate MAX_SPEED = 7 #Maximum Speed BOSS_ACCEL = 0.5 #Acceleration of the Bosses FRIEND_PERCENT = 10 #Percent that a Cube Spawn will be a Friend BOSS_PERCENT = 2 #Percent that a Cube Spawn will be a Boss SPAWNRATEACCEL = 2 #Rate that the Spawn Rate will Increase menu = False #Exits the menu pygame.mixer.music.stop() #Resets the Music #Hard Difficulty elif DifficultyInt == 2: MAX_SPAWN_RATE = 20 #Max Spawn Rate MAX_SPEED = 10 #Maximum Speed BOSS_ACCEL = 0.5 #Acceleration of the Bosses FRIEND_PERCENT = 10 #Percent that a Cube Spawn will be a Friend BOSS_PERCENT = 5 #Percent that a Cube Spawn will be a Boss SPAWNRATEACCEL = 2 #Rate that the Spawn Rate will Increase menu = False #Exits the menu pygame.mixer.music.stop() #Resets the Music #Insane Difficulty elif DifficultyInt == 3: MAX_SPAWN_RATE = 40 #Max Spawn Rate MAX_SPEED = 10 #Maximum Speed BOSS_ACCEL = 0.5 #Acceleration of the Bosses FRIEND_PERCENT = 10 #Percent that a Cube Spawn will be a Friend BOSS_PERCENT = 7 #Percent that a Cube Spawn will be a Boss SPAWNRATEACCEL = 3 #Rate that the Spawn Rate will Increase menu = False #Exits the menu pygame.mixer.music.stop() #Resets the Music #No Hit Difficulty elif DifficultyInt == 4: MAX_SPAWN_RATE = 40 #Max Spawn Rate MAX_SPEED = 10 #Maximum Speed BOSS_ACCEL = 0.5 #Acceleration of the Bosses FRIEND_PERCENT = 0 #Percent that a Cube Spawn will be a Friend BOSS_PERCENT = 20 #Percent that a Cube Spawn will be a Boss SPAWNRATEACCEL = 5 #Rate that the Spawn Rate will Increase Lives = 1 #Set the Amount of Lives given to One menu = False #Exits the menu pygame.mixer.music.stop() #Resets the Music #_ERR_OR__ Difficulty else: MAX_SPAWN_RATE = 50 #Max Spawn Rate MAX_SPEED = 10 #Maximum Speed BOSS_ACCEL = 0.5 #Acceleration of the Bosses FRIEND_PERCENT = 0 #Percent that a Cube Spawn will be a Friend BOSS_PERCENT = 30 #Percent that a Cube Spawn will be a Boss SPAWNRATEACCEL = 10 #Rate that the Spawn Rate will Increase Lives = 1 #Set the Amount of Lives given to One menu = False #Exits the menu pygame.mixer.music.stop() #Resets the Music #Resets key presses to avoid multiple presses being processed if event.type == pygame.KEYDOWN: keyInput = False else: keyInput = True #Read existing data from file newData = [username] + Hscore #File path for saving data save_file = "SaveData.txt" #Initialize a list to store existing save data Savelines = [] #Read existing data from file if os.path.exists(save_file): with open(save_file, "r") as reader: for line in reader.readlines(): line = line.strip() if line: Savelines.append(line) #Check if username already exists in save data found_index = -1 for index, line in enumerate(Savelines): data = line.split() if data and data[0] == username: existing_scores = list(map(int, data[1:])) update_needed = False for i in range(len(existing_scores)): #If High Score is Greater than scores in Files, change the File Score to be High Score if Hscore[i] > existing_scores[i]: existing_scores[i] = Hscore[i] update_needed = True #If File Score is Greater than High Score, Update High Score to be File Score elif existing_scores[i] > Hscore[i]: Hscore[i] = existing_scores[i] #Updates an Array to Rewrite the Save File if update_needed: Savelines[index] = ' '.join([username] + list(map(str, existing_scores))) found_index = index break #If username is not found, append newData to Savelines if found_index == -1: Savelines.append(' '.join(map(str, newData))) #Write updated Savelines back to file with open(save_file, "w") as writer: for line in Savelines: writer.write(line + '\n') #Difficulties DifficultyInt %= 6 Difficulty = ['Easy', 'Medium', 'Hard', 'Insane', 'No Hit', '_ERR_OR__'] DifficultyText = font.render(Difficulty[DifficultyInt], True, WHITE, BLACK) DifficultyRect = DifficultyText.get_rect() DifficultyRect.center = (width / 2, height / 2) screen.blit(DifficultyText, DifficultyRect) #Exit Button exitButton %= 2 exit_color = YELLOW if exitButton == 1 else WHITE #If the Exit Button is selected, chhange the Button to be Slightly bigger and Yellow if exitButton == 1: exit_text = select.render('Exit', True, exit_color) #If the Exit Button isn't selected, make it the usual Text else: exit_text = font.render('Exit', True, exit_color) exit_rect = exit_text.get_rect(bottomright=(width - 40, height - 10)) screen.blit(exit_text, exit_rect) #If the Exit Button is Pressed, Exit the Game if exitButton == 1 and keys[pygame.K_RETURN]: menu = False running = False #High Score HscoreText = font.render(Difficulty[DifficultyInt] + ': High Score: ' + str(Hscore[DifficultyInt]), True, WHITE, BLACK) HscoreRect = HscoreText.get_rect() HscoreRect.topleft = (20, 80) screen.blit(HscoreText, HscoreRect) #Last Score LscoreText = font.render(Difficulty[DifficultyInt] + ': Previous Game Score: ' + str(Lscore[DifficultyInt]), True, WHITE, BLACK) LscoreRect = LscoreText.get_rect() LscoreRect.topleft = (20, 120) screen.blit(LscoreText, LscoreRect) #Username Text usernameText = font.render("Username: " + username, True, WHITE, BLACK) usernameRect = usernameText.get_rect() usernameRect.bottomleft = (10, height - 10) screen.blit(usernameText, usernameRect) pygame.display.flip() pygame.time.delay(33) screen.fill(BLACK) else: #Win Screen if WIN: screen.fill(BLACK) keys = pygame.key.get_pressed() if keys[pygame.K_RETURN]: WIN = False pygame.mixer.music.unpause() winText = titlefont.render('Congratulations', True, WHITE, BLACK) winRect = winText.get_rect() winRect.center = (width / 2, 100) screen.blit(winText, winRect) winText2 = titlefont.render('You beat Dodger', True, WHITE, BLACK) winRect2 = winText2.get_rect() winRect2.center = (width / 2, 220) screen.blit(winText2, winRect2) #Menu button menuButton = select.render('Continue', True, YELLOW, BLACK) menuRect = menuButton.get_rect() menuRect.topright = (width - 100, height - 40) screen.blit(menuButton, menuRect) pygame.display.update() pygame.time.delay(33) else: #Play Music if DifficultyInt == 5 and pygame.mixer.music.get_busy() == False: pygame.mixer.music.load(ErrorMusic) pygame.mixer.music.play(-1) elif pygame.mixer.music.get_busy() == False: pygame.mixer.music.load(gameMusic) pygame.mixer.music.play(-1) #Create Lives Left Text LivesText = font.render('Lives Left: ' + str(Lives), True, WHITE, BLACK) LivesTextRect = LivesText.get_rect() LivesTextRect.topleft = (30, 20) #Create Score Text ScoreVis = Score / 50 ScoreText = font.render('Time: ' + str(ScoreVis), True, WHITE, BLACK) ScoreTextRect = ScoreText.get_rect() ScoreTextRect.topleft = (30, 60) #Translates Key Presses into Player Movement keys = pygame.key.get_pressed() #Moves Player Up if keys[pygame.K_UP] or keys[pygame.K_w]: player.move_U() #Moves Player Down if keys[pygame.K_DOWN] or keys[pygame.K_s]: player.move_D() #Moves Player Left if keys[pygame.K_LEFT] or keys[pygame.K_a]: player.move_L() #Moves Player Right if keys[pygame.K_RIGHT] or keys[pygame.K_d]: player.move_R() #Spawns Other Cubes Randomly if random.randint(0, 100) < spawnRate: spawn = False #Ensures the Spawning Location is beyond the Safe Radius around the Player while spawn == False: x = random.randint(0, width) y = random.randint(0, height) if player.x + SafeRad <= x or player.x - SafeRad >= x: if player.y + SafeRad <= y or player.y - SafeRad >= y: spawn = True rand = random.randint(1, 100) #Spawns Cubes if BOSS_PERCENT < rand <= FRIEND_PERCENT + BOSS_PERCENT: friends.append(Cube(x, y, GREEN)) elif rand <= BOSS_PERCENT: enemies.append(Boss(x, y)) else: enemies.append(Cube(x, y, RED)) screen.fill(BLACK) #Resets Screens for Enemies in enemies: if Enemies.__class__.__name__ == "Boss": #If the Enemy is a Boss, do functions Target, Accelerate and Animate rand = random.randint(1, 10) Enemies.target(player) #Bosses Target the Player Enemies.accelerate() #Bosses Accelerate to the Player Enemies.move() #Moves Enemies Enemies.draw() #Draw the Enemies if check_collision(player, Enemies): #Check if the Player and the Enemy is colliding Lives -= 1 #Remove a Life from the Player enemies.remove(Enemies) #Remove the Enemy for Friends in friends: Friends.move() #Move all Friends Friends.draw() #Draw all Friends if check_collision(player, Friends): #Check if the Player and the Firend are colliding Lives += 1 #Give the Player a Life friends.remove(Friends) #Delete the Friend if Lives <= 0: #If the Player has lost all Lives, reset the Game menu = True #Go back to the Menu friends.clear() #Delete all Friends enemies.clear() #Delete all Enemies #Reset Player Position player.x = width / 2 player.y = height / 2 #Change the Last and High Scores Lscore[DifficultyInt] = Score if Score > Hscore[DifficultyInt]: Hscore[DifficultyInt] = Score #Reset Score for Future Games Score = 0 #Reset Music pygame.mixer.music.stop() spawnRate = 0 time.sleep(1) #Create a looped box if player.x > width + 10: player.x = 0 if player.x < -10: player.x = width if player.y > height + 10: player.y = 0 if player.y < -10: player.y = height #Delete Enemies outside the Screen for Enemy in enemies: if Enemy.x > width + 10: enemies.remove(Enemy) elif Enemy.x < -10: enemies.remove(Enemy) elif Enemy.y > height + 10: enemies.remove(Enemy) elif Enemy.y < -10: enemies.remove(Enemy) #Delete Friends outside the Screen for Friend in friends: if Friend.x > width + 10: friends.remove(Friend) elif Friend.x < -10: friends.remove(Friend) elif Friend.y > height + 10: friends.remove(Friend) elif Friend.y < -10: friends.remove(Friend) #Draw the Player player.draw() #Increase the Spawn Rate to MAX_SPAWN_RATE if random.randint(0, 100) < SPAWNRATEACCEL: spawnRate += 1 if spawnRate > MAX_SPAWN_RATE: spawnRate = MAX_SPAWN_RATE #Add the Lives and Score Text Boxes screen.blit(LivesText, LivesTextRect) screen.blit(ScoreText, ScoreTextRect) #Update the Screen pygame.display.update() pygame.time.delay(20) #Update the Score Score += 1 #Win Condition if DifficultyInt == 5 and ScoreVis == 300: WIN = True #Pause the Music pygame.mixer.music.pause() time.sleep(1) #Stop the Code pygame.quit() sys.exit()