def test_hex_to_pixel(self): """Test hex to pixel.""" hexagon = Hex(0, 1, -1) pointy = Layout(10, (200, 200)) self.assertEqual(pointy.hex_to_pixel(hexagon), (208.6602540378444, 215.0))
class Game: """Class to represent client-side rendering of the game.""" def __init__(self, game_state, logger, server_api): """Initialise display surface.""" self._server_api = server_api pygame.init() pygame.font.init() civ_borders = [ "civ1_border", "civ2_border", "civ3_border", "civ4_border" ] self._shutdown = False self._threads = [] self._game_state = game_state self._civ_colours = dict( (civ, colour) for (civ, colour) in zip(sorted(self._game_state.civs), civ_borders)) self._flags = (pygame.DOUBLEBUF | pygame.HWSURFACE) self.infoObject = pygame.display.Info() self._window_size = (self.infoObject.current_w, self.infoObject.current_h) self._camera_position = (self._window_size[0] / 2, self._window_size[1] / 2) self._screen = pygame.display.set_mode(self._window_size, self._flags, 0) hud_flags = (pygame.HWSURFACE | pygame.SRCALPHA) self._hud_surface = pygame.Surface(self._window_size, hud_flags) self._hud_quick_surface = pygame.Surface(self._window_size, hud_flags) self._font = 'freesansbold.ttf' self._font_size = 115 self._zoom = 30 self._zoom_interval = 5 self._min_zoom = 1 self._max_zoom = 40 self._hex_size = lambda x: (self.infoObject.current_w // x) self._select_menu = SelectMenu(self._screen) self._menu_displayed = False self._music_player = Music( "../resources/music/Egmont_Overture_Op_84.mp3") self._music_playing = True self._main_menu_options = [("Resume", self.close_main_menu), ("Toggle Music", self.toggle_music), ("Exit", self.quit)] self._main_menu = Menu(self._screen, self._main_menu_options) self._main_menu_displayed = False self._grid = self._game_state.grid self._layout = Layout(self._hex_size( self._zoom), (self._window_size[0] / 2, self._window_size[1] / 2)) self._hud = HudOverlay(self._game_state, self._hud_surface, self._hud_quick_surface, self._window_size, self._layout) self._load_images = LoadImages() self._scaled_terrain_images = \ self._load_images.load_terrain_images().copy() self._scaled_sprite_images = \ self._load_images.load_sprite_images().copy() self._scaled_building_images = \ self._load_images.load_building_images().copy() self._scaled_health_bar_images = \ self._load_images.load_health_bar_images().copy() self._scaled_resource_images = \ self._load_images.load_resource_images().copy() self._currently_selected_object = None self._currently_selected_tile = None self._current_available_moves = {} def start(self): """Initialize the game.""" self.scale_images_to_hex_size() self.scale_sprites_to_hex_size() self.scale_buildings_to_hex_size() self.scale_resources_to_hex_size() self._music_player.play() self.draw_map() count = 0 t = threading.Thread(group=None, target=self.render_hud, name="HUD_render", args=(), daemon=True) self._threads.append(t) t.start() while True: self.check_for_events() time.sleep(0.004) count += 1 if count == 100: count = 0 self.draw_map() def check_for_events(self): """Check for mouse and keyboard events.""" for event in pygame.event.get(): # something happened if event.type == pygame.QUIT: self.quit() elif event.type == pygame.KEYDOWN: pressed = pygame.key.get_pressed() if pressed[pygame.K_ESCAPE]: self._main_menu_displayed = True if pressed[306] == 1 and pressed[99] == 1: # 306 CTRL,99 C self.quit() elif pressed[32] == 1: self._server_api.end_turn() if event.type == pygame.MOUSEBUTTONDOWN: self.mouse_button_down(event) if event.type == pygame.MOUSEBUTTONUP: self.mouse_button_up(event) def quit(self): """Close game.""" for thread in self._threads: self._shutdown = True thread.join() sys.exit() def close_main_menu(self): """ Close the main menu """ self._main_menu_displayed = False def toggle_music(self): """ Pause the background music. """ if self._music_playing: self._music_player.pause() self._music_playing = False else: self._music_player.unpause() self._music_playing = True def mouse_button_down(self, event): """ Perform an action depending on the mouse event taking place. :param event: a user inputted event. """ if event.button == 1: # Left click self.panning() elif event.button == 2: # Middle click pass elif event.button == 3: # Right click pass elif event.button == 4: # Scroll up self.zoom_in() elif event.button == 5: # Scroll down self.zoom_out() def mouse_button_up(self, event): """ Perform an action depending on the mouse event taking place. :param event: a user inputted event. """ if event.button == 1: # Left click pass elif event.button == 2: # Middle click pass elif event.button == 3: # Right click if self._main_menu_displayed: click = pygame.mouse.get_pos() self._main_menu.menu_click(click) self.select_object(self._layout) def panning(self): """ Pan around the map. Method that allows the user to move around the map while the left mouse button is being held down. """ pygame.mouse.get_rel() if self._menu_displayed: self._menu_displayed = False self._currently_selected_object = False holding = True while holding: pygame.event.get() change = pygame.mouse.get_rel() c_hex = self._layout.pixel_to_hex(self._camera_position) c_hex_coords = self._grid.hex_round((c_hex.x, c_hex.y, c_hex.z)) wrap = self._grid.get_hextile(c_hex_coords) if (wrap.x, wrap.y, wrap.z) != c_hex_coords: pix_change = self._layout.hex_to_pixel(wrap) change = (self._camera_position[0] - pix_change[0], self._camera_position[1] - pix_change[1]) self._layout.change_origin(change) self.draw_map() holding = pygame.mouse.get_pressed()[0] def zoom_in(self): """ Zoom in method. Method that allows the user to zoom in when the scroll wheel is used. """ self._zoom -= self._zoom_interval if self._zoom <= self._min_zoom: self._zoom = self._min_zoom else: self._layout.size = self._hex_size(self._zoom) self.scale_images_to_hex_size() self.scale_sprites_to_hex_size() self.scale_buildings_to_hex_size() self.scale_resources_to_hex_size() self.draw_map() def zoom_out(self): """ Zoom out method. Method that allows the user to zoom out when the scroll wheel is used. """ self._zoom += self._zoom_interval if self._zoom >= self._max_zoom: self._zoom = self._max_zoom else: self._layout.size = self._hex_size(self._zoom) self.scale_images_to_hex_size() self.scale_sprites_to_hex_size() self.scale_buildings_to_hex_size() self.scale_resources_to_hex_size() self.draw_map() def select_object(self, layout): """ Select a unit or city and display the menu options. :param layout: The layout object being used """ click = pygame.mouse.get_pos() c_hex = layout.pixel_to_hex(click) c_hex_coords = self._grid.hex_round((c_hex.x, c_hex.y, c_hex.z)) hexagon = self._grid.get_hextile(c_hex_coords) if self._menu_displayed: self._menu_displayed = False self._select_menu.menu_click(click) else: if hexagon in self._current_available_moves: self._server_api.move_unit(self._currently_selected_object, hexagon) self._game_state.get_civ( self._game_state.my_id).calculate_vision() self._currently_selected_object = None self._current_available_moves = {} self._currently_selected_tile = None elif isinstance(self._currently_selected_object, Soldier) \ and hexagon.unit != self._currently_selected_object \ and hexagon.unit is not None: self._server_api.attack(self._currently_selected_object, hexagon.unit) elif hexagon.unit not in [None, self._currently_selected_object] \ and hexagon.unit.civ_id == self._game_state.my_id: self._currently_selected_object = hexagon.unit self.unit_menu(layout) elif hexagon.building is not None: if hexagon.building.building_type == BuildingType.CITY \ and hexagon.building.civ_id == self._game_state.my_id: self._currently_selected_object = hexagon.building self.city_menu() def highlight_selected_movement(self, layout): """ Highlight tiles that can be moved to by currently selected unit. :param layout: The Layout object being drawn on :return: """ for k in self._current_available_moves: hexagon_coords = layout.hex_to_pixel(k) self._screen.blit( self._scaled_terrain_images["move-highlight"], (hexagon_coords[0] - math.ceil(layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - layout.size)) def unit_menu(self, layout): """ Create a menu pertaining to unit actions. :param layout: Layout object being drawn on. """ unit = self._currently_selected_object click = pygame.mouse.get_pos() c_hex = layout.pixel_to_hex(click) c_hex_coords = self._grid.hex_round((c_hex.x, c_hex.y, c_hex.z)) hexagon = self._grid.get_hextile(c_hex_coords) self._current_available_moves = {} def move_unit(): """Move a unit and redraw the map.""" self._current_available_moves = self._grid.dijkstra( hexagon, unit.movement_range) self.draw_map() def build_city(): """Build a city and redraw the map.""" self._server_api.build_city(unit) self._game_state.get_civ(self._game_state.my_id).calculate_vision() self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() def build_farm(): """Build a farm and redraw the map.""" self._server_api.build(unit, BuildingType.FARM) self._game_state.get_civ(self._game_state.my_id).calculate_vision() self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() def build_trade_post(): """Build a trade post and redraw the map.""" self._server_api.build(unit, BuildingType.TRADE_POST) self._game_state.get_civ(self._game_state.my_id).calculate_vision() self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() def build_uni(): """Build a university and redraw the map.""" self._server_api.build(unit, BuildingType.UNIVERSITY) self._game_state.get_civ(self._game_state.my_id).calculate_vision() self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() def work_resource(): """Work a resource and redraw the map.""" self._server_api.work_resource(unit) self._game_state.get_civ(self._game_state.my_id).calculate_vision() self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() if self._menu_displayed is False: self._menu_displayed = True if unit.__class__.__name__ == "Worker": if unit.position.building is not None: self._select_menu.set_options(click, [("Move", move_unit)]) elif unit.position.terrain.resource is None: self._select_menu.set_options( click, [("Move", move_unit), ("Build City", build_city), ("Build Farm", build_farm), ("Build Trade Post", build_trade_post), ("Build Uni", build_uni)]) elif unit.position.terrain.resource is not None and \ unit.position.terrain.resource._is_worked is False: self._select_menu.set_options( click, [("Move", move_unit), ("Work Resource", work_resource)]) else: self._select_menu.set_options(click, [("Move", move_unit)]) else: self._select_menu.set_options(click, [("Move", move_unit)]) def city_menu(self): """ Create a menu pertaining to city actions. :param layout: Layout object being drawn on. """ city = self._currently_selected_object click = pygame.mouse.get_pos() self._current_available_moves = {} def buy_archer(): """Buy an archer and redraw the map.""" self._server_api.purchase(city, Archer, 1) self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() def buy_worker(): """Buy an worker and redraw the map.""" self._server_api.purchase(city, Worker, 1) self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() def buy_swordsman(): """Buy an swordsman and redraw the map.""" self._server_api.purchase(city, Swordsman, 1) self._currently_selected_object = None self._currently_selected_tile = None self.draw_map() if self._menu_displayed is False: self._menu_displayed = True self._select_menu.set_options(click, [("Buy Archer", buy_archer), ("Buy Swordsman", buy_swordsman), ("Buy Worker", buy_worker)]) def scale_images_to_hex_size(self): """ Scale images. Takes each image in the terrain_images dictionary, scales it to the current hex_size, then stores the new image in a copy of the dictionary to preserve image quality. """ for k in self._load_images.load_terrain_images(): self._scaled_terrain_images[k] = pygame.transform.smoothscale( self._load_images.load_terrain_images()[k], (math.ceil( (self._hex_size(self._zoom) * 2) * math.sqrt(3) / 2), self._hex_size(self._zoom) * 2)) def scale_sprites_to_hex_size(self): """ Scale sprites. Takes each sprite in the sprite_images dictionary, scales it to the current hex_size, then stores the new image in a copy of the dictionary to preserve image quality. """ adjusted_size = math.floor(1800 / self._zoom) for k in self._load_images.load_sprite_images(): self._scaled_sprite_images[k] = pygame.transform.smoothscale( self._load_images.load_sprite_images()[k], (adjusted_size, adjusted_size)) for k in self._load_images.load_health_bar_images(): self._scaled_health_bar_images[k] = pygame.transform.smoothscale( self._load_images.load_health_bar_images()[k], (adjusted_size, adjusted_size)) for l in self._load_images.load_resource_images(): self._scaled_resource_images[l] = pygame.transform.smoothscale( self._load_images.load_resource_images()[l], (adjusted_size, adjusted_size)) def scale_resources_to_hex_size(self): """ Take each sprite in the sprite_images dictionary. scales it to the current hex_size, then stores the new image in a copy of the dictionary to preserve image quality. """ adjusted_size = math.floor(1800 / self._zoom) for k in self._load_images.load_resource_images(): self._scaled_resource_images[k] = pygame.transform.smoothscale( self._load_images.load_resource_images()[k], (adjusted_size, adjusted_size)) def scale_buildings_to_hex_size(self): """ Scale sprites. Takes each sprite in the sprite_images dictionary, scales it to the current hex_size, then stores the new image in a copy of the dictionary to preserve image quality. """ adjusted_size = math.floor(1800 / self._zoom) for k in self._load_images.load_building_images(): self._scaled_building_images[k] = pygame.transform.smoothscale( self._load_images.load_building_images()[k], (adjusted_size, adjusted_size)) def draw_building(self, hexagon_coords, sprite): """ Draw sprite on hextile terrain. :param hexagon_coords: the coordinates of the center of the hexagon. :param sprite: the sprite image to draw. """ center_x, center_y = hexagon_coords offset = 1800 / (self._zoom * 2) self._screen.blit(sprite, (floor(center_x - offset), floor(center_y - offset))) def draw_sprite(self, hexagon_coords, sprite): """ Draw sprite on hextile terrain. :param hexagon_coords: the coordinates of the center of the hexagon. :param sprite: the sprite image to draw. """ center_x, center_y = hexagon_coords offset = 1800 / (self._zoom * 2) self._screen.blit(sprite, (floor(center_x - offset), floor(center_y - offset))) def draw_hex_grid(self, layout): """ Draw the hexgrid. Draws all currently visible hextiles to the screen, along with any units or structures contained on those tiles. :param layout: The layout of the grid to draw. Either the main layout or one of it's mirrors. """ my_civ = self._game_state.get_civ(self._game_state.my_id) my_vision = my_civ.vision size = pygame.display.get_surface().get_size() for hex_point in self._grid.get_hextiles(): hexagon = self._grid.get_hextile(hex_point) hexagon_coords = layout.hex_to_pixel(hexagon) if size[0] + 100 > hexagon_coords[0] > -100 and\ size[1] + 100 > hexagon_coords[1] > -100: terrain = hexagon.terrain terrain_image = self._scaled_terrain_images[( terrain.terrain_type.value, terrain.biome.value)] self._screen.blit( terrain_image, (hexagon_coords[0] - math.ceil(self._layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - self._layout.size)) if hexagon.civ_id is not None: self._screen.blit( self._scaled_terrain_images[self._civ_colours[ hexagon.civ_id]], (hexagon_coords[0] - math.ceil(self._layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - self._layout.size)) if hexagon.building is not None: build = hexagon.building hexagon_coords = layout.hex_to_pixel(hexagon) self.draw_building( hexagon_coords, self._scaled_building_images[build.building_type]) if hexagon.terrain.resource is not None: resource = hexagon.terrain.resource hexagon_coords = layout.hex_to_pixel(hexagon) if resource._is_worked is True: if resource.resource_type is ResourceType.COAL: image_key = "W_COAL" elif resource.resource_type is ResourceType.IRON: image_key = "W_IRON" elif resource.resource_type is ResourceType.LOGS: image_key = "W_LOGS" elif resource.resource_type is ResourceType.GEMS: image_key = "W_GEMS" else: image_key = resource.resource_type self.draw_sprite(hexagon_coords, self._scaled_resource_images[image_key]) if hexagon.unit is not None and hexagon in my_vision: unit = hexagon.unit unit_level = unit.level unit_health = unit.get_health_percentage() hexagon_coords = layout.hex_to_pixel(unit.position) self._screen.blit( self._scaled_terrain_images[self._civ_colours[ unit.civ_id]], (hexagon_coords[0] - math.ceil(self._layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - self._layout.size)) self.draw_sprite( hexagon_coords, self._scaled_sprite_images[unit.__class__.__name__ + str(unit_level)]) self.draw_sprite( hexagon_coords, self._scaled_health_bar_images[unit_health]) if hexagon not in my_vision: self._screen.blit( self._scaled_terrain_images["fogofwar"], (hexagon_coords[0] - math.ceil(self._layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - self._layout.size)) def get_mirrors(self): """Store each hexgrid mirror layout in a list.""" mirror_centers = self._grid.mirrors layouts = [] for mirror in mirror_centers: layout = Layout( self._layout.size, self._layout.hex_to_pixel(Hex(mirror[0], mirror[1], mirror[2]))) layouts.append(layout) return layouts def draw_map(self): """ Draw the current instance of the hex grid to the screen. Also draws the hexgrid mirrors. """ if not self._main_menu_displayed: self._screen.fill((0, 0, 0)) self.draw_hex_grid(self._layout) layouts = self.get_mirrors() for layout in layouts: self.draw_hex_grid(layout) self.highlight_selected_movement(self._layout) for layout in layouts: self.highlight_selected_movement(layout) self._screen.blit(self._hud_surface, (0, 0)) self._hud.draw_quick_surface(layouts) self._screen.blit(self._hud_quick_surface, (0, 0)) pygame.display.flip() if self._menu_displayed: self._select_menu.display_menu() else: self._main_menu.display_menu() def render_hud(self): """Render heads up display.""" while not self._shutdown: self._hud.draw() time.sleep(1)
class HudOverlay: """Class to represent a HUD Overlay.""" def __init__(self, game_state, screen_surface, quick_surface, resolution, layout): """ Construct hud_overlay. :param game_state: ref to current game state object. :param screen_surface: pygame display surface. :param resolution: tuple or screen resolution (w, h). """ self._game_state = game_state self._grid = game_state.grid self._myciv = game_state.get_civ(self._game_state.my_id) self._screen = screen_surface self._quick_surface = quick_surface self._resolution = resolution self._layout = layout civ = game_state.get_civ(game_state.my_id) self._GUI_tree = TreeGUI(quick_surface, civ.tree) self.font = pygame.font.Font('freesansbold.ttf', 12) path = "../resources/images/hud/" x, y = 50, 50 self._hud_images = { CurrencyType.GOLD: self._load_img(path + "gold_logo.png", x, y), CurrencyType.FOOD: self._load_img(path + "food_logo.png", x, y), CurrencyType.SCIENCE: self._load_img(path + "science_logo.png", x, y), ResourceType.GEMS: self._load_img(path + "gems.png", x, y), ResourceType.LOGS: self._load_img(path + "logs.png", x, y), ResourceType.COAL: self._load_img(path + "coal.png", x, y), ResourceType.IRON: self._load_img(path + "iron.png", x, y), 0: self._load_img(path + "research_logo.png", (x - (x // 5) - (x // 10)), (y - (y // 10))), 1: self._load_img(path + "research_background.png", x, y), 2: self._load_img(path + "button_disabled.png", x * 2, y), 3: self._load_img(path + "button_active.png", x * 2, y) } path = "../resources/images/tiles/" scale = round(200 / self._grid.size) x, y = math.ceil((scale * 2 * math.sqrt(3) / 2)), scale * 2 self._map_layout = Layout(scale, (200, self._resolution[1] - 170)) self.map_imgs = { (0, 0): self._load_img(path + "tundra_flat.png", x, y), (0, 1): self._load_img(path + "grassland_flat.png", x, y), (0, 2): self._load_img(path + "desert_flat.png", x, y), (1, 0): self._load_img(path + "tundra_hill.png", x, y), (1, 1): self._load_img(path + "grassland_hill.png", x, y), (1, 2): self._load_img(path + "desert_hill.png", x, y), (2, 0): self._load_img(path + "tundra_mountain.png", x, y), (2, 1): self._load_img(path + "grassland_mountain.png", x, y), (2, 2): self._load_img(path + "desert_mountain.png", x, y), (3, 0): self._load_img(path + "ocean.png", x, y), (3, 1): self._load_img(path + "ocean.png", x, y), (3, 2): self._load_img(path + "ocean.png", x, y), 0: self._load_img(path + "view-highlight.png", x, y) } self._background = (74, 74, 74) self._color1 = (0, 0, 0) self._color2 = (255, 255, 255) self._color3 = (124, 252, 0) def _load_img(self, img, size_w, size_h): image = pygame.image.load(img).convert_alpha() return self._img_scale(image, size_w, size_h) def _img_scale(self, img, size_w, size_h): return pygame.transform.smoothscale(img, (size_w, size_h)) def draw(self): """Draw all HUD elements.""" self._screen.fill((0, 0, 0, 0)) self.draw_resource_panel() self.draw_info_panel() self.draw_minimap() self.draw_button_panel() def draw_quick_surface(self, layouts): """Draw quick moving HUD elements.""" self._quick_surface.fill((0, 0, 0, 0)) self.draw_view(layouts) def draw_view(self, layouts): """Draw box showing current view.""" self.highlight_view(self._layout) for layout in layouts: self.highlight_view(layout) def highlight_view(self, layout): """Highlight viewed tiles.""" size = pygame.display.get_surface().get_size() image = self.map_imgs[0] for hex_point in self._grid.get_hextiles(): hexagon = self._grid.get_hextile(hex_point) hexagon_coords = layout.hex_to_pixel(hexagon) if (size[0] + 100 > hexagon_coords[0] > -100 and size[1] + 100 > hexagon_coords[1] > -100): hexagon_coords = self._map_layout.hex_to_pixel(hexagon) self._quick_surface.blit( image, (hexagon_coords[0] - math.ceil(self._map_layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - self._map_layout.size)) def draw_resource_panel(self): """Draw resource panel.""" mapresources = self._myciv.resources resources = { CurrencyType.GOLD: self._myciv.gold, CurrencyType.FOOD: self._myciv.food, CurrencyType.SCIENCE: self._myciv.science, ResourceType.GEMS: mapresources[ResourceType.GEMS], ResourceType.LOGS: mapresources[ResourceType.LOGS], ResourceType.COAL: mapresources[ResourceType.COAL], ResourceType.IRON: mapresources[ResourceType.IRON] } points = [(450, 0), (0, 0), (0, 60), (430, 60), (450, 40)] pygame.draw.polygon(self._screen, self._background, points, 0) offset = 10 for resource in resources: value = resources[resource] if value is not None: logo = self._hud_images[resource] self._screen.blit(logo, (offset, 5)) self.draw_text(value, (offset + 5, 30), self._color2) offset += 60 def draw_info_panel(self): """Draw info panel containing turn details and ping.""" points = [(self._resolution[0] - 240, 0), (self._resolution[0], 0), (self._resolution[0], 40), (self._resolution[0] - 220, 40), (self._resolution[0] - 240, 20)] pygame.draw.polygon(self._screen, self._background, points, 0) offset = self._resolution[0] - 200 turn_count = self._game_state.turn_count self.draw_text("Turn: {}".format(turn_count), (offset, 20), self._color2) offset += 80 my_turn = self._game_state.my_turn if my_turn: color = self._color3 else: color = self._color2 value = "Player{}\'s Turn".format(self._game_state._current_player) self.draw_text(value, (offset + 20, 20), color) def draw_minimap(self): """Draw minimap.""" lay = Layout(200, (200, self._resolution[1] - 170), False) points = lay.polygon_corners(self._grid.get_hextile(self._color1)) x, y = 0, self._resolution[1] - 344 pygame.draw.rect(self._screen, self._background, (x, y, 100, 350), 0) pygame.draw.polygon(self._screen, self._background, points, 0) self.draw_hex_grid() def draw_button_panel(self): """Draw button to open science tree.""" points = [(self._resolution[0] - 200, self._resolution[1]), (self._resolution[0], self._resolution[1]), (self._resolution[0], self._resolution[1] - 60), (self._resolution[0] - 180, self._resolution[1] - 60), (self._resolution[0] - 200, self._resolution[1] - 40)] pygame.draw.polygon(self._screen, self._background, points, 0) logo_background = self._hud_images[1] logo_forground = self._hud_images[0] x, y = self._resolution[0] - 55, self._resolution[1] - 55 self._screen.blit(logo_background, (x, y)) z = 50 self._screen.blit(logo_forground, (x + ((z // 5) + (z // 10) // 2), (y + ((z // 10) // 2)))) my_turn = self._game_state.my_turn if my_turn: image = self._hud_images[3] else: image = self._hud_images[2] x, y = self._resolution[0] - 170, self._resolution[1] - 55 self._screen.blit(image, (x, y)) self.draw_text("End Turn", (x + 30, y + 25), self._color1) def draw_text(self, text, position, color): """ Draw text to screen. :param text: text to be drawn. :param position: tuple (x,y). """ text = str(text) text = self.font.render(text, True, color) rect = text.get_rect() rect.center = (position[0] + 20, position[1]) self._screen.blit(text, rect) def draw_hex_grid(self): """Draw the hexgrid.""" grid = self._grid for hex_point in grid.get_hextiles(): hexagon = grid.get_hextile(hex_point) hexagon_coords = self._map_layout.hex_to_pixel(hexagon) terrain = hexagon.terrain terrain_image = self.map_imgs[(terrain.terrain_type.value, terrain.biome.value)] self._screen.blit( terrain_image, (hexagon_coords[0] - math.ceil(self._map_layout.size * (math.sqrt(3) / 2)), hexagon_coords[1] - self._map_layout.size)) def draw_tree(self): """Draw Research Tree.""" self._GUI_tree.display_menu()