class Scene_Level(Scene): def __init__(self, game): Scene.__init__(self, game) def init(self): self.scrollablePosition = [0, 0] self.scrollableSize = [480, 240] self.map = Map(self.game, 'map.tmx') self.game.map = self.map self.scrollableLayer = ScrollableLayer(self.game, self.scrollablePosition, self.scrollableSize, [0, 0], self.map.size) self.game.scrollableLayer = self.scrollableLayer self.units = [] self.units.append(Unit(self.game, [96, 64])) self.units.append(Unit(self.game, [96, 96])) self.units.append(Unit(self.game, [96, 128])) self.units.append(Unit(self.game, [96, 160])) self.ui = UI(self.game) def endTurn(self): for unit in self.units: unit.endTurn() def update(self, deltaTime, events): scrollSpeed = 32 * deltaTime keys = pygame.key.get_pressed() if keys[pygame.K_UP] or self.game.cursor.bounds['top']: self.scrollableLayer.changeOffsetBy([0, 1 * scrollSpeed]) if keys[pygame.K_DOWN] or self.game.cursor.bounds['bottom']: self.scrollableLayer.changeOffsetBy([0, -1 * scrollSpeed]) if keys[pygame.K_LEFT] or self.game.cursor.bounds['left']: self.scrollableLayer.changeOffsetBy([1 * scrollSpeed, 0]) if keys[pygame.K_RIGHT] or self.game.cursor.bounds['right']: self.scrollableLayer.changeOffsetBy([-1 * scrollSpeed, 0]) for event in events: if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: self.endTurn() self.map.update(deltaTime, events) for unit in self.units: unit.update(deltaTime, events) self.scrollableLayer.update(deltaTime, events) self.ui.update(deltaTime, events) def draw(self, screen): self.map.draw(self.scrollableLayer.virtualSurface) for unit in self.units: unit.draw(self.scrollableLayer.virtualSurface) self.scrollableLayer.draw(screen) self.ui.draw(screen)
class Game: def __init__(self): pygame.init() self.w, self.h = 1000, 800 self.win = pygame.display.set_mode((self.w, self.h)) self.board = Board(5, 5, 790, 790, self) self.ui = UI(800, 5, 195, 790) self.ui.create_panel(self) self.mouse_position = (0, 0) self.mouse_button_down = False def run(self): clock = pygame.time.Clock() while True: dt = clock.tick(30) self.board.elapsedTime += dt / 1000 self.mouse_position = pygame.mouse.get_pos() self.mouse_button_down = False self.win.fill((150, 150, 150)) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() quit() if event.type == MOUSEBUTTONDOWN: self.mouse_button_down = True if self.board.HasPieceMouse(self.mouse_position[0], self.mouse_position[1]): self.board.GetPieceMouse(self.mouse_position[0], self.mouse_position[1]) else: self.board.UnselectCase() self.board.draw() self.ui.draw(self) pygame.display.update()
class SnakeGame: """ Main game class """ def __init__(self, s_width, s_height, setup): """ Initialize the game starting in main menu Args: s_width (int): screen_width s_width (int): screen_height setup (Setup[]): list of setup options: Desktop: default option. in this mode everything is controlled by keyboard Arcade: prevents user from quiting the game from ui and changing key bindings in this mode both the game and ui are controlled by joysticks Windowed: default option. Uses s_width and s_height to determine screen dimensions Fullscreen: ignores s_width and s_height args and enables fullscreen (duh) """ pygame.init() pygame.font.init() self.arcade = False fullscreen = False for opt in setup: if opt == Setup.Arcade: self.arcade = True elif opt == Setup.Fullscreen: fullscreen = True self.joysticks = [ pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count()) ] for j in self.joysticks: j.init() self.display = Display((s_width, s_height), fullscreen) self.clock = pygame.time.Clock() self.FPS = 60 self.ui = UI(self.display) if self.arcade: if len(self.joysticks) == 0: print( "=================== plug in the controller ===================" ) exit(1) self.ui.enable_arcade_mode() self.selected_speed = "speed Medium" self.game_manager = GameManager(self.display, self.ui, GameMode.EatToGrow, GameState.Menu) def start_new_game(self, mode): """ Start a new game Args: Mode (GameMode): selected game mode InfiniteSnake: snakes dont shrink and there are no pickups EatToGrow: snakes shrink to preserve constant length. players can eat pickups to grow in length and speed up EatToSurvive = snakes shrink and their length decrease in time. players have to eat pickups to stay alive """ self.display.clear() #self.ui.hide() if self.selected_speed == "speed Slow": self.game_manager.set_players_speed(1.9) elif self.selected_speed == "speed Medium": self.game_manager.set_players_speed(3) elif self.selected_speed == "speed Fast": self.game_manager.set_players_speed(5) self.game_manager = GameManager(self.display, self.ui, mode, GameState.Running, self.game_manager.player1, self.game_manager.player2) def handle_events(self): """ Invoke handlers for desired events during game """ keys = pygame.key.get_pressed() if self.game_manager.game_state == GameState.Running: if self.arcade: self.game_manager.control_players_arcade(self.joysticks) else: self.game_manager.control_players(keys) elif self.arcade: self.ui.arcade_control(self.joysticks[1]) for event in pygame.event.get(): if event.type == pygame.QUIT: self.game_manager.game_state = GameState.Quit if self.game_manager.game_state == GameState.Finished or\ self.game_manager.game_state == GameState.Menu : if event.type == pygame.KEYDOWN and not self.arcade: self.ui.control(event.key) #self.start_new_game(GameMode.EatToSurvive) def handle_ui_response(self): """ Handle user actions performed in the interface """ option = self.ui.get_selected_option() #main menu if option == "Play": #self.game_manager.game_state = GameState.Menu pass elif option == "Quit": self.ui.hide() self.game_manager.game_state = GameState.Quit #settings menu elif option == "p1 Absolute": self.game_manager.player1.steering_mode = "absolute" elif option == "p1 Relative": self.game_manager.player1.steering_mode = "relative" elif option == "p2 Absolute": self.game_manager.player2.steering_mode = "absolute" elif option == "p2 Relative": self.game_manager.player2.steering_mode = "relative" elif option == "P1 Key Bindings": self.ui.load_controls(self.game_manager.player1.controls) elif option == "P2 Key Bindings": self.ui.load_controls(self.game_manager.player2.controls) #key bindings menu elif option == "Apply": if self.ui.currently_changed_player == "p1": self.game_manager.player1.controls = self.ui.loaded_player_controls elif self.ui.currently_changed_player == "p2": self.game_manager.player2.controls = self.ui.loaded_player_controls #speed menu elif option == "speed Slow" or option == "speed Medium" or option == "speed Fast": self.selected_speed = option #play menu elif option == "Standard": self.start_new_game(GameMode.EatToGrow) elif option == "Infinite": self.start_new_game(GameMode.InfiniteSnake) elif option == "Starve": self.start_new_game(GameMode.EatToSurvive) #endgame menu elif option == "Play Again": self.start_new_game(self.game_manager.game_mode) elif option == "Return to main menu": self.game_manager.game_state = GameState.Menu def render_scene(self): """ Draw objects onto the screen. All the rendering is done here """ if self.game_manager.game_state == GameState.Running or\ self.game_manager.game_state == GameState.Finished: self.display.erase_points() self.game_manager.draw_players() self.ui.draw() pygame.display.flip() # if self.game_manager.game_state == GameState.Finished: # time.sleep(0.5) def cleanup(self): """ Cleanup after the game has ended """ pygame.quit() def main_loop(self): """ Main loop of the game. """ while self.game_manager.game_state != GameState.Quit: self.handle_events() self.handle_ui_response() #in menu if self.game_manager.game_state == GameState.Menu: self.display.clear() #in game elif self.game_manager.game_state == GameState.Running: self.game_manager.move_players() #after game elif self.game_manager.game_state == GameState.Finished: if self.game_manager.winner == None: self.game_manager.player1.decay() self.game_manager.player2.decay() else: self.game_manager.loser.decay() self.game_manager.loser.draw() #perform game manager actions self.game_manager.act() #do all the rendering stuff self.render_scene() #control FPS self.clock.tick(self.FPS)
class Game: def __init__(self): # fps stuff self.print_fps = True self.fps_max = 0 self.fps_min = 100000 self.avg_fps = [] self._draw_map_grid = False # system stuff self.screen = None self.clock = None self.pygame_init() self.running = True self.game_tic = 0 self.move_tic = 0 pygame.event.set_blocked(None) pygame.event.set_allowed([ pygame.KEYUP, pygame.KEYDOWN, pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.QUIT, pygame.MOUSEMOTION ]) self.image_loader = Image() self.paused = False self.paused_movement_buffer = [] # map stuff self.get_current_map() # player stuff player_spawn = self.current_map.get_player_spawn_pos() self.can_move = False self.player = Player(player_spawn, ZERO_VECTOR) self.player.set_walls( self.current_map.get_walls()) # TODO don't like this self.smooth_move_list = self.player.get_smooth_movement( ) # TODO change to be hooked to viewable object self.directions = {LEFT: False, RIGHT: False, UP: False, DOWN: False} self.player_inventory = PlayerInventory() # viewable stuff self.bounds = { LEFT: WIDTH // 4, RIGHT: WIDTH // 2, UP: HEIGHT // 4, DOWN: HEIGHT // 2 } self.bounding_rect = pygame.Rect(self.bounds[LEFT], self.bounds[UP], self.bounds[RIGHT], self.bounds[DOWN]) self.camera_object = self.create_view_object() self.offset_value = (0, 0) self.need_to_redraw = True # UI stuff self.fade = Fade() self.ui = UI() self.menu_screen = MenuScreen() self.menu_is_open = False self.need_mouse_movement = False self.mouse_held = False self.inv_pickup = None self.inv_drop = None def update(self): self.get_events() self.update_player() self.check_bounds() # todo move to other method with smooth scrolling self.smooth_scrolling() # TODO self.get_fps() self.ui.update() if self.menu_is_open: self.menu_screen.update() def draw(self): self.check_redraw() self.get_offset() if not self.menu_is_open: self.draw_map() self.draw_ui() if self._draw_map_grid: # TODO remove after testing self.draw_map_grid() # self.fade.draw() self.player.draw() if self.menu_is_open: self.menu_screen.draw() pygame.display.update() self.clock.tick(TIC_RATE) self.game_tic += 1 self.player.get_game_tic( self.game_tic) # TODO do a better way of giving player game tic self.need_to_redraw = True # TODO change to false after testing def draw_ui(self): self.ui.draw() _ = self.player_inventory.get_images_for_ui() if _ is not None: self.ui.set_inventory_images(_) def open_menu(self): self.paused_movement_buffer = self.player.movement_input self.paused = True self.menu_is_open = True def close_menu(self): self.player.movement_input = self.paused_movement_buffer self.paused = False self.menu_is_open = False def get_events(self): _movement = None for event in pygame.event.get(): if event.type == pygame.QUIT: self.stop_running() if event.type == pygame.KEYDOWN: _movement = self.key_down_event(_movement, event) elif event.type == pygame.KEYUP: _movement = self.key_up_event(_movement, event) elif event.type == pygame.MOUSEBUTTONDOWN: self.mouse_button_down_event(event) elif event.type == pygame.MOUSEBUTTONUP: self.mouse_button_up_event(event) if self.need_mouse_movement: if event.type == pygame.MOUSEMOTION: self.mouse_motion_event(event) def key_down_event(self, _movement, event): if event.key == pygame.K_d: _movement = Directions.RIGHT.value elif event.key == pygame.K_a: _movement = Directions.LEFT.value elif event.key == pygame.K_w: _movement = Directions.UP.value elif event.key == pygame.K_s: _movement = Directions.DOWN.value if event.key == pygame.K_ESCAPE: if not self.menu_is_open: self.open_menu() else: self.close_menu() if event.key == pygame.K_i: self.ui.inventory_visible = not self.ui.inventory_visible self.need_mouse_movement = not self.need_mouse_movement # TODO do this differently. if self.paused: if _movement: # todo refactor this. it's messy and has repeating code if _movement not in self.paused_movement_buffer: self.paused_movement_buffer.append(_movement) _movement = None self.player.movement_input = ["still"] if _movement: if _movement not in self.player.movement_input: self.player.add_movement_input(_movement) return _movement def key_up_event(self, _movement, event): if event.key == pygame.K_d: _movement = Directions.RIGHT.value elif event.key == pygame.K_a: _movement = Directions.LEFT.value elif event.key == pygame.K_w: _movement = Directions.UP.value elif event.key == pygame.K_s: _movement = Directions.DOWN.value if self.paused: if _movement: if _movement in self.paused_movement_buffer: self.paused_movement_buffer.remove(_movement) _movement = None if _movement: if _movement in self.player.movement_input: self.player.remove_movement_input(_movement) return _movement def mouse_button_down_event(self, event): self.inv_pickup = (event.pos[0] - STEP // 2) // 32, ( event.pos[1] - STEP // 2 - STEP) // 32 inv_clicked = self.ui.ui_clicked(event.pos) if inv_clicked and self.inv_pickup in self.player_inventory.inventory.filled_cells: self.mouse_held = True else: self.inv_pickup = None def mouse_button_up_event(self, event): self.inv_drop = (event.pos[0] - STEP // 2) // 32, ( event.pos[1] - STEP // 2 - STEP) // 32 if self.inv_pickup and self.inv_drop: self.player_inventory.move_item(self.inv_pickup, self.inv_drop) self.mouse_held = False self.inv_pickup = None self.inv_drop = None def mouse_motion_event(self, event): if self.mouse_held: self.ui.inventory.add_image_offset( self.inv_pickup, (event.pos[0] - 16 - 16 - (self.inv_pickup[0] * 32), event.pos[1] - 32 - 16 - 16 - (self.inv_pickup[1] * 32))) ui_hovering = self.ui.ui_hovering(event.pos) if ui_hovering is not None: if ui_hovering[1] == "inventory": # TODO make constant item = self.player_inventory.get_item(ui_hovering[0]) if item: self.ui.inventory.make_info_box(item, event.pos) else: self.ui.inventory.reset_info_box() else: self.ui.inventory.reset_info_box() def pygame_init(self): self.screen = pygame.display.get_surface() self.clock = pygame.time.Clock() def update_player(self): self.player.set_offset(self.offset_value) self.player.update() def draw_moving_tiles(self): self.current_map.draw_single_tile(self.player.get_stood_tile(), self.offset_value) self.current_map.draw_single_tile(self.player.get_facing_tile(), self.offset_value) self.current_map.draw_single_tile(self.player.get_behind_tile(), self.offset_value) def draw_map(self): if self.need_to_redraw: self.current_map.draw(self.offset_value) else: self.draw_moving_tiles() def get_offset(self): self.offset_value = self.camera_object.get_offset() def check_bounds(self): if self.player.pos[0] + self.offset_value[0] < self.bounding_rect.left: self.directions[LEFT] = True elif self.player.pos[0] + self.offset_value[ 0] > self.bounding_rect.right: self.directions[RIGHT] = True if self.player.pos[1] + self.offset_value[1] < self.bounding_rect.top: self.directions[UP] = True elif self.player.pos[1] + self.offset_value[ 1] > self.bounding_rect.bottom: self.directions[DOWN] = True def check_redraw(self): if self.camera_object.check_if_offset_changed(self.offset_value): self.need_to_redraw = True def smooth_map_scrolling(self): if self.player.is_moving(): if self.directions[RIGHT]: self.move_cycle(-self.smooth_move_list[self.move_tic], 0) elif self.directions[LEFT]: self.move_cycle(self.smooth_move_list[self.move_tic], 0) if self.directions[DOWN]: self.move_cycle(0, -self.smooth_move_list[self.move_tic]) elif self.directions[UP]: self.move_cycle(0, self.smooth_move_list[self.move_tic]) self.tic_cycle() def smooth_scrolling(self): if any(list(self.directions.values())): self.smooth_map_scrolling() else: self.smooth_player_scrolling() self.reset_directions() def smooth_player_scrolling(self): if self.player.is_moving(): self.tic_cycle() def reset_directions(self): for key in self.directions.keys(): self.directions[key] = False def tic_cycle(self): self.move_tic += 1 if self.move_tic == self.player.get_speed(): self.move_tic = 0 self.player.update_move_tic(self.move_tic) def move_cycle(self, x=0, y=0): self.camera_object.shift(x, y) def get_current_map(self): self.current_map = Map01() # TODO get from file def is_running(self): return self.running def stop_running(self): self.running = False def start_running(self): self.running = True def create_view_object(self): return View(self.current_map, self.player, *self.current_map.camera_pos) def get_fps(self): fps = self.clock.get_fps() self.avg_fps.append(fps) if len(self.avg_fps) > 1000: del (self.avg_fps[0]) avg = sum(self.avg_fps) // (len(self.avg_fps)) self.fps_max = max(self.fps_max, fps) _min = min(self.fps_min, fps) if _min: self.fps_min = _min if self.print_fps: pygame.display.set_caption( f'fps: avg={avg:.0f} current={fps:.0f} min={self.fps_min:.0f},' f' max={self.fps_max:.0f} TIC={self.game_tic}') def draw_map_grid(self): # for testing only. delete after testing for i in range(WIDTH // STEP): pygame.draw.line(self.screen, (0, 0, 0), (i * STEP, 0), (i * STEP, HEIGHT), 1) for i in range(HEIGHT // STEP): pygame.draw.line(self.screen, (0, 0, 0), (0, i * STEP), (WIDTH, i * STEP), 1)