class AsteroidsGame: def setup(self, startWindow=None, playerName=None): self.params = GameParams() # To be filled by user input # Set up scorekeeping self.score = 0 self.scoreKeeper = ScoreKeeper() self.scoreKeeper.setFile('asteroidScore.txt') # Set up window width = 800 height = 600 font = sf.Font.from_file("rust.ttf") self.params.setFont(font) if startWindow is None: # startWindow is None unless this is a restart startWindow = sf.RenderWindow(sf.VideoMode(width, height), "Asteroids") startWindow.framerate_limit = 60 startWindow.clear(sf.Color.BLACK) #Display Welcome welcomeText = utils.drawText(startWindow, string="Asteroids", size=60, font=font, position='center') startWindow.display() # Wait for any input while (True): setup = False for event in startWindow.events: if type(event) is sf.CloseEvent: exit() elif (type(event) is sf.MouseButtonEvent or type(event) is sf.KeyEvent): setup = True if setup: break # Select Player Name if playerName is None: playerName = utils.textInput(startWindow, "Enter Name:", font, maxLength=10) self.params.setPlayerName(playerName.lower()) #Choose Difficulty difficulty = utils.selectOptions(startWindow, ["Easy", "Medium", "Hard"], [0, 1, 2], font) makeTimes = [20, 15, 12] timeModifiers = [0.98, 0.95, 0.92] self.params.setDifficulty(difficulty) self.timeToMakeAsteroid = makeTimes[difficulty] self.makeTimeModifier = timeModifiers[difficulty] self.lastAsteroidTime = time.time() - self.timeToMakeAsteroid self.timeToMakePowerup = 20 self.lastPowerupTime = time.time() - self.timeToMakePowerup self.powerupProbability = 1 / 600 # Set up Board self.board = Board(title="Asteroids", width=700, height=700) # Set up Ship self.ship = Ship(position=(self.board.getBoundary()[0] / 2, self.board.getBoundary()[1] / 2)) self.ship.setWrapping(True) self.ship.setBoundary(self.board.getBoundary()) startWindow.close() def endGame(self): gameOverText = utils.drawText(self.board.window, string="Game Over", font=self.params.font, size=60, position='center', color=sf.Color.RED) oldScore = self.scoreKeeper.checkScore(self.params.playerName, self.params.getDifficulty()) scoreTextYPosition = gameOverText.position[ 1] + gameOverText.local_bounds.height + 10 if self.score > oldScore: # display a "New Highscore" screen self.scoreKeeper.setScore(self.params.playerName, self.score, self.params.getDifficulty()) utils.drawText(self.board.window, string="New High Score! {}".format(self.score), font=self.params.font, size=30, position='center', yposition=scoreTextYPosition, color=sf.Color.GREEN) else: # Display the old highscore utils.drawText(self.board.window, string="High Score: {}".format(oldScore), font=self.params.font, size=30, position='center', yposition=scoreTextYPosition, color=sf.Color.WHITE) utils.drawText(self.board.window, string="Press ENTER to Relplay", font=self.params.font, size=15, position='center', yposition=self.board.window.height - 20, color=sf.Color.WHITE) self.board.window.display() while (True): for event in self.board.window.events: if (type(event) is sf.CloseEvent or (type(event) is sf.KeyEvent and event.code is sf.Keyboard.ESCAPE)): exit() if (type(event) is sf.KeyEvent and event.code is sf.Keyboard.RETURN): # Reset self.setup(self.board.window, self.params.getPlayerName()) self.playGame() def _generateAsteroid(self, asteroidManager, velocityLimit=2): if (time.time() - self.lastAsteroidTime >= self.timeToMakeAsteroid): self.lastAsteroidTime = time.time() self.timeToMakeAsteroid *= self.makeTimeModifier #make asteroids appear faster as time progresses # Generate beyond the border so it doesn't appear in middle of screen # random velocity will make it appear evenly on either side position = (random.uniform(-20, 0), random.uniform(-20, 0)) velocity = (random.uniform(-velocityLimit, velocityLimit), random.uniform(-velocityLimit, velocityLimit)) asteroid = Asteroid(4, position, velocity, wrapping=True, boundary=self.board.getBoundary()) asteroidManager.addObject(asteroid) def _generatePowerup(self, powerupManager, velocityLimit=2): if ((time.time() - self.lastPowerupTime >= self.timeToMakePowerup) and random.random() < self.powerupProbability): typeNum = random.randint(0, 2) typeNames = ["cooldown", "agility", "acceleration"] typeColors = [sf.Color.BLUE, sf.Color.GREEN, sf.Color.YELLOW] # Lots of calculations to make it start evenly on any side of the board # and ensure that it moves across the board no matter where it starts positionX = None positionY = None velocityX = None velocityY = None boundary = self.board.getBoundary() if random.random() < 0.5: positionX = random.uniform(-20, 0) else: positionX = random.uniform(boundary[0], boundary[0] + 20) if random.random() < 0.5: positionY = random.uniform(-20, 0) else: positionY = random.uniform(boundary[0], boundary[0] + 20) if (positionX < 0): velocityX = random.uniform(0, velocityLimit) else: velocityX = random.uniform(-velocityLimit, 0) if (positionY < 0): velocityY = random.uniform(0, velocityLimit) else: velocityY = random.uniform(-velocityLimit, 0) velocity = (velocityX, velocityY) position = (positionX, positionY) powerup = Powerup(position=position, velocity=velocity, color=typeColors[typeNum], powerupType=typeNames[typeNum]) powerupManager.addObject(powerup) self.lastPowerupTime = time.time() def playGame(self): self.board.window.clear(sf.Color.BLACK) self.ship.draw(self.board.window) self.board.displayBoard() play = False while not play: for event in self.board.window.events: if type(event) is sf.CloseEvent: exit() elif (type(event) is sf.KeyEvent): play = True bulletManager = ObjectManager(cleanSize=10) asteroidManager = ObjectManager(cleanSize=10) powerupManager = ObjectManager(cleanSize=5) while (True): self.board.window.clear(sf.Color.BLACK) self._generateAsteroid(asteroidManager) self._generatePowerup(powerupManager) # Input handler for event in self.board.window.events: if type(event) is sf.CloseEvent: exit() if type( event ) is sf.KeyEvent and event.code is sf.Keyboard.SPACE and event.pressed: bullet = self.ship.shootBullet( boundary=self.board.getBoundary()) if bullet: bulletManager.addObject(bullet) if sf.Keyboard.is_key_pressed(sf.Keyboard.RIGHT): self.ship.turnRight() if sf.Keyboard.is_key_pressed(sf.Keyboard.UP): self.ship.accelerate() if sf.Keyboard.is_key_pressed(sf.Keyboard.LEFT): self.ship.turnLeft() # Move and draw bullets for i in range(bulletManager.getLength()): bullet = bulletManager.getItem(i) bullet.move() bullet.draw(self.board.window) # Move and draw Asteroids for i in range(asteroidManager.getLength()): asteroid = asteroidManager.getItem(i) asteroid.move() asteroid.draw(self.board.window) # Move and draw Powerups for i in range(powerupManager.getLength()): powerup = powerupManager.getItem(i) powerup.move() powerup.draw(self.board.window) # Move and draw Ship self.ship.moveForward() self.ship.draw(self.board.window) # Check for collisions newAsteroids = [] for i in reversed(range(asteroidManager.getLength())): asteroid = asteroidManager.getItem(i) # Asteroid-Ship collision if (self.ship.circleTriangleCollision(asteroid.getShape())): self.endGame() for j in reversed(range(bulletManager.getLength())): bullet = bulletManager.getItem(j) # if collision: break asteroid if asteroid.didCollide(bullet): self.score += 1 if asteroid.breakAsteroid(): for newAsteroid in asteroid.breakAsteroid(): newAsteroids.append(newAsteroid) bulletManager.removeIndex(j) asteroidManager.removeIndex(i) break asteroidManager.addObjects(newAsteroids) # Check for powerup collisions for i in reversed(range(powerupManager.getLength())): powerup = powerupManager.getItem(i) if self.ship.circleTriangleCollision(powerup.getShape()): power = powerup.getType() if power == "acceleration": oldAcc = self.ship.getAcceleration() self.ship.setAcceleration(1.1 * oldAcc) elif power == "cooldown": oldCool = self.ship.getCooldown() self.ship.setCooldown(0.9 * oldCool) elif power == "agility": oldSpeed = self.ship.getRotateSpeed() self.ship.setRotateSpeed(1.1 * oldSpeed) powerupManager.removeIndex(i) self._drawScore(self.board.window) self.board.window.display() def _drawScore(self, window): if hasattr(self, 'scoreText'): self.scoreText.string = str(self.score) else: self.scoreText = utils.drawText(window, size=25, font=self.params.font, string=str(self.score)) window.draw(self.scoreText)
class Asteroids(Game): """ Asteroids extends the base class Game to provide logic for the specifics of the game """ def __init__(self, name, width, height): super().__init__(name, width, height) self.ship = Ship() self.asteroids = [] self.stars = [] self.screen = pygame.display.set_mode((self.width, self.height)) self.max_num_asteroids = 5 self.current_level = 1 self.new_level = True self.timer = 0 self.state = "startmenu" self.background_image = self.image_handle() self.buttons = [] self.highscore = Highscoreboard() self.newhighscore = False self.score = 0 self.timer_ship_alien_collide = 0 self.is_alien = False self.alien = Alien(self.ship.position.x + 300, HEIGHT - 40) self.sound = True self.testing() def testing(self): if TEST_LASTLEVEL: self.current_level = 5 self.check_max_asteroids() if TEST_HIGHSCORE: self.score = (self.highscore.get_min_score() + 10) self.ship.life = 1 self.ship.lifebar = "{}".format("♥") * self.ship.life if TEST_GAMEOVER: self.ship.life = 0 self.ship.lifebar = "{}".format("♥") * self.ship.life if TEST_VICTORY: self.current_level = 5 self.max_num_asteroids = 0 def image_handle(self): if self.state == "startmenu": return pygame.image.load("menu.jpg").convert() if self.state == "gameover": return pygame.image.load("gameover.png").convert() if self.state == "menuoption": return pygame.image.load("help.jpg").convert() if self.state == "victory": return pygame.image.load("victory.jpg").convert() else: return False def handle_input(self): super().handle_input() keys_pressed = pygame.key.get_pressed() if self.state == "playing": if keys_pressed[K_s]: self.ship.activate_shield() if keys_pressed[K_p]: self.state = "paused" if keys_pressed[K_SPACE]: if pygame.time.get_ticks() > self.timer: pygame.mixer.Channel(1).play(shoot_sound) self.timer = pygame.time.get_ticks() + 300 if len(self.ship.bullets) >= 5: self.ship.bullets.clear() self.ship.bullets.append( Bullet(self.ship.position, self.ship.rotation)) if keys_pressed[K_LEFT] and self.ship: self.ship.rotate(-0.6) if self.ship.shield_activated: self.ship.shield.rotate(-0.6) if keys_pressed[K_RIGHT] and self.ship: self.ship.rotate(0.6) if self.ship.shield_activated: self.ship.shield.rotate(0.6) if keys_pressed[K_UP] and self.ship: self.ship.accelerate(0.003) if self.ship.shield_activated: self.ship.shield.accelerate(0.003) if keys_pressed[K_DOWN] and self.ship: self.ship.accelerate(0) if self.ship.shield_activated: self.ship.shield.accelerate(0) if keys_pressed[K_r] and self.state in {"playing", "gameover"}: self.restart_game() if self.state == "paused": if keys_pressed[K_SPACE]: self.state = "playing" if keys_pressed[K_r]: pygame.mixer.music.stop() self.state = "startmenu" if keys_pressed[K_RETURN] and self.state == "menuoption": pygame.mixer.music.stop() self.state = "startmenu" if self.state == "middlescreen": if keys_pressed[K_c]: self.new_level = True self.current_level += 1 self.check_max_asteroids() self.state = "playing" def restart_game(self): self.ship.life = 5 self.ship.lifebar = "{}".format("♥") * self.ship.life self.max_num_asteroids = 5 self.score = 0 self.current_level = 1 self.new_level = True self.is_alien = False self.state = "playing" self.newhighscore = False def calc_distance(self, p, q): return math.sqrt((p.x - q.x)**2 + (p.y - q.y)**2) def collision_handle(self): transform_asteroid = False #if you shoot if len(self.ship.bullets) > 0: for bullet in self.ship.bullets: for asteroid in self.asteroids: if (self.calc_distance(bullet.position, asteroid.position) < 70 and asteroid.size == "big") or (self.calc_distance( bullet.position, asteroid.position) < 30): if asteroid.explode(): self.asteroids.remove(asteroid) self.score += 10 else: transform_asteroid = True newsize = asteroid.get_size() position = asteroid.position self.asteroids.remove(asteroid) self.score += 5 if bullet in self.ship.bullets: self.ship.bullets.remove(bullet) if transform_asteroid: self.asteroids.extend((self.CreateAsteroid(position, newsize), self.CreateAsteroid(position, newsize))) #if the ship and an astreoid collides if len(self.asteroids) > 0 and self.ship.life > 0: for asteroid in self.asteroids: if self.calc_distance( self.ship.position, asteroid.position ) < 70 and asteroid.size == "big" or self.calc_distance( self.ship.position, asteroid.position) < 30: asteroid.explode() self.asteroids.remove(asteroid) self.ship.collide() if not self.ship.shield_activated: self.ship.lifebar = self.ship.lifebar[:-1] def CreateAsteroid(self, pos, size): if pos == "random": x = random.randint(0, 600) y = random.randint(0, 430) while self.calc_distance(Point(x, y), self.ship.position) < 80: x = random.randint(0, 600) y = random.randint(0, 430) else: x = pos.x y = pos.y rotation = random.randint(0, 5) point_x = random.uniform(-0.001, 0.5) point_y = random.uniform(-0.001, 0.5) angular_velocity = random.uniform(0.1, 0.8) if size == "medium": points = MEDIUM_ASTEROID elif size == "small": points = SMALL_ASTEROID else: points = BIG_ASTEROID return Astreoid(points, x, y, rotation, Point(point_x, point_y), angular_velocity, size) def spawn_asteroids(self): sizes = ["small", "medium", "big"] if self.new_level: self.asteroids.clear() for i in range(0, self.max_num_asteroids): size = sizes[random.randint(0, 2)] self.asteroids.append(self.CreateAsteroid("random", size)) self.new_level = False def show_lifebar(self): self.ship.show_lifebar(self.screen) if self.is_alien: self.alien.show_lifebar(self.screen) def shield_bar(self): pygame.draw.rect(self.screen, (LIFEBARBLUE), (10, 50, self.ship.shield.health, 20), 0) if not self.ship.shield_activated: if pygame.time.get_ticks( ) > self.ship.shield.timer and not self.ship.shield.health == 200: self.ship.shield.timer = pygame.time.get_ticks() + 190 pygame.draw.rect(self.screen, (0, 102, 102), (10, 50, self.ship.shield.health, 20), 0) self.ship.shield.health += 5 pygame.draw.rect(self.screen, (WHITE), (8, 48, 204, 24), 1) def death_handler(self): self.highscorecheck() name = "" output = "INPUT YOUR INITIALS" if self.newhighscore == False: self.background_image = self.image_handle() self.screen.blit(self.background_image, [0, 0]) self.screen.blit(respawn, (250, 100)) else: pygame.mixer.music.stop() # while not self.highscore.right_lenght_string(name): name = self.highscore.ask_for_input(self.screen, output) # output = "MUST BE 3 LETTERS OR CHARACTERS" self.highscore.newname = name.upper() self.highscore.newscore = self.score self.highscore.update_board() self.highscore.printboard(self.screen) self.state = "menuoption" def check_max_asteroids(self): if self.current_level == 1: self.max_num_asteroids = 5 elif self.current_level == 2: self.max_num_asteroids = 10 elif self.current_level == 3: self.max_num_asteroids = 15 elif self.current_level == 4: self.max_num_asteroids = 20 elif self.current_level == 5: self.max_num_asteroids = 20 self.is_alien = True def highscorecheck(self): if self.score > self.highscore.get_min_score(): self.newhighscore = True def next_level_check(self): if len(self.asteroids) == 0 and not self.state == "gameover": if self.current_level == 5: self.state = "victory" pygame.display.flip() self.screen.blit(self.image_handle(), [0, 0]) self.screen.blit(victory_text, (230, 200)) else: self.state = "middlescreen" self.screen.fill(BLACK) self.screen.blit(next_level_text, (120, 200)) self.screen.blit(continue_text, (120, 240)) def spawn_stars(self): if self.new_level: self.stars.clear() if len(self.stars) < 100 and not self.ship.life == 0: self.stars.append(Star()) def print_score_and_level(self): score_text = pygame.font.SysFont(myfont, 20).render("Score:" + str(self.score), 1, WHITE) stage_text = pygame.font.SysFont(myfont, 20).render( "Stage:" + str(self.current_level), 1, WHITE) self.screen.blit(score_text, (700, 10)) self.screen.blit(stage_text, (700, 25)) def start_menu(self): self.screen.fill(BLACK) self.background_image = self.image_handle() self.screen.blit(self.background_image, [0, 0]) self.screen.blit(welcome_text, (300, 70)) self.screen.blit(welcome_text_two, (240, 120)) self.buttons.extend((start_button, options_button, quit_button, help_button, highscore_button)) for b in self.buttons: b.draw(self.screen) def paused(self): self.screen.blit(return_text, (180, 200)) self.screen.blit(start_text, (215, 240)) self.screen.blit(pause_text, (335, 100)) def bhelp(self): self.background_image = self.image_handle() self.screen.blit(self.background_image, [0, 0]) def runGame(self): super().runGame() def life_check(self): if self.ship.life == 0: self.state = "gameover" def update_simulation(self): """ update_simulation() causes all objects in the game to update themselves """ super().update_simulation() if self.ship: self.ship.update(self.width, self.height) if self.ship.shield_activated: self.ship.shield.update(self.width, self.height) for asteroid in self.asteroids: asteroid.update(self.width, self.height) for star in self.stars: star.update(self.width, self.height) for bullets in self.ship.bullets: bullets.update(self.width, self.height) if self.is_alien: self.alien.alien_in_game(self.ship, self.width, self.height, self.screen) for bullets in self.alien.bullets: bullets.update(self.width, self.height) if self.alien.life == 0: self.is_alien = False def handle_state(self): if self.state == "gameover": self.death_handler() if self.state == "playing": self.screen.fill(BLACK) self.life_check() self.spawn_stars() self.spawn_asteroids() self.collision_handle() self.next_level_check() self.print_score_and_level() self.show_lifebar() if self.state == "paused": self.paused() elif self.state == "startmenu": self.start_menu() for event in pygame.event.get(): for button in self.buttons: if 'click' in button.handleEvent(event): if button._propGetCaption() == "QUIT": self.running = False if button._propGetCaption() == "START": if self.sound: pygame.mixer.music.play(-1) self.state = "playing" if button._propGetCaption() == "OPTIONS": self.state = "menuoption" if button._propGetCaption() == "HELP": self.state = "menuoption" self.bhelp() if button._propGetCaption() == "HIGHSCORE": self.state = "menuoption" self.highscore.printboard(self.screen) def render_objects(self): """ render_objects() causes all objects in the game to draw themselves onto the screen """ super().render_objects() # Render the ship: if self.state == "playing": if self.ship.shield_activated: self.ship.shield.draw(self.screen) self.ship.draw(self.screen) self.shield_bar() # Render all the stars, if any: for star in self.stars: star.draw(self.screen) # Render all the asteroids, if any: for asteroid in self.asteroids: asteroid.draw(self.screen) # Render all the bullet, if any: for bullet in self.ship.bullets: bullet.draw(self.screen) if self.is_alien: self.alien.draw(self.screen) for bullet in self.alien.bullets: bullet.draw_a(self.screen) if bullet.position.x >= self.width - 5 or bullet.position.y >= self.height - 5: self.alien.bullets.remove(bullet)