So, you've managed to set up a high scores feature to the game - this is rather difficult to scope if you're just starting out, so well done! You have also activated the other buttons on the menu screen so you can view and save high scores accordingly.
1. Copy and paste the code below (this is the solution to Challenge 3 and includes the high scores functionality that is now built in)
2. Extend the program to do the following:
>>Add an angel sprite to the game (you can use any image of an angel that you please!) The angel sprite drops like a bullet from the top of the screen at three random intervals and from three random positions each time. If the player ball collides with the angel sprite, the score jumps to 100 each time. Please note that you need to add the image to the same folder that your .py game is in.
import pygame import random import math import sys import os #FILE 3: High Scores #Added the following functions #updateScores: Updates the scores in memory #saveScores: Saves the highscores to an external file #readScores: Read the scores from an external file #scoreSavedScreen: Shows a confirmation screen for when scores are saved #viewScoresScreen: Shows the highscores #The menuChoice if has been expanded to include the aforementioned functions #updateScores is called when the player wins #Now the program asks for the player's name in the console before starting SCREEN_WIDTH = 400 SCREEN_HEIGHT = 300 class Ball: def __init__(self, x, y, radius, color, screen): self.x = x self.y = y self.radius = radius self.screen = screen self.color = color def draw(self): pygame.draw.circle(screen, self.color, [self.x, self.y], self.radius) class PlayerBall(Ball): def __init__(self, x, y, radius, color, screen): Ball.__init__(self, x, y, radius, color, screen) self.green_cooldown = 0 self.red_cooldown = 0 def move(self, mv_type): if mv_type == "UP": self.y -= 5 elif mv_type == "DOWN": self.y += 5 elif mv_type == "LEFT": self.x -= 5 elif mv_type == "RIGHT": self.x += 5 if self.x - self.radius < 0: self.x = self.radius elif self.x + self.radius > SCREEN_WIDTH: self.x = SCREEN_WIDTH - self.radius if self.y - self.radius < 0: self.y = self.radius elif self.y + self.radius > SCREEN_HEIGHT: self.y = SCREEN_HEIGHT - self.radius def check_contact(self, greenBall, redBall): to_return = 0 if math.sqrt((self.y - greenBall.y) ** 2 + (self.x - greenBall.x) ** 2) < self.radius + greenBall.radius: if self.green_cooldown == 0: self.green_cooldown = 10 to_return += 10 if math.sqrt((self.y - redBall.y) ** 2 + (self.x - redBall.x) ** 2) < self.radius + redBall.radius: if self.red_cooldown == 0: self.red_cooldown = 10 to_return -= 10 return to_return class GreenBall(Ball): def __init__(self, x, y, radius, color, screen): Ball.__init__(self, x, y, radius, color, screen) self.vy = random.randint(0, 4) - 2 self.vx = random.randint(0, 4) - 2 while self.vy == 0 or self.vx == 0: self.vy = random.randint(0, 4) - 2 self.vx = random.randint(0, 4) - 2 def move(self): self.x += self.vx self.y += self.vy if self.x - self.radius < 0: self.x = self.radius self.vx *= -1 elif self.x + self.radius > SCREEN_WIDTH: self.x = SCREEN_WIDTH - self.radius self.vx *= -1 if self.y - self.radius < 0: self.y = self.radius self.vy *= -1 elif self.y + self.radius > SCREEN_HEIGHT: self.y = SCREEN_HEIGHT - self.radius self.vy *= -1 class RedBall(Ball): def __init__(self, x, y, radius, color, screen): Ball.__init__(self, x, y, radius, color, screen) self.vy = random.randint(0, 6) - 3 self.vx = random.randint(0, 6) - 3 while self.vy == 0 or self.vx == 0: self.vy = random.randint(0, 6) - 3 self.vx = random.randint(0, 6) - 3 def move(self): self.x += self.vx self.y += self.vy if self.x - self.radius < 0: self.x = self.radius self.vx *= -1 elif self.x + self.radius > SCREEN_WIDTH: self.x = SCREEN_WIDTH - self.radius self.vx *= -1 if self.y - self.radius < 0: self.y = self.radius self.vy *= -1 elif self.y + self.radius > SCREEN_HEIGHT: self.y = SCREEN_HEIGHT - self.radius self.vy *= -1 def renderMenu(): f = pygame.font.SysFont("monospace", 30) title = f.render("Main Menu", 1, (0,0,0)) screen.blit(title, (SCREEN_WIDTH/4,0)) play = f.render("P - Play", 1, (0,0,0)) screen.blit(play, (0,50)) quit = f.render("Q - Quit", 1, (0,0,0)) screen.blit(quit, (0,100)) save = f.render("S - Save Scores", 1, (0,0,0)) screen.blit(save, (0,150)) view = f.render("V - View Scores", 1, (0,0,0)) screen.blit(view, (0,200)) res = 0 pressed = pygame.key.get_pressed() if pressed[pygame.K_p]: res = 1 if pressed[pygame.K_q]: res = 2 if pressed[pygame.K_s]: res = 3 if pressed[pygame.K_v]: res = 4 pygame.display.flip() clock.tick(60) return res #Function that updates the highscores in memory def updateScores(highScores, score): for i in range(len(highScores)): if(score[1] > highScores[i][1]): highScores = highScores[0:i] + [score] + highScores[i:-1] break return highScores #Function that saves the scores to a file named score.txt def saveScores(highScores): f = open("score.txt","w") for score in highScores: f.write(score[0] + " " + str(score[1]) + "\n") f.close() #Function that reads the scores from score.txt def readScores(): if os.path.isfile("score.txt"): f = open("score.txt","r") highScores = [] for line in f: l = line.split(" ") highScores.append((l[0],int(l[1]))) f.close() return highScores else: return [("Player",0),("Player",0), ("Player",0)] #Displays a score saved screen for a small amount of time def scoreSavedScreen(won): screen.fill((255, 255, 255)) text = "Scores Saved!" text2 = "" if not won: text = "You must have won" text2 = "to save scores!" f = pygame.font.SysFont("monospace", 30) title = f.render(text, 1, (0,0,0)) screen.blit(title, (0,50)) secondLine = f.render(text2,1,(0,0,0)) screen.blit(secondLine, (0,100)) pygame.display.flip() pygame.time.delay(2000) #Displays the highscores def viewScoresScreen(): screen.fill((255, 255, 255)) hScores = readScores() s1 = hScores[0][0] + ": " + str(hScores[0][1]) s2 = hScores[1][0] + ": " + str(hScores[1][1]) s3 = hScores[2][0] + ": " + str(hScores[2][1]) f = pygame.font.SysFont("monospace", 30) s1Label = f.render(s1, 1, (0,0,0)) screen.blit(s1Label, (0,50)) s2Label = f.render(s2, 1, (0,0,0)) screen.blit(s2Label, (0,100)) s3Label = f.render(s3, 1, (0,0,0)) screen.blit(s3Label, (0,150)) pygame.display.flip() pygame.time.delay(2000) #Before the game initiates, we ask the player to enter their name in the console sys.stdout.write("Please enter your name: ") name = input() pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) done = False score = 0 myfont = pygame.font.SysFont("monospace", 15) clock = pygame.time.Clock() ball1 = PlayerBall(100, 100, 20, (0, 0, 0), screen) ball2 = GreenBall(200, 200, 5, (0, 255, 0), screen) ball3 = RedBall(250, 300, 90, (255, 0, 0), screen) menuChoice = 0 timeToEnd = 20000 timeEllapsed = 0 #Variable to determine if the player won won = False #List to store the three best scores highScores = readScores() while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True screen.fill((255, 255, 255)) #Added the choices for saving and viewing scores if menuChoice != 1: menuChoice = renderMenu() if menuChoice == 1: score = 0 won = False timeEllapsed = 0 elif menuChoice == 2: done = True elif menuChoice == 3: if won: saveScores(highScores) scoreSavedScreen(won) elif menuChoice == 4: viewScoresScreen() continue if score > -100 and score < 200 and timeEllapsed < timeToEnd: pressed = pygame.key.get_pressed() if pressed[pygame.K_UP]: ball1.move("UP") if pressed[pygame.K_DOWN]: ball1.move("DOWN") if pressed[pygame.K_LEFT]: ball1.move("LEFT") if pressed[pygame.K_RIGHT]: ball1.move("RIGHT") label = myfont.render("SCORE: " + str(score), 1, (0,0,0)) timeLabel = myfont.render("TIME: " + str((timeToEnd - timeEllapsed) / 1000 + 1), 1,(0,0,0)) screen.blit(label, (10, SCREEN_HEIGHT - 20)) screen.blit(timeLabel, (300, SCREEN_HEIGHT - 20)) ball2.move() ball3.move() score += ball1.check_contact(ball2, ball3) ball2.draw() ball3.draw() ball1.draw() if ball1.green_cooldown > 0: ball1.green_cooldown -= 1 if ball1.red_cooldown > 0: ball1.red_cooldown -= 1 timeEllapsed += clock.get_time() else: finalFont = pygame.font.SysFont("monospace", 50) if score < 100: label = finalFont.render("YOU LOSE!", 1, (0,0,0)) screen.blit(label, (0,0)) else: label = finalFont.render("YOU WIN!", 1, (0,0,0)) won = True #Update the highscores if the user won highScores = updateScores(highScores,(name,score)) screen.blit(label, (0,0)) #Return to the menu after the game has ended so the player can choose to play again, save or view scores menuChoice = 0 #Display the current message (Win or Lose) and wait a while so the user can read it pygame.display.flip() clock.tick(60) pygame.time.delay(3000) continue #Update the screen pygame.display.flip() #Set the FPS value to 60 clock.tick(60) pygame.quit()