def on_new_game(self): debugger( "Display: mGamestateChangeListener: on_new_game: Redrawing background" ) self.parent.randomise_background() self.parent.draw_background() self.parent.hud = NewGameHUD(self.parent.display)
def state_controls(self, event): if event.key in self.START_KEYS: debugger("NewGameState: state_controls: Pressed a START key") self.state_instance.current_state = FlappyFlyingState( self.flappy, self.pipes, self.ground) return True # state has changed, do not call state_update return False
def on_flappy_flying(self): debugger( "Display: mGamestateChangeListener: on_flappy_flying: Redrawing background" ) self.parent.draw_background() self.parent.hud = FlappyFlyingHUD(self.parent.display, self.parent.background)
def __init__(self, scale_pos_x, scale_pos_y): super(Flappy, self).__init__() self.display_width = Assets.get().display_width self.display_height = Assets.get().display_height self.default_position = (int(scale_pos_x * self.display_width), int(scale_pos_y * self.display_height)) debugger("Flappy: __init__: default_position = {}".format( self.default_position)) # scaling physics with display resolution self.ACCELERATION *= self.display_height self.MAX_VELOCITY *= self.display_height self.JUMP_VELOCITY *= self.display_height self.IDLE_ANIMATION_MAX_Y *= self.display_height self.IDLE_ANIMATION_SPEED *= self.display_height # loading flappy assets self.FLAPPY_UP_IMAGE = Assets.get().FLAPPY_UP_IMAGE self.FLAPPY_IMAGES = Assets.get().FLAPPY_IMAGES # the actual image that gets rendered and collision detection mask self.image = self.FLAPPY_IMAGES[0] self.rect = self.image.get_rect() self.hitmask = get_alpha_hitmask(self.image, self.rect) # setting Flappy's default values self.position = self.default_position self.velocity = 0 self.idle_direction = -1 self.animation_ms = 0 self.flappy_flap_listeners = list()
def update(self, delta_t): ''' The central Gamestate class will call this method in order to update the individual state. ''' drawables = list() for event in pygame.event.get(): if not hasattr(event, 'key') or event.type is not pygame.KEYDOWN: continue # these controls apply to all states that subclass the template elif event.key in self.QUIT_KEYS: debugger("GamestateTemplate: update: Pressed a QUIT key") self.state_instance.quit() else: # update controls specific to the individial state # the stop flag is used to avoid drawing if the state changes stop = self.state_controls(event) if stop: return drawables # update the individual state drawables = self.state_update(delta_t) return drawables
def current_state(self, new_state): self._current_state = new_state if isinstance(new_state, IntroState): debugger( "Gamestate: current_state.setter: Setting state to IntroState") self.call_gamestate_change_listeners_on_intro() elif isinstance(new_state, NewGameState): debugger( "Gamestate: current_state.setter: Setting state to NewGameState" ) self.call_gamestate_change_listeners_on_new_game() elif isinstance(new_state, FlappyFlyingState): debugger( "Gamestate: current_state.setter: Setting state to FlappyFlyingState" ) self.call_gamestate_change_listeners_on_flappy_flying() elif isinstance(new_state, GameOverState): debugger( "Gamestate: current_state.setter: Setting state to GameOverState" ) self.call_gamestate_change_listeners_on_game_over( self.current_state.score) else: debugger( "FATAL ERROR: Gamestate: current_state.setter: Given state is not valid!", fatal=True)
def get_ground_under_flappy(self): ''' This method returns the Ground object that is directly under Flappy. It is called by FlappyFlyingState in its update_state method. ''' for ground in self.ground_list: # TODO: better way of using flappy's position (.. > s.d_w * 0.2) if ground.position[0] + Assets.get().GROUND_IMAGE.get_width( ) / 2.0 > self.display_width * 0.2: return ground debugger("FATAL ERROR: GroundManager: get_ground_under_flappy:" \ " Did not find any ground under Flappy!", fatal=True)
def run(self): debugger("Gameloop: run: Starting gameloop") while self.gamestate.is_running: # get the elapsed time since last tick and cap the fps delta_t_ms = self.clock.tick(self.FRAMES_PER_SECOND) delta_t_sec = delta_t_ms / 1000.0 fps = self.clock.get_fps() drawables = self.gamestate.update(delta_t_sec) self.display.update(drawables, fps) debugger("Gameloop: run: Exiting gameloop")
def __init__(self, pipes, score): super(GameOverState, self).__init__() self.pipes = pipes self.score = score self.pipes.reset_pipes() try: # TODO: track best score as well track_data('updater-flappy-judoka-score', {'score': score}) except: logger.warn("Tracking the users score failed!") debugger( "ERROR: GameOverState: __init__: Tracking the users score failed!" )
def update_difficulty(self): self.difficulty_counter += 1 if self.difficulty_counter == self.DIFFICULTY_CHANGE: self.difficulty_counter = 0 # increase the difficulty by making the spacing between the pipes smaller if self.pipe_spacing_x > self.PIPE_MIN_SPACING_X: self.pipe_spacing_x -= self.PIPE_SPACING_DECREASE self.pipe_spacing_y -= self.PIPE_SPACING_DECREASE debugger( "PipeManager: update_difficulty: Making spacing smaller X = {}, Y = {}" .format(self.pipe_spacing_x, self.pipe_spacing_y)) else: debugger( "PipeManager: update_difficulty: Highest difficulty reached! WOOHOO! Keep going!" )
def setup(self): ''' This method is called by the Gameloop in order to initialise the Sound class. It provides the implementation of the state change listener such that it can play various sounds specific to state transitions. ''' # check that the platform supports sound playback # if it doesn't, then it won't implement any listeners initialised = pygame.mixer.get_init() if initialised: debugger("Sound: __init__: Mixer is available and is initialised:" \ " frequency = {}, format = {}, channels = {}" .format(initialised[0], initialised[1], initialised[2])) Gamestate.get().add_gamestate_change_listener(self.mGamestateChangeListener(self)) else: debugger("Sound: __init__: Mixer is not available! Game will not have sounds!")
def load(self): debugger("Assets: load: Loading all game assets") self.FLAPPY_UP_IMAGE = load_image('flappy-up.png', colorkey=None, alpha=True) self.FLAPPY_MIDDLE_IMAGE = load_image('flappy-middle.png', colorkey=None, alpha=True) self.FLAPPY_DOWN_IMAGE = load_image('flappy-down.png', colorkey=None, alpha=True) self.PIPE_TOP_IMAGE = load_image('yellow-cable-top.png') self.PIPE_BODY_IMAGE = load_image('yellow-cable-body.png') self.BACKGROUND_DAY_COLOR = (49, 64, 70) self.BACKGROUND_DAY_IMAGE = load_image('background.png') self.GROUND_IMAGE = load_image('ground.png') # sounds downloaded under CCO License from http://www.freesound.org/ # some of these have been edited to fit the game self.GAME_OVER_SOUND = load_sound('game-over.wav') self.START_GAME_SOUND = load_sound('game-start.wav') self.FLAPPY_FLAP_SOUND = load_sound('jump.wav') self.GAINED_POINT_SOUND = load_sound('point.wav')
def update(self, delta_t): ''' This method updates the entire pipe "system" and is called by each individual game state when appropriate. It calls the update for each Pipe and moves the first two pipes to the back when they fall off the display to the left. ''' # call the update function of every Pipe sprite for pipe in self.pipes_list: pipe.update(delta_t) # if the first two pipes fall off the screen completely if self.pipes_list[0].position[0] < -self.pipe_width / 2: debugger("PipeManager: update: A pipe object fell off the screen") # remove the first pipes (by X) top/bottom first_top_pipe = self.pipes_list.pop(0) first_bottom_pipe = self.pipes_list.pop(0) # calculate X to move first pipes to last, equally spaced # when the top/bottom pipes are moved to the back, randomize Y positions new_last_pipe_x = self.pipes_list[-1].position[ 0] + self.pipe_spacing_x + self.pipe_width new_last_pipe_top_y, new_last_pipe_bottom_y = self.randomize_pipe_y_positions( ) # first pipe (by X) becomes the last first_top_pipe.position = (new_last_pipe_x, new_last_pipe_top_y) first_bottom_pipe.position = (new_last_pipe_x, new_last_pipe_bottom_y) # add the pipes to the end of the list self.pipes_list.append(first_top_pipe) self.pipes_list.append(first_bottom_pipe) self.update_difficulty()
def __init__(self): self.display_width = Assets.get().display_width self.display_height = Assets.get().display_height # scaling ground position with display resolution self.GROUND_Y *= self.display_height debugger("GroundManager: __init__: GROUND_Y = {}".format( self.GROUND_Y)) self.ground_width = Assets.get().GROUND_IMAGE.get_width() debugger("GroundManager: __init__: ground_width = {}".format( self.ground_width)) # calculate the number of ground sprites needed and generate them self.no_of_grounds = self.display_width / self.ground_width + 2 debugger("GroundManager: __init__: no_of_grounds = {}".format( self.no_of_grounds)) self.ground_list = self.generate_ground() self.ground_group = pygame.sprite.RenderUpdates(self.ground_list)
def __init__(self): self.display_width = Assets.get().display_width self.display_height = Assets.get().display_height # scaling parameters with display resolution self.PIPE_INIT_X = int(self.PIPE_INIT_X * self.display_width) self.PIPE_MIN_SPACING_X = int(self.PIPE_MIN_SPACING_X * self.display_height) self.PIPE_MIN_SPACING_Y = int(self.PIPE_MIN_SPACING_Y * self.display_height) self.PIPE_MAX_SPACING_X = int(self.PIPE_MAX_SPACING_X * self.display_height) self.PIPE_MAX_SPACING_Y = int(self.PIPE_MAX_SPACING_Y * self.display_height) self.PIPE_SPACING_DECREASE = int(self.PIPE_SPACING_DECREASE * self.display_height) self.pipe_spacing_x = self.PIPE_MAX_SPACING_X self.pipe_spacing_y = self.PIPE_MAX_SPACING_Y self.pipe_width, self.pipe_height = Assets.get( ).PIPE_BOTTOM_IMAGE.get_size() debugger( "PipeManager: __init__: pipe_width = {}, pipe_height = {}".format( self.pipe_width, self.pipe_height)) # initialising parameters for randomizing top/bottom pipe y positions self.rand_from = int(self.display_height * self.SPACING_FROM_Y) self.rand_to = int(self.display_height * self.SPACING_TO_Y) debugger("PipeManager: __init__: (rand_from, rand_to) = {}".format( (self.rand_from, self.rand_to))) # calculate the number of pipes needed and generate them self.no_of_pipes = self.display_width / (self.pipe_width + self.PIPE_MIN_SPACING_X) + 2 debugger("PipeManager: __init__: no_of_pipes = {}".format( self.no_of_pipes)) self.pipes_list = self.generate_pipes() self.pipes_group = pygame.sprite.RenderUpdates(self.pipes_list) self.difficulty_counter = self.no_of_pipes
def __init__(self): # if the resolution was not changed through cmdline args, use the default scaling if self.WIDTH < 1 and self.HEIGHT < 1: monitor_info = pygame.display.Info() debugger("Display: __init__: Monitor resolution is {}x{}".format( monitor_info.current_w, monitor_info.current_h)) self.WIDTH = int(self.WIDTH * monitor_info.current_w) self.HEIGHT = int(self.HEIGHT * monitor_info.current_h) # TODO: remove this if font sizes in HUDs are scaled if self.HEIGHT < 400: debugger( "WARNING: flappy-judoka: main: Height resolution is below the recommended value 400!" ) self.display = pygame.display.set_mode((self.WIDTH, self.HEIGHT), pygame.NOFRAME) debugger("Display: __init__: Setting game resolution {}x{}".format( self.WIDTH, self.HEIGHT)) # setting the window name (this is for the window manager to have a reference) pygame.display.set_caption(self.GAME_TITLE) # hiding mouse pointer when the game runs pygame.mouse.set_visible(False) # grabing all keyboard and mouse inputs, apps behind the game won't get input pygame.event.set_grab(True) # initialising and loading assets based on screen resolution Assets(self.WIDTH, self.HEIGHT) # compose and draw the background self.randomise_background() self.draw_background()
def on_flappy_flying(self): debugger("Sound: mGamestateChangeListener: on_flappy_flying: Setting ScoreChangedListener and FlappyFlapListener") Gamestate.get().current_state.flappy.add_flappy_flap_listener(self.parent.mFlappyFlapListener(self.parent)) Gamestate.get().current_state.add_score_changed_listener(self.parent.mScoreChangedListener(self.parent))
def state_controls(self, event): if event.key in self.FLAP_KEYS: debugger("FlappyFlyingState: state_controls: Pressed a FLAP key") if not self.flappy_hit_pipe: self.flappy.flap()
def on_game_over(self, score): debugger( "Display: mGamestateChangeListener: on_game_over: Redrawing background" ) self.parent.draw_background() self.parent.hud = GameOverHUD(self.parent.display, score)
def on_intro(self): debugger( "Display: mGamestateChangeListener: on_intro: Setting the IntroHUD" ) self.parent.hud = IntroHUD(self.parent.display)
def add_score_changed_listener(self, listener): if not isinstance(listener, self.ScoreChangedListener): debugger("FATAL ERROR: PipeManager: add_score_changed_listener:" \ " Given listener is not an instance of ScoreChangedListener!", fatal=True) self.score_changed_listeners.append(listener)
def on_score_changed(self, score): debugger("Sound: mScoreChangedListener: on_score_changed: Playing gained_point_sound") self.parent.gained_point_sound.play()
def on_flappy_flap(self): debugger("Sound: mFlappyFlapListener: on_flappy_flap: Playing flappy_flap_sound") self.parent.flappy_flap_sound.play()
def add_gamestate_change_listener(self, listener): if not isinstance(listener, self.GamestateChangeListener): debugger("FATAL ERROR: Gamestate: set_gamestate_change_listener:" \ " Given listener is not an instance of GamestateChangeListener!", fatal=True) self.gamestate_change_listeners.append(listener)
def state_controls(self, event): if event.key in self.START_KEYS: debugger("GameOverState: state_controls: Pressed a START key") self.state_instance.current_state = NewGameState(self.pipes) return True # state has changed, do not call state_update return False
def on_intro(self): debugger("Sound: mGamestateChangeListener: on_intro: Playing start_game_sound") self.parent.start_game_sound.play()
def get(): if not Gamestate._singleton_instance: debugger( "FATAL ERROR: Gamestate: get: Gamestate was not initialised!", fatal=True) return Gamestate._singleton_instance
def add_flappy_flap_listener(self, listener): if not isinstance(listener, self.FlappyFlapListener): debugger("FATAL ERROR: Flappy: add_flappy_flap_listener:" \ " Given listener is not an instance of FlappyFlapListener!", fatal=True) self.flappy_flap_listeners.append(listener)
def on_game_over(self, score): debugger("Sound: mGamestateChangeListener: on_game_over: Playing game_over_sound") self.parent.game_over_sound.play()
def quit(self): debugger("Gamestate: quit: Setting _is_running to False") self._is_running = False