class Window(pyglet.window.Window): def __init__(self, map_file, config_file): super().__init__(resizable=True, caption='Tourism Simulation', visible=False) self.set_minimum_size(640, 480) self.set_maximum_size(2260, 3540) self.frame_rate = 1 / 60.0 # Target frame-rate, usually can't keep up self.icon1 = pyglet.image.load('./graphics/Icon1.png') self.icon2 = pyglet.image.load('./graphics/Icon2.png') self.set_icon(self.icon1, self.icon2) self.map = Map(self.width, self.height, map_file) self.set_visible(True) self.x = 800 self.y = -800 self.simulation = Simulation(2260, 3540, self.width, self.height, config_file) def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): if (buttons & mouse.LEFT) or (buttons & mouse.MIDDLE): self.x = self.x + dx self.y = self.y + dy if self.x > 1120: self.x = 1120 pass if self.x < self.width - 1120: self.x = self.width - 1120 pass if self.y > 1760: self.y = 1760 pass pass if self.y < self.height - 1760: self.y = self.height - 1760 pass def update(self, dt): self.simulation.update(dt) def on_draw(self): self.clear() self.map.draw(self.width, self.height, self.x, self.y) self.simulation.draw(self.x, self.y, self.width, self.height)
class AppEngine(pyglet.window.Window): def __init__(self): bit_map = assets.generate_map() super().__init__(bit_map.shape[1] * settings.BLOCK_SIZE, bit_map.shape[0] * settings.BLOCK_SIZE + settings.BLOCK_SIZE * 3, "PAC-MAN", resizable=False) self.map = Map(bit_map) self.event_loop = pyglet.app.EventLoop() pyglet.clock.schedule_interval(self.update, 1 / 120.0) def on_key_press(self, symbol, modifiers): if symbol == key.ESCAPE: self.close() self.map.keypress(symbol) def update(self, dt): self.map.update(dt) def on_draw(self): self.clear() self.map.draw()
class Game: """ Starts the game loop. The main game loop consists of an event loop, the update loop (things updated every frame), and the draw loop. """ def __init__(self, network): """ Set up display and game map. Arguments: network {Network} -- Connection to server """ pygame.init() # Connection to the server self.network = network self.player_num = self.network.get_player_num() print("You are player", self.player_num) # Set up display window pygame.display.set_caption( "A Game of Shapes - Player " + str(self.player_num)) # NOTE: Display player num here? screen_res = (WINDOW_WIDTH, WINDOW_HEIGHT) self.screen = pygame.display.set_mode(screen_res, flags=pygame.RESIZABLE) # Set up font pygame.font.init() self.game_font = pygame.font.SysFont("Verdana", 60) # Set up gameplay map self.map = Map(self.screen, self.player_num) # Represents the state of game # Modified by server and sent to clients self.gamestate = self.network.get_gamestate() is_turn = self.gamestate.is_players_turn(self.player_num) # Effects of turn that are sent across network self.turn = {"move": None, "attack": None, "phase": NOT_TURN} # Let the starting player begin moving units if is_turn: self.turn["phase"] = SELECT_UNIT_TO_MOVE # Clock tracks time from beginning of game self.clock = pygame.time.Clock() # Keep track of user's cursor. Updates every frame self.mouse_position = pygame.mouse.get_pos() # Show waiting screen until other player connects self.waiting_screen() # Start the game self.game_loop() def game_loop(self): """ Loop until window is closed. """ while True: self.event_loop() self.update() self.draw() def event_loop(self): """ Handle user input. Events include mouse clicks and keyboard presses. """ events = pygame.event.get() for event in events: # Client closes window if event.type == pygame.QUIT: self.exit_game() # User hovers over tile if event.type == pygame.MOUSEMOTION: self.map.handle_hover(self.mouse_position) # Only process clicks if it's this player's turn if self.gamestate.is_players_turn(self.player_num): # User is placing tiles if self.turn["phase"] == PLACE_TILES: pass else: # Attack! # User clicks button if event.type == pygame.MOUSEBUTTONDOWN: self.turn = self.map.handle_click( self.mouse_position, self.turn) # User presses a key # TODO: Delete or implement keydown elif event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: self.turn["phase"] == ATTACKING def update(self): """ Update variables that change every frame. """ self.time = self.clock.tick(60) self.mouse_position = pygame.mouse.get_pos() # Other player's turn if self.turn["phase"] == NOT_TURN: players_turn = self.network.request_turn() if players_turn == self.player_num: self.update_gamestate() self.turn["phase"] = SELECT_UNIT_TO_MOVE # Check if turn ended if self.turn["phase"] == END_TURN: # Send moves and attacks made to server self.network.send_turn(self.turn) self.gamestate.change_turns() self.turn["phase"] = NOT_TURN # Check if someone has won if self.gamestate.game_is_over: self.gameover() def update_gamestate(self): """ Pull in new information from server and apply changes. """ new_gamestate = self.network.get_gamestate() self.update_health(new_gamestate) self.update_positions(new_gamestate) self.turn["attack"] = None self.turn["move"] = None self.gamestate = new_gamestate def update_health(self, new_gamestate): """ Update units with any health changes. """ if new_gamestate.unit_health != self.gamestate.unit_health: for unit_type, health in new_gamestate.unit_health.items(): unit = self.map.get_unit_by_type(unit_type) if unit: unit.change_health(health) if not unit.is_alive: self.map.kill_unit(unit) def update_positions(self, new_gamestate): """ Update units with changes in position. """ if new_gamestate.unit_locations != self.gamestate.unit_locations: # Update map with any moved units for unit_type, location in new_gamestate.unit_locations.items(): if location: col, row = location unit = self.map.get_unit_by_type(unit_type) self.map.move(unit, col, row) def draw(self): """ Draw graphics and display on screen. """ self.screen.fill(colors.lightgray) # Display player statistics self.display_statistics() self.display_help() # Display game board self.map.draw() pygame.display.update() def display_statistics(self): """ Display player information. """ #TODO: Generalize the placement of text. # Create function for reused code. # Set alignment of text. # Font size is equal to line spacing SIZE = 20 font = pygame.font.SysFont("Verdana", SIZE) # Display player turn is_turn = self.gamestate.is_players_turn(self.player_num) turn_text = "" text_color = "" if is_turn: turn_text = "Your Turn" text_color = colors.darkgreen else: turn_text = "Enemy Turn" text_color = colors.darkred textsurface = font.render(turn_text, False, text_color) text_rect = textsurface.get_rect(center=[WINDOW_WIDTH / 2, SIZE * 3]) self.screen.blit(textsurface, text_rect) # Display unit statistics if self.player_num == 1: # Display "Unit Information" location = [20, SIZE * 5] # Beginning of unit info. textsurface = font.render("Your Units", False, colors.white) self.screen.blit(textsurface, location) for unit in self.map.players_units: # Increment horizontal placement location[1] += SIZE health = str(unit.health) + "/" + str(unit.max_health) textsurface = font.render(unit.archetype + ": " + health, False, unit.color) self.screen.blit(textsurface, location) # Display "Enemy Unit Information" location = [self.screen.get_width() - 150, SIZE * 5] # Beginning of unit info. textsurface = font.render("Enemy Units", False, colors.white) self.screen.blit(textsurface, location) for unit in self.map.enemy_units: # Increment horizontal placement location[1] += SIZE health = str(unit.health) + "/" + str(unit.max_health) textsurface = font.render(unit.archetype + ": " + health, False, unit.color) self.screen.blit(textsurface, location) elif self.player_num == 2: # Display "Unit Information" location = [self.screen.get_width() - 150, SIZE * 5] # Beginning of unit info. textsurface = font.render("Your Units", False, colors.white) self.screen.blit(textsurface, location) for unit in self.map.players_units: # Increment horizontal placement location[1] += SIZE health = str(unit.health) + "/" + str(unit.max_health) textsurface = font.render(unit.archetype + ": " + health, False, unit.color) self.screen.blit(textsurface, location) # Display "Enemy Information" location = [20, SIZE * 5] # Beginning of unit info. textsurface = font.render("Enemy Units", False, colors.white) self.screen.blit(textsurface, location) for unit in self.map.enemy_units: # Increment horizontal placement location[1] += SIZE health = str(unit.health) + "/" + str(unit.max_health) textsurface = font.render(unit.archetype + ": " + health, False, unit.color) self.screen.blit(textsurface, location) def display_help(self): """ Display help text. """ LOCATION = [0, WINDOW_HEIGHT - 25] SIZE = 16 font = pygame.font.SysFont("Verdana", SIZE) phase_text = "" # Change help text based on phase if self.turn["phase"] == SELECT_UNIT_TO_MOVE: phase_text = "HELP: Select a unit by clicking on it with your mouse." elif self.turn["phase"] == MOVING: phase_text = "HELP: Choose a tile to move your unit or click on the unit to deselect." elif self.turn["phase"] == ATTACKING: phase_text = "HELP: Attack by clicking an emeny unit" textsurface = font.render(phase_text, False, colors.white) self.screen.blit(textsurface, LOCATION) def waiting_screen(self): """ Display a waiting message until other client connects. """ self.network.send_command("start") reply = self.network.receive() self.gamestate = self.network.get_gamestate() while not self.gamestate.ready(): # Update events so window can be closed events = pygame.event.get() for event in events: if event.type == pygame.QUIT: self.exit_game() # Display waiting text self.screen.fill(colors.darkgray) textsurface = self.game_font.render("Waiting for player 2...", False, colors.white) text_rect = textsurface.get_rect(center=(WINDOW_CENTER)) self.screen.blit(textsurface, text_rect) pygame.display.update() # Update gamestate to check if other player is connected self.gamestate = self.network.get_gamestate() def gameover(self): self.network.send_turn(self.turn) # Loop until player resets or quits # while not self.gamestate.ready(): while True: # Show text and how to reset self.display_endgame_results() events = pygame.event.get() for event in events: if event.type == pygame.QUIT: self.exit_game() # Press space to restart or esc to exit if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: # Tell server that you're ready self.network.send_command("start") elif event.key == pygame.K_ESCAPE: self.exit_game() # Update gamestate to check if other player is ready self.gamestate = self.network.get_gamestate() # Clear the map self.map.reset() # Determine turn to start back with is_turn = self.gamestate.is_players_turn(self.player_num) if is_turn: self.turn["phase"] = SELECT_UNIT_TO_MOVE def display_endgame_results(self): """ Display winning/losing text. """ self.screen.fill(colors.lightgray) # Show results if self.gamestate.winner == self.player_num: textsurface = self.game_font.render("You won!", False, colors.darkgreen) else: textsurface = self.game_font.render("You lost...", False, colors.darkred) text_rect = textsurface.get_rect(center=(WINDOW_CENTER)) self.screen.blit(textsurface, text_rect) #TODO: display endgame statistics slightly differently self.display_statistics() pygame.display.update() def exit_game(self): print("Exiting game...") self.network.close() pygame.quit() sys.exit(0)
class Game(object): def __init__(self, screen, tutorialMenu, fakeNewsMenu, saveFile=None): self.isRunning = False if saveFile is None: self.map = Map("assets/maps/default.json") self.player = Player() else: self.load(saveFile) self.openMenu = "[Esc] Open Menu" self.openMenu = screen.fonts["25"].render(self.openMenu, 1, (255, 255, 255)) self.closeMenu = "[Esc] Close Menu" self.closeMenu = screen.fonts["25"].render(self.closeMenu, 1, (255, 255, 255)) self.ennemyController = EnnemyController(5) button_help = Button((700, 300), (300, 60), "How to Build Walls", tutorialMenu.run, screen=screen) button_help.build(screen) button_fakeNewsMenu = Button((1100, 300), (300, 60), "Fake News", fakeNewsMenu.run, screen=screen) button_fakeNewsMenu.build(screen) button_quit = Button((1500, 300), (300, 60), "Quit", self.stop) button_quit.build(screen) self.pauseMenu = Menu(None, [button_help, button_fakeNewsMenu, button_quit], True) self.winMenu = Menu(pygame.image.load("assets/img/youWon.jpg"), [], True) button_continue = Button((10, 1000), (300, 60), "4 Years Later >>", self.winMenu.stop) button_continue.build(screen) self.winMenu.buttons.append(button_continue) button_quit = Button((10, 1000), (300, 60), "Quit Because I'm Bad", exit) button_quit.build(screen) self.loseMenu = Menu(pygame.image.load("assets/img/youLose.jpg"), [button_quit], True) button_continue = Button((400, 1000), (300, 60), "Continue & Sue Bedin", self.loseMenu.stop) button_continue.build(screen) self.loseMenu.buttons.append(button_continue) self.invocations = [] self.twats = [] button_resume = Button((300, 300), (300, 60), "Resume", self.pauseMenu.stop) button_resume.build(screen) self.pauseMenu.buttons.append(button_resume) self.gameEndTime = cst.GAME_TIME self.ballots = { "republican": Ballot((1800, 20), "assets/img/republican.png"), "democrat": Ballot((1800, 140), "assets/img/democrat.png"), } def load(self, saveFile): """ Loads the game from a save file, creates an empty game if the save is None """ save = json.load(open(saveFile, "r")) self.map = Map(save['map']) self.player = Player(save['player']) def update(self, screen): self.gameEndTime = int(self.gameEndTime - screen.timeElapsed) if self.gameEndTime <= 0: if self.ballots["republican"].votes > self.ballots[ "democrat"].votes: self.winMenu.run(screen) else: button_info = Button((100, 800), ( 700, 60 ), f'You : {self.ballots["republican"].votes} - Bedin : {self.ballots["democrat"].votes}', exit) button_info.build(screen) button_info.clickable = False self.loseMenu.buttons.append(button_info) self.loseMenu.run(screen) self.stop() if self.player.popularity < 20: button_info = Button( (100, 800), (500, 60), f"Your popularity went below 20% ... You Bad Boy", exit) button_info.build(screen) button_info.clickable = False self.loseMenu.buttons.append(button_info) self.loseMenu.run(screen) self.stop() for event in screen.events(): action = self.player.eventUpdate(event) if action == "HIT": self.ennemyController.hit(self.player.hitbox, self.player.damage) elif action == "KAMEHAMEHA": self.ennemyController.hit(self.player.hitbox, 50) elif action == "BUILDWALL": self.invocations.append( Wall([ self.player.position[0] + 205, self.player.position[1] ])) if event.type == pygame.locals.KEYDOWN: if event.key == pygame.locals.K_ESCAPE: self.pauseMenu.run(screen, self) for inv in self.invocations[:]: result = inv.update(self.ennemyController) if result == "DEAD": del self.invocations[self.invocations.index(inv)] self.player.update(screen, self.ennemyController, self.invocations, self.twats) for twat in self.twats[:]: result = twat.update(screen) if result == "DEAD": del self.twats[self.twats.index(twat)] deaths, baddeaths, democrat_votes, republican_votes = self.ennemyController.update( screen, self.player.popularity) self.player.addSpecialAttack(deaths * 5) for baddeath in range(baddeaths): twat = Twat(screen, [random.randint(200, 1400), random.randint(30, 600)]) self.twats.append(twat) self.player.popularity -= twat.rt * 0.1 self.player.updatePopularity(screen) self.player.popularity += deaths * 0.2 self.player.updatePopularity(screen) for key, ballot in self.ballots.items(): if key == "democrat": ballot.add_votes(democrat_votes) elif key == "republican": ballot.add_votes(republican_votes) ballot.update(screen) def draw(self, screen): self.map.draw(screen, self.player) self.ennemyController.draw(screen) for inv in self.invocations: inv.draw(screen) self.player.draw(screen) for twat in self.twats: twat.draw(screen) for key, ballot in self.ballots.items(): ballot.draw(screen) def stop(self): self.isRunning = False self.pauseMenu.stop() def getTimeDisplay(self): return str(datetime.timedelta(seconds=self.gameEndTime)) def run(self, screen): self.isRunning = True while self.isRunning: self.update(screen) self.draw(screen) screen.blit(self.openMenu, (10, 10)) self.gameEndTimeDisplay = screen.fonts["75"].render( self.getTimeDisplay(), 0, (255, 255, 255)) screen.blit(self.gameEndTimeDisplay, (10, 30)) screen.flip()