def __init__(self, window): super().__init__(window) self.player1_name = "Dark Conqueror" self.player2_name = "Knight of Light" self.game_keys = GAME_KEYS self.pressed_keys = {} for key in self.game_keys: self.pressed_keys[key] = False self.prev_pressed_keys = {} for key in self.game_keys: self.prev_pressed_keys[key] = False self.images = {} self.gui_textures = {self.player1_name: [], self.player2_name: []} self.init_gui_textures() self.player_name_font_size = 30 self.player_name_font = pygame.font.SysFont(None, self.player_name_font_size) self.does_menu = False self.menu = pygame_menu.Menu(title="Game menu", height=250, width=500, theme=pygame_menu.themes.THEME_DARK) self.menu.add.button("Quit", switch_to_menu, self.event_manager) self.engine = GameEngine(Player(self.player1_name), Player(self.player2_name)) self.end_time_frame_ended = get_time() self.fps_sys = FpsRenderSystem(window) self.end_time = None
def run_game(): global CONNECTED_PEOPLE global THREADS player1 = Player("Dark Conqueror") player2 = Player("Knight of Light") engine = GameEngine(player1, player2) game_running = True frame_in_period = 0 dt = 1 / 60 start_frame_time = get_time() print("GAME") end_time = None keys = [None] * 2 while game_running: frame_in_period += 1 # get players keys (non blocking) for i in range(len(CONNECTED_PEOPLE)): try: keys[i] = recv_data_on_open_socket(CONNECTED_PEOPLE[i]) except socket.error: keys[i] = None # update logic state = engine.update(dt, keys[0], keys[1]) # check for endgame if state.has_ended and end_time is None: end_time = get_time() if end_time and (get_time()-end_time) * 1e-9 >= 1: state.should_exit = True print("Game over") if state.should_exit: for i in range(len(CONNECTED_PEOPLE)): WANT_TO_PLAY[i] = False # block sockets block_socket(CONNECTED_PEOPLE[i]) # create threads player_thread = threading.Thread(target=threaded_client, args=[CONNECTED_PEOPLE[i], i]) player_thread.start() THREADS.append(player_thread) game_running = False # send data (if period ended) if frame_in_period % SENDING_PERIOD == 0 or state.should_exit: frame_in_period = 0 for i in range(len(CONNECTED_PEOPLE)): if not send_data_on_open_socket(CONNECTED_PEOPLE[i], state): print("Client exited.") return False # calculate frame time end_frame_time = get_time() dt = (end_frame_time - start_frame_time) * 1e-9 start_frame_time = get_time() return True
def __init__(self): self.player1 = Player('1', player_config['types'][0]) self.player2 = Player('2', player_config['types'][1]) self.game_board = GameWindow(window_config['resolution'], window_config['size'], window_config['hexes']) self.game_board.draw_display(True) self.game_engine = GameEngine(self.game_board, self.player1) self.turns_played = 0 # Four functions for four different types of game. self._games = { 'human_human': self._run_p1_p2_human, 'human_ai': self._run_p1_human_p2_ai, 'ai_human': self._run_p1_ai_p2_human, 'ai_ai': self._run_p1_ai_p2_ai, } # Select game type based on players self._run_func = self._games['{}_{}'.format(self.player1.type, self.player2.type)] self.game_ended = False self.start_time = time.time()
from engine.game_engine import GameEngine from engine.game.game_system import GameSystem from engine.game.event_system import EventSystem from engine.game.player_system import PlayerSystem from engine.render.render_system import RenderSystem game = GameEngine() game.add_system(GameSystem(game)) game.add_system(EventSystem(game)) game.add_system(PlayerSystem(game)) game.add_system(RenderSystem(game)) game.run()
def run(): parser = argparse.ArgumentParser(description='Run a game') parser.add_argument('game') parser.add_argument( '--renderer', choices=['LED', 'PYGAME'], default=defaults.DEFAULT_RENDERER, help= 'Use LED to control phisical leds. Use PYGAME for testing. Default: %s' % defaults.DEFAULT_RENDERER) parser.add_argument( '--total-leds', default=defaults.DEFAULT_TOTAL_LEDS, help= 'The total number of leds. This must match the configuration on the Teensy. Default: %s' % defaults.DEFAULT_TOTAL_LEDS) parser.add_argument( '--max-leds', default=defaults.DEFAULT_MAX_LEDS_PER_CELL, help= 'Max leds per cell (That is an X,Y coordinate in the game), this is handy to reduce bright clusters. Default: %s' % defaults.DEFAULT_MAX_LEDS_PER_CELL) parser.add_argument( '--max-brightness', default=defaults.DEFAULT_MAX_BRIGHTNESS, help= 'Possible values between 0 and 255. Scales the brightness of the leds. The leds can be really bright and with this value you can scale that down. Default: %s' % defaults.DEFAULT_MAX_BRIGHTNESS) parser.add_argument( '--pair-file', default=defaults.DEFAULT_PAIRING_FILE, help= 'The pair file which holds the led numbers and their positions. This is created by `src/tools/02-process-photos/process.py`. Default: %s' % defaults.DEFAULT_PAIRING_FILE) parser.add_argument( '--view-files', nargs='+', default=defaults.DEFAULT_VIEW_FILES, help= 'One or more view files. One view file is created by `src/tools/02-process-photos/process.py`. Default: %s' % defaults.DEFAULT_VIEW_FILES) parser.add_argument( '--min-x', default=defaults.DEFAULT_PAIRING_MIN_X, help='This helps cropping the screen. Default: %s' % defaults.DEFAULT_PAIRING_MIN_X) parser.add_argument( '--max-x', default=defaults.DEFAULT_PAIRING_MAX_X, help='This helps cropping the screen. Default: %s' % defaults.DEFAULT_PAIRING_MAX_X) parser.add_argument( '--min-y', default=defaults.DEFAULT_PAIRING_MIN_Y, help='This helps cropping the screen. Default: %s' % defaults.DEFAULT_PAIRING_MIN_Y) parser.add_argument( '--max-y', default=defaults.DEFAULT_PAIRING_MAX_Y, help='This helps cropping the screen. Default: %s' % defaults.DEFAULT_PAIRING_MAX_Y) parser.add_argument('--grid-width', default=defaults.DEFAULT_GRID_WIDTH, help='The width of the game screen. Default: %s' % defaults.DEFAULT_GRID_WIDTH) parser.add_argument('--grid-height', default=defaults.DEFAULT_GRID_HEIGHT, help='The height of the game screen. Default: %s' % defaults.DEFAULT_GRID_HEIGHT) parser.add_argument( '--serial-port', default=defaults.DEFAULT_SERIAL_PORT, help= 'The serial port towards the Teensy. This is only used if `--renderer` is `LED. Default: %s' % defaults.DEFAULT_SERIAL_PORT) parser.add_argument('--fps', default=defaults.DEFAULT_FPS, help='How fast the game runs. Default: %s' % defaults.DEFAULT_FPS) args = parser.parse_args(sys.argv[2:]) game_setup = games[args.game] led_config = LedConfig(total=int(args.total_leds), per_cell=int(args.max_leds), max_brightness=int(args.max_brightness)) pair_config = PairConfig(pair_file=args.pair_file, view_files=args.view_files, min_x=int(args.min_x), max_x=int(args.max_x), min_y=int(args.min_y), max_y=int(args.max_y), grid_width=int(args.grid_width), grid_height=int(args.grid_height)) config = Config(led=led_config, pair=pair_config, serial_port=args.serial_port, fps=int(args.fps)) game = game_setup.create(config) engine = GameEngine(args.renderer, config, game) engine.start()
import pygame import logging from config.gameparams import GameParams from sprite.sprite import Sprite from display.grid import Grid from engine.game_engine import GameEngine from display.display import Display logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger() pygame.init() pygame.display.set_caption("gamename") engine = GameEngine() def mouse_listener(keys): if keys[0] == 1: if engine.player.param['ready']: # pygame.display.update() if Grid.get_pixel_distance( engine.mouse_motion_pos[0], engine.mouse_motion_pos[1], engine.player.perma_px[0], engine.player.perma_px[1] ) > GameParams.config['player']['minimun_mouse_distance']: engine.player.move_by_mouse(engine.mouse_motion_pos) if __name__ == '__main__': engine.initialize_world()
def test_begin_session(self): game_engine = GameEngine() game_engine.begin_session(['player1'])
class GameInstance: def __init__(self): self.player1 = Player('1', player_config['types'][0]) self.player2 = Player('2', player_config['types'][1]) self.game_board = GameWindow(window_config['resolution'], window_config['size'], window_config['hexes']) self.game_board.draw_display(True) self.game_engine = GameEngine(self.game_board, self.player1) self.turns_played = 0 # Four functions for four different types of game. self._games = { 'human_human': self._run_p1_p2_human, 'human_ai': self._run_p1_human_p2_ai, 'ai_human': self._run_p1_ai_p2_human, 'ai_ai': self._run_p1_ai_p2_ai, } # Select game type based on players self._run_func = self._games['{}_{}'.format(self.player1.type, self.player2.type)] self.game_ended = False self.start_time = time.time() def _save_state(self): """ Saving function. Calls the 'to_dict' function of each object and stores it as a pickle file. :return: """ save_path = os.path.join(save_config['root_dir'], str(time.time()) + '.pkl') save_dict = dict() save_dict['player1'] = self.player1.to_dict() save_dict['player2'] = self.player2.to_dict() save_dict['game_board'] = self.game_board.to_dict() save_dict['game_engine'] = self.game_engine.to_dict() save_dict['turns_played'] = self.turns_played save_dict['_run_func'] = '{}_{}'.format(self.player1.type, self.player2.type) save_dict['game_ended'] = self.game_ended save_dict['start_time'] = self.start_time with open(save_path, 'wb') as f: pickle.dump(save_dict, f) def _load_state(self): """ Loads from the checkpoint specified in configs. This is done by re-playing both players moves in the right sequence. Board must be empty for correct loading. :return: """ load_path = os.path.join(save_config['load_from']) with open(load_path, 'rb') as f: save_dict = pickle.load(f) self.player1.from_dict(save_dict['player1']) self.player2.from_dict(save_dict['player2']) self.game_engine.from_dict(save_dict['game_engine']) self._run_func = self._games[save_dict['_run_func']] # Chain the moves in the right order and iterate through for move in [ *chain.from_iterable( zip(save_dict['player1']['move_list'], save_dict['player2']['move_list'])) ]: self.play_piece(move) self.game_ended = save_dict['game_ended'] self.start_time = save_dict['start_time'] def _undo_move(self): """ Removes the last two played stones. :return: """ # Undo player's move player = self.player1 if self._get_turn() == 1 else self.player2 if len(player.move_list) > 0: last_move = player.move_list.pop(-1) player.hex_list.remove(last_move) # Sanity check if not len(player.hex_list) == len(player.move_list): raise ValueError('List and set have different element count') self.game_engine.set_owner(last_move, -1) self.game_board.change_cell_color(last_move, (255, 255, 255, 255)) self.turns_played -= 1 # Then undo AI's move player = self.player1 if self._get_turn() == 1 else self.player2 last_move = player.move_list.pop(-1) player.hex_list.remove(last_move) # Sanity check if not len(player.hex_list) == len(player.move_list): raise ValueError('List and set have different element count') self.game_engine.set_owner(last_move, -1) self.game_board.change_cell_color(last_move, (255, 255, 255, 255)) self.turns_played -= 1 def _human_move(self): """ Function handling human-made plays. Validates if the move is possible then changes the cell color and updates the player move list. Also handles other commands (save, load, undo). :return: """ for event in pygame.event.get(): event_out = self.game_board.on_event(event) if event_out is not None: data = event_out[1] event_out = event_out[0] if event_out == pygame.MOUSEBUTTONDOWN: if not self.game_ended: self.play_piece(data) elif event_out == pygame.KEYDOWN: if data == 'save': self._save_state() elif data == 'load': self._load_state() elif data == 'undo': self._undo_move() def _run_p1_p2_human(self): """ Runs a human vs. human game. :return: """ # event handling, gets all event from the event queue self._human_move() def _run_p1_human_p2_ai(self): """ Runs a human vs. ai game. :return: """ if self._get_turn() == 0: self._human_move() else: if not self.game_ended: move = self.game_engine.ai_move(self.player1.hex_list, self.player2.hex_list, self.player2.heuristic) self.play_piece(move) def _run_p1_ai_p2_human(self): """ Runs an ai vs. human game. :return: """ if self._get_turn() == 1: self._human_move() else: if not self.game_ended: move = self.game_engine.ai_move(self.player1.hex_list, self.player2.hex_list, self.player1.heuristic) self.play_piece(move) def _run_p1_ai_p2_ai(self): """ Runs an ai vs. ai game. Alternates between each player's evaluation function. :return: """ if not self.game_ended: if self.turns_played % 2 == 0: heuristic_type = self.player1.heuristic else: heuristic_type = self.player2.heuristic move = self.game_engine.ai_move(self.player1.hex_list, self.player2.hex_list, heuristic_type) self.play_piece(move) sleep(1) pygame.event.get() def _check_if_open(self, cell): """ Check if a cell does not contain a stone. :param cell: Tuple (x,y). :return: True if the cell is empty. False otherwise. """ if cell not in self.player1.hex_list and cell not in self.player2.hex_list: return True else: return False def _check_if_playable(self, cell): """ Cell is playable if adjacent to two other cells. :param cell: Tuple (x,y). :return: Number of neighbours. """ hex_p1 = self.player1.hex_list hex_p2 = self.player2.hex_list hex_played = set(hex_p1).union(hex_p2) neigh_cell = set(self.game_board.map.spread(cell)) hex_count = hex_played.intersection(neigh_cell) return len(hex_count) def _check_cell(self, cell): """ Validate if cell is playable. :param cell: Coordinates of cell to check :param player_cells: List of cells marked by a player token. :return: True if cell is surrounded by 2 or more pieces. """ if self._check_if_playable(cell) >= 2: return True return False def _add(self, cell, player): """ GUI and backend management of plays without validity checks. Change the hex color. Set owner in board graph. Add move to correct player. Increment turn counter. :param cell: Tuple (x,y). :param player: :return: """ self.game_board.change_cell_color(cell, player.color) self.game_engine.set_owner(cell, player.number) player.hex_list.add(cell) player.move_list.append(cell) self.turns_played += 1 def _check_and_add(self, cell, player): """ GUI and backend management of plays without validity checks. Change the hex color. Set owner in board graph. Add move to correct player. Increment turn counter. Check if game has ended. :param cell: Tuple (x,y). :param player: :return: """ # Check for validity of the move if self._check_cell(cell): self.game_board.change_cell_color(cell, player.color) self.game_engine.set_owner(cell, player.number) player.hex_list.add(cell) player.move_list.append(cell) self.turns_played += 1 # If a few plays have been made start checking for game end. if len(self.player1.hex_list) >= 2 or len(self.player2.hex_list) >= 2: result = [] surrounded1, colinear1, surrounded2, colinear2 = self.game_engine.check_for_game_end( self.player1.hex_list, self.player2.hex_list, details=True) p0_won = surrounded1 or colinear1 p1_won = surrounded2 or colinear2 # Print message based on game result if p0_won: print("Player 1 has won!") result = (1, surrounded1, colinear1) self.game_ended = p0_won elif p1_won: print("Player 2 has won!") result = (2, surrounded2, colinear2) self.game_ended = p1_won elif p0_won and p1_won or (len(self.player1.hex_list) + len(self.player2.hex_list)) >= 50: print("Draw!") result = (0, -1, -1) self.game_ended = 1 # Save a small log file if self.game_ended: end_time = time.time() - self.start_time print("Game finished in {} seconds".format(end_time)) with h5py.File( os.path.join(save_config['root_dir'], 'log_{}.h5'.format(time.time())), 'w') as game_log: sess_id = str(len(game_log.keys())) session_log = game_log.create_group(sess_id) session_log.create_dataset(name='win', data=result) session_log.create_dataset(name='time', data=end_time) p1_log = session_log.create_group('p1') if self.player1.type == 'ai': p1_log.create_dataset(name='heuristic', data=self.player1.heuristic) p1_log.create_dataset(name='surrounded', data=surrounded1) p1_log.create_dataset(name='colinear', data=colinear1) p2_log = session_log.create_group('p2') if self.player2.type == 'ai': p2_log.create_dataset(name='heuristic', data=self.player2.heuristic) p2_log.create_dataset(name='surrounded', data=surrounded2) p2_log.create_dataset(name='colinear', data=colinear2) self.game_board.running = False def add_piece(self, cell, first=False): """ Add a stone on the board. No check if first pieces. Validity check afterwards. :param cell: Tuple (x,y). :param first: First turn or not :return: """ if self._get_turn() == 0: self._add(cell, self.player1) if first else self._check_and_add( cell, self.player1) else: self._add(cell, self.player2) if first else self._check_and_add( cell, self.player2) def _check_if_first_piece(self, cell): """ First piece must be played in the center of the board. HARDCODED for current board. :param cell: :return: """ # Center cell for standard board. Hardcoded center_cell = (16, 9) if self.turns_played == 0: center_nn = set(self.game_board.map.spread(center_cell, radius=1)) else: center_nn = set(self.game_board.map.spread(center_cell, radius=1)) player1_nn = set( self.game_board.map.spread(self.player1.move_list[0], radius=1)) center_nn = center_nn.intersection(player1_nn) if cell in center_nn and self._check_if_open(cell): self.add_piece(cell, True) def _get_turn(self): """ :return: Returns which player should make a move. """ return self.turns_played % 2 def play_piece(self, cell): """ Play a stone in a hex. Performa all validity checks. :param cell: Tuple (x,y). :return: """ if len(self.player1.move_list) == 0: self._check_if_first_piece(cell) elif len(self.player1.move_list) > 0 and len( self.player2.move_list) == 0: self._check_if_first_piece(cell) elif self._check_if_open(cell): self.add_piece(cell) def run(self): # main loop while self.game_board.running: self._run_func() if not self.game_board.running: "Save a capture of the final board state" pygame.image.save( self.game_board.window, os.path.join(save_config['root_dir'], "screenshot{}.jpg".format(time.time())))
class SingleGameScene(Scene): def __init__(self, window): super().__init__(window) self.player1_name = "Dark Conqueror" self.player2_name = "Knight of Light" self.game_keys = GAME_KEYS self.pressed_keys = {} for key in self.game_keys: self.pressed_keys[key] = False self.prev_pressed_keys = {} for key in self.game_keys: self.prev_pressed_keys[key] = False self.images = {} self.gui_textures = {self.player1_name: [], self.player2_name: []} self.init_gui_textures() self.player_name_font_size = 30 self.player_name_font = pygame.font.SysFont(None, self.player_name_font_size) self.does_menu = False self.menu = pygame_menu.Menu(title="Game menu", height=250, width=500, theme=pygame_menu.themes.THEME_DARK) self.menu.add.button("Quit", switch_to_menu, self.event_manager) self.engine = GameEngine(Player(self.player1_name), Player(self.player2_name)) self.end_time_frame_ended = get_time() self.fps_sys = FpsRenderSystem(window) self.end_time = None def draw(self, events): dt = (get_time() - self.end_time_frame_ended) * 1e-9 self.end_time_frame_ended = get_time() self.get_keys(events) game_state = self.engine.update(dt, self.pressed_keys) if game_state.has_ended and self.end_time is None: self.end_time = get_time() if self.end_time and (get_time() - self.end_time) * 1e-9 >= 1: game_state.should_exit = True self.event_manager.add_scene_change("game_over_scene") if game_state.looser == self.player1_name: self.event_manager.set_winner(self.player2_name) else: self.event_manager.set_winner(self.player1_name) return self.render_all(game_state.to_render, dt) self.render_gui(game_state) if self.does_menu and not self.pressed_keys[pygame.K_TAB]: if self.menu.is_enabled(): self.menu.update(events) self.menu.draw(self.window) def get_keys(self, events): for event in events: if event.type == pygame.KEYDOWN: key = event.key if key in self.game_keys: self.pressed_keys[key] = True if key == pygame.K_ESCAPE and not self.prev_pressed_keys[ key]: self.does_menu = not self.does_menu elif event.type == pygame.KEYUP: key = event.key if key in self.game_keys: self.pressed_keys[key] = False def render_all(self, sprites, dt): sprites.sort(key=lambda s: s.z) if sprites: for sprite in sprites: x = sprite.pos.x y = sprite.pos.y # if new, save to ram not to access disc every frame image_name = sprite.img_name if image_name not in self.images and image_name != 'tile.png': self.images[image_name] = pygame.image.load( os.path.join('assets/images/textures/', image_name)).convert_alpha() if sprite.size and sprite.fixed_size: self.images[image_name] = pygame.transform.scale( self.images[image_name], sprite.size) elif image_name == 'tile.png': self.images[image_name] = pygame.image.load( os.path.join('assets/images/textures/', image_name)).convert_alpha() self.images[image_name] = pygame.transform.scale( self.images[image_name], sprite.size) image = self.images[image_name] if sprite.size and not sprite.fixed_size: image = pygame.transform.scale(image, sprite.size) if not sprite.fixed_orient: image = pygame.transform.rotate( image, sprite.orient.to_angle_degrees()) # render render_pos = (int(x - image.get_width() / 2), int(y - image.get_height() / 2)) self.window.blit(image, render_pos) self.fps_sys.update(dt) def render_gui(self, game_state): for player in [self.player1_name, self.player2_name]: gui_elements = self.gui_textures[player] bg_pos = gui_elements[0][1] # background self.window.blit(*gui_elements[0]) # tank-avatar self.window.blit(gui_elements[1][0], (gui_elements[1][1][0] + bg_pos[0], gui_elements[1][1][1] + bg_pos[1])) # bullet-icon if game_state.shot_ready[player]: self.window.blit(gui_elements[2][0], (gui_elements[2][1][0] + bg_pos[0], gui_elements[2][1][1] + bg_pos[1])) else: self.window.blit(gui_elements[3][0], (gui_elements[3][1][0] + bg_pos[0], gui_elements[3][1][1] + bg_pos[1])) # hp full bar length = 170 thickness = 60 start_offset = (105, 70) start_point = [ bg_pos[0] + start_offset[0], bg_pos[1] + start_offset[1] ] end_point = [ bg_pos[0] + start_offset[0] + length, bg_pos[1] + start_offset[1] ] pygame.draw.line(self.window, pygame.color.Color(190, 150, 0), start_point, end_point, thickness) # hp current bar if game_state.curr_hp[player] == 0: continue hp_normalized = game_state.curr_hp[player] / game_state.max_hp[ player] start_point[0] += 5 end_point[0] = bg_pos[0] + start_offset[0] + length * hp_normalized end_point[0] -= 5 thickness = 50 pygame.draw.line(self.window, pygame.color.Color(140, 100, 0), start_point, end_point, thickness) # names if player == self.player1_name: img = self.player_name_font.render(self.player1_name, True, (0, 0, 0)) self.window.blit(img, (bg_pos[0] + 110, bg_pos[1] + 14)) else: img = self.player_name_font.render(self.player2_name, True, (0, 0, 0)) self.window.blit(img, (bg_pos[0] + 110, bg_pos[1] + 14)) def init_gui_textures(self): def load_image(p, name): return pygame.image.load(os.path.join(p, name)).convert_alpha() path_ = 'assets/images/textures/' tank_avatar_offset = (16, 15) bullet_offset = (67, 22) self.gui_textures[self.player1_name] = [ (load_image(path_, "gui-background.jpg"), (20, SCR_HEIGHT - 140)), (load_image(path_, "tank0avatar.png"), tank_avatar_offset), (load_image(path_, "bullet-icon-full.png"), bullet_offset), (load_image(path_, "bullet-icon-empty.png"), bullet_offset), ] self.gui_textures[self.player2_name] = [ (load_image(path_, "gui-background.jpg"), (SCR_WIDTH - (40 + 280), SCR_HEIGHT - 140)), (load_image(path_, "tank1avatar.png"), tank_avatar_offset), (load_image(path_, "bullet-icon-full.png"), bullet_offset), (load_image(path_, "bullet-icon-empty.png"), bullet_offset), ]
from engine.game_engine import GameEngine from gui.puzzle_gui import PuzzleWindow if __name__ == '__main__': game_engine = GameEngine() puzzle_window = PuzzleWindow() puzzle_window.set_engine(game_engine) puzzle_window.startRenderLoop()