class Game: def __init__(self, surface): """ :param surface: surface of the window """ # game variables self.surface = surface self.clock = pygame.time.Clock() self.continue_game = True self.game_pause = False self.start_game = False self.collision = False # score variables self.score = 0 self.cross_pipe1 = False self.cross_pipe2 = False # fps counter self.fps = 30 # background and ground self.background = pygame.image.load( "./Assets/images/flappy_background.png").convert_alpha() self.background = pygame.transform.scale( self.background, (surface.get_width(), surface.get_height())) self.ground = pygame.image.load( "./Assets/images/ground.png").convert_alpha() self.ground = pygame.transform.scale( self.ground, (surface.get_width(), int(surface.get_height() // 5.48))) self.bg_scroll = 0 self.rel_x = self.bg_scroll % self.ground.get_rect( ).width # for background scrolling self.ground_y = self.surface.get_height() - self.ground.get_rect( ).height # flappy objects self.player = Bird(self.surface, self.background) self.all_sprites = pygame.sprite.Group(self.player) self.dt = None # timer for bird animation # bottom rect for collision self.bottom_rect = pygame.Rect( 0, self.surface.get_height() - self.ground.get_rect().height, self.ground.get_rect().width, self.ground.get_rect().height) # pipe object self.pipe1 = Pipe(self.surface, self.ground) self.pipe2 = Pipe(self.surface, self.ground) # pipe scroll variables self.pipe1_rel_x = self.surface.get_width() + self.surface.get_width( ) // 1.08 # added 1000 to give some time when game starts self.min_pipe1_rel_x = -self.pipe1.pipe_width() self.pipe2_rel_x = self.surface.get_width( ) + self.surface.get_width() // 1.54 + self.surface.get_width( ) // 1.08 # added 700 due to pipe difference self.min_pipe2_rel_x = -self.pipe2.pipe_width() # game texts object self.game_text = Font(self.surface, self.ground) def play(self): """ Main Game Loop :return: None """ while self.continue_game: self.dt = self.clock.tick(self.fps) / 1000 # for game animation self.event_handler() # handling pygame events if self.start_game: self.play_game() # game start function if not self.game_pause: self.player.image_animation(self.dt, self.start_game) # bird animation self.draw() if not self.start_game: if not self.game_pause: self.game_text.draw_intro() if self.game_pause: self.game_text.draw_game_over(str(self.score)) pygame.display.update() def event_handler(self): """ Handles pygame events :return: None """ events = pygame.event.get() keys = pygame.key.get_pressed() for event in events: if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: self.continue_game = False if event.type == pygame.KEYDOWN: if keys[pygame.K_SPACE]: self.start_game = True self.player.jump(True) if not keys[pygame.K_SPACE]: self.player.jump(False) if keys[pygame.K_SPACE]: if self.game_pause: self.__init__(self.surface) # restarts the game self.dt = self.clock.tick(self.fps) / 1000 if keys[pygame.K_ESCAPE]: self.continue_game = False if self.collision: self.game_pause = True self.start_game = False def play_game(self): """ Starts the game when space is pressed :return: None """ self.pipe_scroll() self.player.rotation(self.dt) self.player.move() self.update_score() self.player_collision() def draw(self): """ Draws the objects on the surface :return: None """ self.surface.blit(self.background, (0, -self.ground.get_rect().height)) if self.start_game: self.pipe1.draw(self.pipe1_rel_x) self.pipe2.draw(self.pipe2_rel_x) self.game_text.draw_score(str(self.score)) self.all_sprites.draw(self.surface) if not self.game_pause: self.background_scroll() if self.game_pause: # draws the last frame when game pauses self.pipe1.draw(self.pipe1_rel_x) self.pipe2.draw(self.pipe2_rel_x) self.surface.blit( self.ground, (self.rel_x - self.ground.get_rect().width, self.ground_y)) self.surface.blit(self.ground, (self.rel_x, self.ground_y)) def background_scroll(self): """ Infinite scroll of the ground when the game is being played :return: None """ if self.continue_game: # stars scrolling when game starts self.rel_x = self.bg_scroll % self.ground.get_rect().width self.surface.blit( self.ground, (self.rel_x - self.ground.get_rect().width, self.ground_y)) if self.rel_x < self.surface.get_width(): self.surface.blit(self.ground, (self.rel_x, self.ground_y)) if self.continue_game: self.bg_scroll -= 10 def pipe_scroll(self): # maybe make it into list """ Moves the pipes 10 pixels :return: None """ if self.pipe1_rel_x < self.min_pipe1_rel_x: # changes the pipe position when it goes out of window self.pipe1_rel_x = self.pipe2_rel_x + self.surface.get_width( ) // 1.54 # maintains the distance between the pipes self.cross_pipe1 = False self.pipe1.pip_position() self.pipe1_rel_x -= 10 if self.pipe2_rel_x < self.min_pipe2_rel_x: self.pipe2_rel_x = self.pipe1_rel_x + self.surface.get_width( ) // 1.54 self.cross_pipe2 = False self.pipe2.pip_position() self.pipe2_rel_x -= 10 def player_collision(self): """ Checks for collision with the player and the bird :return: None """ if self.pipe1.collision(self.player.collision_rect): self.collision = True elif self.pipe2.collision(self.player.collision_rect): self.collision = True elif self.bottom_rect.colliderect(self.player.collision_rect): self.collision = True def update_score(self): if self.player.return_pos() > self.pipe1_rel_x + self.pipe1.pipe_width( ) and self.cross_pipe1 is False: self.score += 1 self.cross_pipe1 = True if self.player.return_pos() > self.pipe2_rel_x + self.pipe2.pipe_width( ) and self.cross_pipe2 is False: self.score += 1 self.cross_pipe2 = True