class Scoreboard: def __init__(self, ai_settings, screen, stats): self.screen = screen self.screen_rect = screen.get_rect() self.ai_settings = ai_settings self.stats = stats self.text_color = (255, 255, 0) self.font = SysFont(None, 48) self.score_image = None self.score_rect = None self.high_score_image = None self.high_score_rect = None self.level_image = None self.level_rect = None self.ships = None self.prep_score() self.prep_high_score() self.prep_level() self.prep_ships() def prep_score(self): rounded_score = int(round(self.stats.score, -1)) score_str = 'Score: {:,}'.format(rounded_score) self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color) self.score_rect = self.score_image.get_rect() self.score_rect.right = self.screen_rect.right - 20 self.score_rect.top = 20 def prep_high_score(self): high_score = int(round(self.stats.high_score, -1)) high_score_str = 'High Score: {:,}'.format(high_score) self.high_score_image = self.font.render(high_score_str, True, self.text_color, self.ai_settings.bg_color) self.high_score_rect = self.high_score_image.get_rect() self.high_score_rect.centerx = self.screen_rect.centerx self.high_score_rect.top = self.score_rect.top def prep_level(self): self.level_image = self.font.render('Level: ' + str(self.stats.level), True, self.text_color, self.ai_settings.bg_color) self.level_rect = self.level_image.get_rect() self.level_rect.right = self.score_rect.right self.level_rect.top = self.score_rect.bottom + 10 def prep_ships(self): self.ships = Group() for ship_number in range(self.stats.ships_left): ship = Ship(self.ai_settings, self.screen) ship.rect.x = 10 + ship_number * (ship.rect.width + 5) ship.rect.y = 10 self.ships.add(ship) def show_score(self): self.screen.blit(self.score_image, self.score_rect) self.screen.blit(self.high_score_image, self.high_score_rect) self.screen.blit(self.level_image, self.level_rect) self.ships.draw(self.screen)
class Button: def __init__(self, ai_settings, screen, msg): self.ai_settings = ai_settings self.screen = screen self.screen_rect = screen.get_rect() # Dimensions and properties of the button self.width, self.height = 200, 50 self.button_color = (0, 255, 0) self.text_color = (255, 255, 255) self.font = SysFont(None, 48) # Build button rect and center it self.rect = Rect(0, 0, self.width, self.height) self.rect.center = self.screen_rect.center # Prep button message only once self.msg_image, self.msg_image_rect = None, None self.prep_msg(msg) def prep_msg(self, msg): """Turn msg into a rendered image and center it on the button""" self.msg_image = self.font.render(msg, True, self.text_color, self.button_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center def draw_button(self): """Draw button and then draw message""" self.screen.fill(self.button_color, self.rect) self.screen.blit(self.msg_image, self.msg_image_rect)
class Title: """Represents the title text to be displayed on screen""" def __init__(self, bg_color, screen, text, text_size=50, text_color=(255, 0, 0)): self.bg_color = bg_color self.screen = screen self.text = text self.text_color = text_color self.font = SysFont(None, text_size) self.image = None self.image_rect = None def prep_image(self): """Render the subtitle text as an image""" self.image = self.font.render(self.text, True, self.text_color, self.bg_color) self.image_rect = self.image.get_rect() def blitme(self): """Draw the subtitle's image to the screen""" self.screen.blit(self.image, self.image_rect)
class Button: def __init__(self, ai_settings: Settings, screen: SurfaceType, msg: str): self._screen = screen self._screen_rect = screen.get_rect() self._width, self._height = 200, 50 self._button_color = (0, 255, 0) self._text_color = (255, 255, 255) self._font = SysFont(None, 48) self.rect = pygame.Rect(0, 0, self._width, self._height) self.rect.center = self._screen_rect.center self._prep_msg(msg) def _prep_msg(self, message: str): # print(self._text_color, self._button_color, sep=" -> ") self._msg_image = self._font.render(message, True, self._text_color, self._button_color) self._msg_image_rect = self._msg_image.get_rect() self._msg_image_rect.center = self.rect.center def draw_button(self): self._screen.fill(self._button_color, self.rect) self._screen.blit(self._msg_image, self._msg_image_rect)
class Titletext: # Text def __init__(self, bg_color, screen, text, text_size=56, text_color=(0, 0, 0)): self.bg_color = bg_color self.screen = screen self.text = text self.text_color = text_color self.font = SysFont(None, text_size) self.image = None self.image_rect = None def prep_image(self): self.image = self.font.render(self.text, True, self.text_color, self.bg_color) self.image_rect = self.image.get_rect() def blitme(self): self.screen.blit(self.image, self.image_rect)
class Label(Component): def __init__(self, location=(0, 0), size=(0, 0), caption="", font=None, fontColor=(255, 255, 255), fixedToCaption=True): super(Label, self).__init__(location=location, size=size) self.__font = SysFont('arial', 20) if (font == None) else font self.fixedToCaption = fixedToCaption self.caption = caption self.fontColor = fontColor Label.graphicInit(self) def graphicInit(self): self.writeCaption() def writeCaption(self): if self.fixedToCaption: self.fixToCaption() else: self.reset() captionSurface = self.__font.render(self.__caption, True, self.fontColor) self.blit(captionSurface, (0, 0)) def fixToCaption(self): captionSurface = self.__font.render(self.caption, True, self.fontColor) self.width = captionSurface.get_size()[0] self.height = captionSurface.get_size()[1] self.reset() self.blit(captionSurface, (0, 0))
class Fruit(Sprite): def __init__(self, screen): super(Fruit, self).__init__() self.screen = screen ss = SpriteSheet.spritesheet('images/Fruits.png') self.fruits = [ss.image_at((0,0,32,32)), ss.image_at((32,0,32,32)), ss.image_at((64,0,32,32)), ss.image_at((96,0,32,32)), ss.image_at((128,0,32,32))] self.values = [100, 300, 500, 700, 1000] index = random.randint(0,4) img, self.value = self.fruits[index], self.values[index] img = pygame.transform.scale(img, (25, 25)) self.rect = img.get_rect() self.image = img self.rect.x, self.rect.y = 1000,1000 # hide fruit offscreen self.font = SysFont(None, 32, italic=True) self.score_image = self.font.render(str(self.value), True, (255, 255, 255), (0,0,0)) self.randomint = 101 self.fruitspawned = False self.destroyed = False # how long to show score self.frames = 0 def blitfruit(self): if(not self.destroyed): if(pygame.time.get_ticks() % 1000 <= 1 and not self.fruitspawned): self.randomint = random.randint(1,100) if(self.randomint <= 20): # 20% chance of fruit spawn self.rect.x, self.rect.y = 312, 364 self.screen.blit(self.image, self.rect) self.fruitspawned = True elif(self.frames <= 60 and self.destroyed): self.screen.blit(self.score_image, self.rect) self.frames += 1 if(self.frames > 60): self.frames = 0 self.rect.x, self.rect.y = 1000, 1000 # hide fruit offscreen def fruitReset(self): self.destroyed = False # make getting the fruit possible again for the next stage self.fruitspawned = False self.randomint = 101
class Button: """Initialize button""" def __init__(self, settings, screen, msg, y_factor=0.60): self.settings = settings self.screen = screen self.screen_rect = screen.get_rect() # set button self.button_color = (51, 161, 201) self.text_color = (255, 255, 255) self.alt_color = (187, 255, 255) self.font = SysFont(None, 48) self.y_factor = y_factor # set message self.msg = msg self.msg_image, self.msg_image_rect = None, None self.prep_msg(self.text_color) def check_button(self, mouse_x, mouse_y): """check clicked button event""" if self.msg_image_rect.collidepoint(mouse_x, mouse_y): return True else: return False def alter_text_color(self, mouse_x, mouse_y): """update button when pressed""" if self.check_button(mouse_x, mouse_y): self.prep_msg(self.alt_color) else: self.prep_msg(self.text_color) def prep_msg(self, color): """initialize message""" self.msg_image = self.font.render(self.msg, True, color, self.settings.bg_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.centerx = (self.settings.screen_width // 2) self.msg_image_rect.centery = int(self.settings.screen_height * self.y_factor) def draw_button(self): """display""" self.screen.blit(self.msg_image, self.msg_image_rect)
class Button: """Represents a click-able button style text, with altering text color""" def __init__(self, settings, screen, msg, y_factor=0.65): self.settings = settings self.screen = screen self.screen_rect = screen.get_rect() # Dimensions and properties of the button self.button_color = (0, 255, 0) self.text_color = (255, 255, 255) self.alt_color = (0, 255, 0) self.font = SysFont(None, 48) self.y_factor = y_factor # Prep button message self.msg = msg self.msg_image, self.msg_image_rect = None, None self.prep_msg(self.text_color) def check_button(self, mouse_x, mouse_y): """Check if the given button has been pressed""" if self.msg_image_rect.collidepoint(mouse_x, mouse_y): return True else: return False def alter_text_color(self, mouse_x, mouse_y): """Change text color if the mouse coordinates collide with the button""" if self.check_button(mouse_x, mouse_y): self.prep_msg(self.alt_color) else: self.prep_msg(self.text_color) def prep_msg(self, color): """Turn msg into a rendered image and center it on the button""" self.msg_image = self.font.render(self.msg, True, color, self.settings.bg_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.centerx = (self.settings.screen_width // 2) self.msg_image_rect.centery = int(self.settings.screen_height * self.y_factor) def draw_button(self): """blit message to the screen""" self.screen.blit(self.msg_image, self.msg_image_rect)
class Button: # button text def __init__(self, settings, screen, msg, y_factor=0.65): self.settings = settings self.screen = screen self.screen_rect = screen.get_rect() # Dimensions and properties of the button self.button_color = (0, 0, 0) self.text_color = (0, 0, 0) self.alt_color = (0, 0, 255) self.font = SysFont(None, 48) self.y_factor = y_factor # Prep button message self.msg = msg self.msg_image, self.msg_image_rect = None, None self.prep_msg(self.text_color) def check_button(self, mouse_x, mouse_y): # check for button input if self.msg_image_rect.collidepoint(mouse_x, mouse_y): return True else: return False def change_text_color(self, mouse_x, mouse_y): # change button color if self.check_button(mouse_x, mouse_y): self.prep_msg(self.alt_color) else: self.prep_msg(self.text_color) def prep_msg(self, color): # prep msg image self.msg_image = self.font.render(self.msg, True, color, self.settings.bg_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.centerx = (self.settings.screen_width // 2) self.msg_image_rect.centery = int(self.settings.screen_height * self.y_factor) def draw_button(self): # draw the button self.screen.blit(self.msg_image, self.msg_image_rect)
class Button: def __init__(self, settings, screen, msg, y_factor=0.65): self.settings = settings self.screen = screen self.screen_rect = screen.get_rect() # Dimensions of the buttons self.button_color = (0, 255, 0) self.text_color = (255, 255, 255) self.alt_color = (0, 255, 0) self.font = SysFont(None, 48) self.y_factor = y_factor # Prep button message self.msg = msg self.msg_image, self.msg_image_rect = None, None self.prep_msg(self.text_color) def check_button(self, mouse_x, mouse_y): # check for button clicks if self.msg_image_rect.collidepoint(mouse_x, mouse_y): return True else: return False def alter_text_color(self, mouse_x, mouse_y): # change color of button is mouse hits it if self.check_button(mouse_x, mouse_y): self.prep_msg(self.alt_color) else: self.prep_msg(self.text_color) def prep_msg(self, color): # make the writing an image that sits on the button self.msg_image = self.font.render(self.msg, True, color, self.settings.bg_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.centerx = (self.settings.screen_width // 2) self.msg_image_rect.centery = int(self.settings.screen_height * self.y_factor) def draw_button(self): self.screen.blit(self.msg_image, self.msg_image_rect)
class Button: def __init__(self, settings, screen, msg, y_factor=0.65): self.settings = settings self.screen = screen self.screen_rect = screen.get_rect() self.button_color = (0, 255, 0) self.text_color = (255, 255, 255) self.alt_color = (0, 255, 0) self.font = SysFont(None, 48) self.y_factor = y_factor self.msg = msg self.msg_image, self.msg_image_rect = None, None self.prep_msg(self.text_color) def check_button(self, mouse_x, mouse_y): if self.msg_image_rect.collidepoint(mouse_x, mouse_y): return True else: return False def alter_text_color(self, mouse_x, mouse_y): if self.check_button(mouse_x, mouse_y): self.prep_msg(self.alt_color) else: self.prep_msg(self.text_color) def prep_msg(self, color): self.msg_image = self.font.render(self.msg, True, color, self.settings.bg_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.centerx = (self.settings.screen_width // 2) self.msg_image_rect.centery = int(self.settings.screen_height * self.y_factor) def draw_button(self): self.screen.blit(self.msg_image, self.msg_image_rect)
class Subtitle: """Represents the subtitle text displayed on startup""" def __init__(self, bg_color, screen): self.bg_color = bg_color self.screen = screen self.text = 'AI -- No Walls' self.text_color = (0, 255, 0) self.font = SysFont(None, 36) self.image = None self.image_rect = None def prep_image(self): """Render the subtitle text as an image""" self.image = self.font.render(self.text, True, self.text_color, self.bg_color) self.image_rect = self.image.get_rect() def blitme(self): """Draw the subtitle's image to the screen""" self.screen.blit(self.image, self.image_rect)
class Button: """Represents a click-able button""" def __init__(self, config, screen, msg): self.config = config self.screen = screen self.screen_rect = screen.get_rect() # Dimensions and properties of the button self.button_color = (0, 255, 0) self.text_color = (255, 255, 255) self.font = SysFont(None, 48) # Build button rect and center it self.width, self.height = self.font.size(msg) self.width, self.height = (self.width + self.width / 4), (self.height + self.height / 4) self.rect = Rect(0, 0, self.width, self.height) self.rect.centerx = (self.config.screen_width // 2) self.rect.centery = int(self.config.screen_height * 0.75) # Prep button message only once self.msg_image, self.msg_image_rect = None, None self.prep_msg(msg) def check_button(self, mouse_x, mouse_y): """Check if the given button has been pressed""" if self.rect.collidepoint(mouse_x, mouse_y): return True else: return False def prep_msg(self, msg): """Turn msg into a rendered image and center it on the button""" self.msg_image = self.font.render(msg, True, self.text_color, self.config.bg_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center def draw_button(self): """Draw button and then draw message""" draw.rect(self.screen, self.button_color, self.rect, 3) self.screen.blit(self.msg_image, self.msg_image_rect)
class Ufo(pygame.sprite.Sprite): def __init__(self, ai_settings, screen, sound=True): super().__init__() self.screen = screen self.ai_settings = ai_settings self.possible_scores = ai_settings.UFO_pts self.score = None self.image = [pygame.image.load('images/face.png'), pygame.image.load('images/face1.png'), pygame.image.load('images/face2.png'), pygame.image.load('images/face3.png')] self.image_index = 0 self.image = self.image[self.image_index] self.rect = self.image.get_rect() self.score_image = None self.font = SysFont(None, 32, bold=True) self.prep_score() self.death_frames = [pygame.image.load('images/deaths/deadface.png'), pygame.image.load('images/deaths/deadface1.png'), pygame.image.load('images/deaths/deadface2.png'), pygame.image.load('images/deaths/deadface3.png'), pygame.image.load('images/deaths/deadface4.png'), pygame.image.load('images/deaths/deadface5.png')] self.death_index = None # self.death_frames.append(pygame.image.load('images/deaths/deadface.png')) self.death_frames.append(self.score_image) self.last_frame = None self.wait_interval = 500 self.entrance_sound = pygame.mixer.Sound('sound/UFO_entrance.wav') self.death_sound = pygame.mixer.Sound('sound/UFO_death.wav') self.entrance_sound.set_volume(0.6) self.channel = ai_settings.ufo_channel self.speed = ai_settings.ufo_spd * (choice([-1, 1])) self.rect.x = 0 if self.speed > 0 else ai_settings.screen_width self.rect.y = ai_settings.screen_height * 0.1 self.dead = False if sound: self.channel.play(self.entrance_sound, loops=-1) def kill(self): self.channel.stop() super().kill() def death_begins(self): self.channel.stop() self.channel.play(self.death_sound) self.dead = True self.death_index = 0 self.image = self.death_frames[self.death_index] self.last_frame = pygame.time.get_ticks() def score(self): self.score = choice(self.possible_scores) return self.score def prep_score(self): score_str = str(self.get_score()) self.score_image = self.font.render(score_str, True, (255, 0, 0), self.ai_settings.bg_color) def update(self): if not self.dead: # if abs(self.last_frame - time) > 1000: # self.last_frame = time # self.image_index = (self.image_index + 1) % len(self.images) # self.image = self.images[self.image_index] self.rect.x += self.speed if self.speed > 0 and self.rect.left > self.ai_settings.screen_width: self.kill() elif self.rect.right < 0: self.kill() else: time = pygame.time.get_ticks() if abs(time - self.last_frame) > self.wait_interval: self.last_frame = time self.death_index += 1 if self.death_index >= len(self.death_frames): self.kill() else: self.image = self.death_frames[self.death_index] self.wait_interval += 500 def get_score(self): # get random score of ufo pt value self.score = choice(self.possible_scores) return self.score def blitme(self): self.screen.blit(self.image, self.rect)
class Plotter: def __init__(self, bot: 'Bot'): self.bot = bot self.bot.add_callback(self.run) pygame.init() self.win_size = (bot.game.map.width * CELL_SIZE, bot.game.map.height * CELL_SIZE) self.update_display_size() pygame.mouse.set_cursor(*pygame.cursors.tri_right) self.font = SysFont("vcrosdmono", 16) self.clock = pygame.time.Clock() self.speed_up = DEFAULT_SPEEDUP self.pause = False self.selected = None def run(self): self.clock.tick(int(FPS * self.speed_up) if not self.pause else 60) keys_mod = pygame.key.get_mods() for e in pygame.event.get(): if e.type == pygame.QUIT: raise SystemExit("QUIT") elif e.type == pygame.KEYDOWN: self.key_handler(e, keys_mod) elif e.type == pygame.KEYUP: self.key_handler(e, keys_mod, True) if e.type == pygame.MOUSEBUTTONUP: self.mouse_handler(e) self.screen.fill(BLACK) if not self.selected: self.draw_halite() else: self.draw_selected() self.draw_bases() self.draw_ships() label = self.font.render(self.info, 0, (255, 0, 0)) self.screen.blit(label, (0, 0)) mouse = pygame.mouse.get_pos() pos = mul_tuple(mouse, 1 / CELL_SIZE, integer=True) halite_hover = self.font.render( str(self.bot.game.map[pos].halite_amount), 0, GREY) self.screen.blit(halite_hover, mouse) display.update() return not self.pause def draw_halite(self): # halite = [[cell.halite_amount for cell in row] for row in self.bot.game.map.cells] # halite = blur(halite, 1, 5) # positions = [[cell.position for cell in row] for row in self.bot.game.map.cells] # field = [[MapCell(positions[i][j], halite[i][j]) for j in range(len(halite[0]))] for i in range(len(halite))] # for cell in chain(*field): for cell in self.bot.game.map: halite = cell.halite_amount / constants.MAX_HALITE color = mul_tuple((255, 255, 255), min(halite, 1), integer=True) if "gbh_norm" in self.bot.debug_maps: r, g, b = color k = 1 - self.bot.debug_maps["gbh_norm"][cell.position.y][ cell.position.x] g *= k b *= k color = r, g, b pygame.draw.rect(self.screen, color, pos2rect(cell.position)) def draw_selected(self): if isinstance(self.selected, Ship): debug = self.bot.debug_maps.get(self.selected.id, None) if not debug: self.draw_halite() return max_value = max(debug.values()) for position, halite in debug.items(): pygame.draw.rect( self.screen, mul_tuple((255, 255, 255), halite / max_value, integer=True), pos2rect(position)) def draw_ships(self): for n, player in self.bot.game.players.items(): color = PLAYERS[n] for ship in player.get_ships(): # noinspection PyTypeChecker is_selected = self.selected is None or self.selected.id == ship.id p = ship.position * CELL_SIZE + (CELL_SIZE // 2, CELL_SIZE // 2) pygame.draw.circle( self.screen, mul_tuple(color, 1.2 if is_selected else .1, integer=True), (p.x, p.y), round(CELL_SIZE / 2.5)) self.screen.blit(self.font.render(str(ship.id), 0, GREY), (p.x, p.y)) if ship.halite_amount: pygame.draw.circle( self.screen, mul_tuple(WHITE, 1 if is_selected else .1, integer=True), (p.x, p.y), round(CELL_SIZE / 2.5 * (ship.halite_amount / constants.MAX_HALITE))) if is_selected and self.bot.ships_targets.get(ship, None): target = self.bot.ships_targets[ship] if isinstance(target, Position): points = (ship.position, target) else: points = [ship.position, *target] pygame.draw.lines(self.screen, color, False, [ tuple(point * CELL_SIZE + CELL_SIZE // 2) for point in points ], 1) def draw_bases(self): for n, player in self.bot.game.players.items(): color = PLAYERS[n] for base in (player.shipyard, ): pygame.draw.rect(self.screen, color, pos2rect(base.position), 1) def update_display_size(self): self.screen = display.set_mode(self.win_size, pygame.DOUBLEBUF | pygame.RESIZABLE) display.flip() def key_handler(self, e, m: int, up=False): if not up: logging.debug(f"Press {e.unicode}") if m & pygame.KMOD_ALT and e.key == pygame.K_F4: raise SystemExit("QUIT") elif e.unicode == ',': # '<' self.speed_up /= 2 elif e.unicode == '.': # '>' self.speed_up *= 2 elif e.key == pygame.K_SPACE: self.pause = not self.pause def mouse_handler(self, e): map_pos = tuple(map(int, mul_tuple(e.pos, 1 / CELL_SIZE))) cell = self.bot.game.map[map_pos] logging.info(f"Cell: pos={cell.position} halite={cell.halite_amount}") if cell.ship: ship = cell.ship logging.info(f"Ship: id={ship.id} halite={ship.halite_amount}") if ship.owner == self.bot.game.me.id: self.selected = ship else: self.selected = None @property def info(self): if self.selected: load = (1 - self.selected.halite_amount / constants.MAX_HALITE) * 100 else: load = 0 return f"{self.bot.game.turn_number}/{constants.MAX_TURNS} X{self.speed_up:.0f} |" \ f" G: {len(self.bot.game.players[0].get_ships()):>2d} {self.bot.game.players[0].halite_amount:>5d} | " \ f" R: {len(self.bot.game.players[1].get_ships()):>2d} {self.bot.game.players[1].halite_amount:>5d}" \ + (f" | selected: #{self.selected.id} {load:>2.0f}%" if self.selected else "")
class Plotter: VIEWS = [ "__default__", "gbh_norm", "dropoff", "dropoff_2", "ships_mask", ] def __init__(self, bot: 'Bot'): self.bot = bot self.bot.add_callback(self.run) pygame.init() self.win_size = (bot.game.map.width * CELL_SIZE, bot.game.map.height * CELL_SIZE) self.update_display_size() pygame.mouse.set_cursor(*pygame.cursors.tri_right) self.font = SysFont("vcrosdmono", 16) self.clock = pygame.time.Clock() self.speed_up = DEFAULT_SPEEDUP self.pause = False self.selected = None self.current_view = self.VIEWS[0] def run(self): self.clock.tick(int(FPS * self.speed_up) if not self.pause else 60) keys_mod = pygame.key.get_mods() for e in pygame.event.get(): if e.type == pygame.QUIT: raise SystemExit("QUIT") elif e.type == pygame.KEYDOWN: self.key_handler(e, keys_mod) elif e.type == pygame.KEYUP: self.key_handler(e, keys_mod, True) if e.type == pygame.MOUSEBUTTONUP: self.mouse_handler(e) self.screen.fill(BLACK) if self.current_view == "__default__": if not self.selected: self.draw_halite() else: self.draw_selected() else: self.drop_custom_map(self.current_view) self.draw_bases() self.draw_ships() height = 0 for info in self.info: label = self.font.render(info, 0, WHITE) self.screen.blit(label, (0, height)) height += label.get_height() + 2 mouse = pygame.mouse.get_pos() pos = mul_tuple(mouse, 1 / CELL_SIZE, integer=True) halite_hover = self.font.render( str(self.bot.game.map[pos].halite_amount), 0, GREY) self.screen.blit(halite_hover, mouse) display.update() return not self.pause def draw_halite(self): # halite = [[cell.halite_amount for cell in row] for row in self.bot.game.map.cells] # halite = blur(halite, 1, 5) # positions = [[cell.position for cell in row] for row in self.bot.game.map.cells] # field = [[MapCell(positions[i][j], halite[i][j]) for j in range(len(halite[0]))] for i in range(len(halite))] # for cell in chain(*field): for cell in self.bot.game.map: halite = cell.halite_amount / constants.MAX_HALITE color = mul_tuple((255, 255, 255), min(halite, 1), integer=True) if "gbh_norm" in self.bot.debug_maps: r, g, b = color k = 1 - self.bot.debug_maps["gbh_norm"][cell.position.y][ cell.position.x] g *= k b *= k color = r, g, b pygame.draw.rect(self.screen, color, pos2rect(cell.position)) def draw_selected(self): if isinstance(self.selected, Ship): debug_map = self.bot.debug_maps.get(self.selected.id, None) if debug_map is None: self.draw_halite() return max_value = debug_map.max() it = np.nditer(debug_map, ['multi_index']) while not it.finished: halite = it[0] position = Position(*reversed(it.multi_index)) pygame.draw.rect( self.screen, mul_tuple((255, 255, 255), halite / max_value, integer=True), pos2rect(position)) it.iternext() def draw_ships(self): for n, player in self.bot.game.players.items(): color = PLAYERS[n] for ship in player.get_ships(): # noinspection PyTypeChecker is_selected = self.selected is None or self.selected.id == ship.id p = ship.position * CELL_SIZE + (CELL_SIZE // 2, CELL_SIZE // 2) pygame.draw.circle( self.screen, mul_tuple(color, 1.2 if is_selected else .1, integer=True), (p.x, p.y), round(CELL_SIZE / 2.5)) self.screen.blit(self.font.render(str(ship.id), 0, GREY), (p.x, p.y)) if ship.halite_amount: pygame.draw.circle( self.screen, mul_tuple(WHITE, 1 if is_selected else .1, integer=True), (p.x, p.y), round(CELL_SIZE / 2.5 * (ship.halite_amount / constants.MAX_HALITE))) if is_selected and self.bot.ship_manager.targets.get( ship, None): target = self.bot.ship_manager.targets[ship] if isinstance(target, Position): points = (ship.position, target) else: points = [ship.position, *target] pygame.draw.lines(self.screen, color, False, [ tuple(point * CELL_SIZE + CELL_SIZE // 2) for point in points ], 1) def draw_bases(self): for n, player in self.bot.game.players.items(): color = PLAYERS[n] for base in (player.shipyard, *player.get_dropoffs()): pygame.draw.rect(self.screen, color, pos2rect(base.position), 1) def drop_custom_map(self, view): debug_map = self.bot.debug_maps.get(view, None) if debug_map is None: self.draw_halite() return max_value = debug_map.max() min_value = debug_map.min() it = np.nditer(debug_map, ['multi_index']) while not it.finished: halite = it[0] position = Position(*reversed(it.multi_index)) k = (max_value - min_value) or .1 pygame.draw.rect( self.screen, mul_tuple((255, 255, 255), (halite - min_value) / k, integer=True), pos2rect(position)) it.iternext() def update_display_size(self): self.screen = display.set_mode(self.win_size, pygame.DOUBLEBUF | pygame.RESIZABLE) display.flip() def key_handler(self, e, m: int, up=False): if not up: logging.debug(f"Press {e.unicode}") if m & pygame.KMOD_ALT and e.key == pygame.K_F4: raise SystemExit("QUIT") elif e.unicode == ',': # '<' self.speed_up /= 2 elif e.unicode == '.': # '>' self.speed_up *= 2 elif e.key == pygame.K_SPACE: self.pause = not self.pause elif '0' <= e.unicode <= '9': code = int(e.unicode) if code == 0: code = 9 else: code -= 1 self.current_view = self.VIEWS[code] def mouse_handler(self, e): map_pos = tuple(map(int, mul_tuple(e.pos, 1 / CELL_SIZE))) cell = self.bot.game.map[map_pos] logging.info(f"Cell: pos={cell.position} halite={cell.halite_amount}") if cell.ship: ship = cell.ship logging.info(f"Ship: id={ship.id} halite={ship.halite_amount}") if ship.owner == self.bot.game.me.id: self.selected = ship else: self.selected = None @property def info(self): gmap = self.bot.game.map if self.selected: load = (1 - self.selected.halite_amount / constants.MAX_HALITE) * 100 else: load = 0 total = gmap.total_halite info = [ f"{self.bot.game.turn_number:>3d}/{constants.MAX_TURNS} X{self.speed_up:.0f} " f"{total:>6.0f} {total / gmap.initial_halite:>3.0%} ({self.bot.ship_fill_k:.1f})" ] players = [ f"{color}: {len(p.get_ships()):>2d} {p.halite_amount:>5d}" for color, p in zip("GRBC", self.bot.game.players.values()) ] info.append(f"{players[0]} | {players[1]}") if len(players) > 2: info.append(f"{players[2]} | {players[3]}") if self.selected: info.append(f":> selected: #{self.selected.id} {load:>2.0f}%") return info
class Ufo(pygame.sprite.Sprite): def __init__(self, ai_settings, screen, sound=True): super().__init__() self.screen = screen self.ai_settings = ai_settings self.possible_scores = ai_settings.ufo_point_values self.score = None self.image = pygame.image.load('resources/Images/UFO Alien-1.png') self.rect = self.image.get_rect() self.score_image = None self.font = SysFont(None, 32, italic=True) self.prep_score() self.death_frames = [] self.death_index = None self.death_frames.append(pygame.image.load('resources/Images/UFO Alien-3.png')) self.death_frames.append(self.score_image) self.last_frame = None self.wait_interval = 500 self.entrance_sound = pygame.mixer.Sound('resources/Sounds/ufo_lowpitch.wav') self.death_sound = pygame.mixer.Sound('resources/Sounds/invaderkilled.wav') self.entrance_sound.set_volume(0.6) self.channel = ai_settings.ufo_channel self.speed = ai_settings.ufo_speed * (choice([-1, 1])) self.rect.x = 0 if self.speed > 0 else ai_settings.screen_width self.rect.y = ai_settings.screen_height * 0.1 self.dead = False if sound: self.channel.play(self.entrance_sound, loops=-1) def kill(self): self.channel.stop() super().kill() def begin_death(self): self.channel.stop() self.channel.play(self.death_sound) self.dead = True self.death_index = 0 self.image = self.death_frames[self.death_index] self.last_frame = pygame.time.get_ticks() def get_score(self): self.score = choice(self.possible_scores) return self.score def prep_score(self): score_str = str(self.get_score()) self.score_image = self.font.render(score_str, True, (255, 0, 0), self.ai_settings.bg_color) def update(self): if not self.dead: self.rect.x += self.speed if self.speed > 0 and self.rect.left > self.ai_settings.screen_width: self.kill() elif self.rect.right < 0: self.kill() else: time_test = pygame.time.get_ticks() if abs(time_test - self.last_frame) > self.wait_interval: self.last_frame = time_test self.death_index += 1 if self.death_index >= len(self.death_frames): self.kill() else: self.image = self.death_frames[self.death_index] self.wait_interval += 500 def blitme(self): self.screen.blit(self.image, self.rect)
class UFO(pygame.sprite.Sprite): """Represents a UFO meant to move across the screen at random intervals""" def __init__(self, ai_settings, screen, sound=True): super().__init__() # Set screen self.sound = sound self.screen = screen self.ai_settings = ai_settings self.possible_scores = ai_settings.ufo_point_values self.score = None # Load Image self.image = pygame.image.load('images/ufo.png') self.rect = self.image.get_rect() self.score_image = None self.font = SysFont(None, 32, italic=True) self.prep_score() # Sound of UFO self.entrance_sound = pygame.mixer.Sound('sounds/ufo.wav') self.hit_sound = pygame.mixer.Sound('sounds/ufoHit.wav') self.entrance_sound.set_volume(0.6) self.channel = ai_settings.ufoRadio # Speed of UFO self.speed = ai_settings.ufo_speed * (choice([-1, 1])) # Starting Position with speed self.rect.x = 0 if self.speed > 0 else ai_settings.screen_width self.rect.y = ai_settings.screen_height * 0.1 # When UFO is inactive self.dead = False # When UFO hit self.hit_animated = [] self.hit_index = None self.hit_animated.append(self.score_image) self.end_scene = None self.wait_interval = 200 def blitme(self): self.screen.blit(self.image, self.rect) def hit_ufo(self): self.channel.stop() self.channel.play(self.hit_sound) self.dead = True self.hit_index = 0 self.image = self.hit_animated[self.hit_index] self.end_scene = pygame.time.get_ticks() def died(self): self.channel.stop() super().kill() def get_score(self): """Get any score""" self.score = choice(self.possible_scores) return self.score def prep_score(self): score_str = str(self.get_score()) self.score_image = self.font.render(score_str, True, (255, 223, 0), self.ai_settings.bg_color) def update(self): """Update the UFO functions""" # When ufo is not yet dead manage the speed if not self.dead: self.rect.x += self.speed if self.speed > 0 and self.rect.left > self.ai_settings.screen_width: self.died() elif self.rect.right < 0: self.died() else: # Random movements of ufo timer = pygame.time.get_ticks() if abs(timer - self.end_scene) > self.wait_interval: self.end_scene = timer self.hit_index += 1 if self.hit_index >= len(self.hit_animated): self.died() else: # When UFO get hit the image animates through self.image = self.hit_animated[self.hit_index] self.wait_interval += 200
class Ufo(Sprite): """Represents a UFO meant to move across the screen at random intervals.""" def __init__(self, ai_settings, screen): """Initialize ufo settings.""" super().__init__() # screen, settings, score values self.screen = screen self.ai_settings = ai_settings self.possible_scores = ai_settings.ufo_points self.score = None # images, score text self.image = pygame.image.load('images/ufo.png') self.rect = self.image.get_rect() self.score_image = None self.font = SysFont(None, 32, italic=True) self.prep_score() # death frames self.death_frames = [] self.death_index = None self.death_frames.append( pygame.image.load('images/ufo_death/ufo_death.png')) self.death_frames.append(self.score_image) self.last_frame = None self.wait_interval = 500 # sound self.entrance_sound = pygame.mixer.Sound('sounds/ufo_sound.wav') self.death_sound = pygame.mixer.Sound('sounds/ufo_death.wav') self.entrance_sound.set_volume(0.6) self.channel = ai_settings.ufo_channel # initial position, speed/direction self.speed = ai_settings.ufo_speed_factor * (choice([-1, 1])) self.rect.x = 0 if self.speed > 0 else ai_settings.screen_width self.rect.y = ai_settings.screen_height * 0.1 # death flag self.dead = False # Play sound while its on screen self.channel.play(self.entrance_sound, loops=-1) def kill(self): """Stop music if killed and remove ufo from group.""" self.channel.stop() super().kill() def begin_death(self): self.channel.stop() self.channel.play(self.death_sound) self.dead = True self.death_index = 0 self.image = self.death_frames[self.death_index] self.last_frame = pygame.time.get_ticks() def get_score(self): """Get a random score from the UFO's possible score values.""" self.score = choice(self.possible_scores) return self.score def prep_score(self): """Prepare score pop up when killed.""" score_str = str(self.get_score()) self.score_image = self.font.render(score_str, True, (255, 0, 0), self.ai_settings.bg_color) def update(self): """Update the ufo.""" if not self.dead: self.rect.x += self.speed if self.speed > 0 and self.rect.left > self.ai_settings.screen_width: self.kill() elif self.rect.right < 0: self.kill() else: time_test = pygame.time.get_ticks() if abs(time_test - self.last_frame) > self.wait_interval: self.last_frame = time_test self.death_index += 1 if self.death_index >= len(self.death_frames): self.kill() else: self.image = self.death_frames[self.death_index] self.wait_interval += 350 def blitme(self): """Draw ufo on screen.""" self.screen.blit(self.image, self.rect)
class Ufo(pygame.sprite.Sprite): """Represents a UFO meant to move across the screen at random intervals""" def __init__(self, ai_settings, screen, sound=True): super().__init__() # screen, settings, score values self.screen = screen self.ai_settings = ai_settings self.possible_scores = ai_settings.ufo_point_values self.ufo_images = None self.image = None self.image_index = None self.death_index = None self.last_frame = None self.death_frames = None self.rect = None self.score = None self.score_image = None self.font = SysFont(None, 32, italic=True) self.prep_score() # sound self.entrance_sound = pygame.mixer.Sound('sound/ufoAppeared.wav') self.death_sound = pygame.mixer.Sound('sound/Gottem.wav') self.entrance_sound.set_volume(0.6) self.channel = ai_settings.ufo_channel # death flag self.dead = False # images, score text self.ufo_images = [ pygame.image.load('images/Fish/Fish_0.png'), pygame.image.load('images/Fish/Fish_0.png'), pygame.image.load('images/Fish/Fish_1.png'), pygame.image.load('images/Fish/Fish_1.png'), pygame.image.load('images/Fish/Fish_2.png'), pygame.image.load('images/Fish/Fish_2.png'), pygame.image.load('images/Fish/Fish_3.png'), pygame.image.load('images/Fish/Fish_3.png'), pygame.image.load('images/Fish/Fish_4.png'), pygame.image.load('images/Fish/Fish_4.png'), pygame.image.load('images/Fish/Fish_5.png'), pygame.image.load('images/Fish/Fish_6.png'), pygame.image.load('images/Fish/Fish_6.png') ] # death frames self.death_frames = [ pygame.image.load('images/Boom/Boom_0.png'), pygame.image.load('images/Boom/Boom_1.png'), pygame.image.load('images/Boom/Boom_2.png'), pygame.image.load('images/Boom/Boom_3.png'), pygame.image.load('images/Boom/Boom_4.png'), pygame.image.load('images/Boom/Boom_5.png'), pygame.image.load('images/Boom/Boom_6.png'), pygame.image.load('images/Boom/Boom_7.png'), pygame.image.load('images/Boom/Boom_8.png') ] self.death_frames.append(self.score_image) self.image_index = 0 self.image = self.ufo_images[self.image_index] self.rect = self.image.get_rect() self.last_frame = pygame.time.get_ticks() # initial position, speed/direction self.speed = ai_settings.ufo_speed * (choice([-1, 1])) self.rect.x = 0 if self.speed > 0 else ai_settings.screen_width self.rect.y = ai_settings.screen_height * 0.1 self.last_frame = 0 self.wait_interval = 0 if sound: self.channel.play(self.entrance_sound, loops=-1) def kill(self): self.channel.stop() super().kill() def begin_death(self): self.channel.stop() self.channel.play(self.death_sound) self.dead = True self.death_index = 0 self.image = self.death_frames[self.death_index] self.last_frame = 0 def get_score(self): """Get a random score from the UFO's possible score values""" self.score = choice(self.possible_scores) return self.score def prep_score(self): score_str = str(self.get_score()) self.score_image = self.font.render(score_str, True, (255, 0, 0), self.ai_settings.bg_color) def update(self): time_test = pygame.time.get_ticks() if not self.dead: if abs(self.last_frame - time_test) > 50: self.last_frame = time_test self.image_index = (self.image_index + 1) % len( self.ufo_images) # Loop over frames self.image = self.ufo_images[self.image_index] if not self.dead: self.rect.x += self.speed if self.speed > 0 and self.rect.left > self.ai_settings.screen_width: self.kill() elif self.rect.right < 0: self.kill() else: if abs(self.last_frame - time_test ) > 100: # At least 100 millisecond delay between frames self.last_frame = time_test # Delay should ensure animation is perceivable at high fps self.death_index += 1 if self.death_index >= len(self.death_frames): self.kill() else: self.image = self.death_frames[self.death_index] self.wait_interval += 100 def blitme(self): self.screen.blit(self.image, self.rect)
class Game: """ Class with game settings/level loaders/game rules :self.width (int) width of game window; :self.height (int) - height of game window; :self.full_screen (int) - FULLSCREEN or 0; :self.fps (int) - frame per second; :self.caption (str) - window name; :self.active_game (bool) - if false - quit from game else game is running :self.background_path (str) - path to image background :self._screen (pygame.Surface) - screen where image will be drew :self.background_image (pygame.image) - background image """ def __init__(self): self.width = 0 self.height = 0 self.full_screen = True self.fps = 0 self.caption = 'Adventure' self.active_game = True self.statistics = False self.background_path = 'Gamedata/Backgrounds/fon.png' self.max_distance = 0 self.total_distance = 0 self.sound = True self.font = SysFont(None, 45) self._screen = None self._camera = None @staticmethod def _get_settings(): """ Method for getting game settings from file :return: settings_data (dict) - dict with game settings """ settings_data = dict() with open('Gamedata/settings.txt', mode='r') as f: for line in f: line = line.split(':') parameter, value = line[0], int(line[-1]) settings_data[parameter] = value return settings_data @property def background_image(self): return pygame.image.load(self.background_path) @property def clock_(self): return pygame.time.Clock() def set_screen(self): """ Set screen with self.width, self.height and self.full_screen :return: None """ self._screen = pygame.display.set_mode((self.width, self.height), self.full_screen) def set_camera(self): self._camera = Camera(camera_configure, (self.width, self.height)) @staticmethod def _get_save_data(): """ Method for getting game saves from file :return: save_data (dict) - dict with save data """ save_data = dict() with open('GameData/saves.txt', mode='r') as f: for line in f: line = line.split(':') save_data[line[0]] = int(line[-1]) return save_data def _menu(self): """ Menu level where player may choose settings/levels and etc. If self.active_game is True it means that game is running else exiting the game :return: None """ ui_elems = self._load_menudata() while self.active_game: for event in pygame.event.get(): if event.type == MOUSEBUTTONUP: pos = pygame.mouse.get_pos() for obj in ui_elems: if obj.name == 'start' and obj.check_collision( pos, self.sound): self._game_loop() if obj.name == 'music' and obj.check_collision( pos, self.sound): self.sound = not self.sound obj.change_state() if obj.name == 'trophy' and obj.check_collision( pos, self.sound): self._get_statistics(obj) if obj.name == 'quit' and obj.check_collision( pos, self.sound): self.active_game = False if event.type == QUIT: self.active_game = False self._screen.blit(self.background_image, (0, 0)) for obj in ui_elems: self._screen.blit(obj.main_image, obj.left_up_corner) pygame.display.update() self.clock_.tick(self.fps) self._save_game() pygame.quit() def _load_game(self): """ Load game with saved game settings and game status :return: None """ settings = self._get_settings() for parameter, value in settings.items(): if parameter == 'width': self.width = value elif parameter == 'height': self.height = value elif parameter == 'full_screen': self.full_screen = FULLSCREEN if value == 1 else 0 elif parameter == 'fps': self.fps = value elif parameter == 'sound': self.sound = True if value == 1 else False else: raise ('Undefined parameter ' + str(parameter) + ' in settings.txt') saves = self._get_save_data() for parameter, value in saves.items(): if parameter == 'max_distance': self.max_distance = value elif parameter == 'total_distance': self.total_distance = value else: raise ('Undefined parameter ' + str(parameter) + 'in saves.txt') self.set_screen() @staticmethod def _load_menudata(): """ Load icons and its sounds for menu game :return: (arr) - ui_elems """ data = [(['GameData/Menu/buttonStart.png'], 'start', (450, 384), (90, 60), 'GameData/Sounds/MainButton.wav'), (['GameData/Menu/trophy.png'], 'trophy', (900, 50), (50, 50), 'GameData/Sounds/click.wav'), (['GameData/Menu/musicOn.png', 'GameData/Menu/musicOff.png'], 'music', (900, 100), (50, 50), 'GameData/Sounds/click.wav'), (['GameData/Menu/quit.png'], 'quit', (900, 150), (50, 50), 'GameData/Sounds/click.wav')] ui_elems = [] for img_paths, name, coords, shape, sound_path in data: imgs = [] for img_path in img_paths: img = pygame.image.load(img_path) imgs.append(img) ui_obj = UiObject(imgs, name, *coords, *shape, sound_path) ui_elems.append(ui_obj) return ui_elems def _game_loop(self): """ Main loop with game where will be load main character, game mobs, ui levels and etc During the game all game objects will be drawn in self._screen Self.clock_ supports current self.fps :return: None """ player = MainCharacter() level_generator = LevelGenerator(play_sounds=self.sound) dead_mobs = Group() self.set_camera() active_level = True result_session_was_saved = False while active_level: for event in pygame.event.get(): if event.type == QUIT or (event.type == MOUSEBUTTONUP and player.is_dead): active_level = False self._screen.blit(self.background_image, (0, 0)) level_data = level_generator.draw_blocks(self._screen, self._camera, player.region) left_region = level_generator.get_left_region() level_blocks = level_data['level_blocks'].copy() level_blocks.add(level_data['mobs']) if not player.is_dead: player.move(self._screen, self._camera, left_region, level_blocks) else: if not result_session_was_saved: self._save_session_result(player) result_session_was_saved = True self._get_end_game_caption() for entity in level_data['mobs']: if entity.live(self._screen, self._camera, level_blocks): dead_mobs.add(entity) level_generator.remove_objects(entity) for dead_entity in dead_mobs: if dead_entity.die(self._screen, self._camera): dead_mobs.remove(dead_entity) self._draw_ui_elem(player) pygame.display.update() self._camera.update(player) self.clock_.tick(self.fps) def start_game(self): """ Public method for starting the game :return: None """ self._load_game() pygame.display.set_caption(self.caption) self._menu() def _get_end_game_caption(self): """ Method for drawing end game caption :return: None """ curr_font = self.font.render(GAME_OVER_CAPTION, 0, GREEN) self._screen.blit(curr_font, (GAME_OVER_CAPTION_X, GAME_OVER_CAPTION_Y)) def _save_session_result(self, player): """ Method for saving session data :param player: (Player) - player object :return: None """ self.max_distance = max(self.max_distance, player.max_distance) self.total_distance += player.max_distance def _draw_ui_elem(self, player): """ Method for drawing ui elems in during the game (health and etc.) :param player: (Player) - player object :return: None """ health_font = self.font.render(str(player.health), 0, GREEN) self._screen.blit(player.health_image, (HEALTH_IMAGE_X, HEALTH_IMAGE_Y)) self._screen.blit(health_font, (HEALTH_X, HEALTH_Y)) def _get_statistics(self, trophy_obj): """ Method for showing statistics to player :param trophy_obj: (UiObject) :return: None """ self.statistics = True curr_font = self.font.render( THE_LONGEST_DISTANCE_CAPTION + str(self.max_distance), 0, GREEN) curr_font_2 = self.font.render( ALL_DISTANCE_CAPTION + str(self.total_distance), 0, GREEN) while self.statistics: for event in pygame.event.get(): if event.type == MOUSEBUTTONUP: pos = pygame.mouse.get_pos() if trophy_obj.check_collision(pos, self.sound): self.statistics = False if event.type == QUIT: self.statistics = False self._screen.blit(self.background_image, (0, 0)) self._screen.blit(curr_font, (DISTANCE_CAPTION_X, DISTANCE_CAPTION_Y)) self._screen.blit(curr_font_2, (ALL_DISTANCE_CAPTION_X, ALL_DISTANCE_CAPTION_Y)) self._screen.blit(trophy_obj.main_image, trophy_obj.left_up_corner) pygame.display.update() self.clock_.tick(self.fps) def _save_game(self): """ Save statistics data and settings in the end of game. :return: None """ settings = { 'width': self.width, 'height': self.height, 'full_screen': self.full_screen, 'fps': self.fps, 'sound': self.sound } statistics = { 'max_distance': self.max_distance, 'total_distance': self.total_distance } with open('GameData/settings.txt', 'w') as f: for parameter, value in settings.items(): if isinstance(value, bool): value = 1 if value is True else 0 if parameter == 'full_screen' and value != 0: value = 1 f.write(parameter + ': ' + str(value) + '\n') with open('GameData/saves.txt', 'w') as f: for parameter, value in statistics.items(): f.write(parameter + ': ' + str(value) + '\n')
class Ufo(Sprite): """Represents a UFO meant to move across the screen at random intervals""" def __init__(self, ai_settings, screen, sound=True): super().__init__() # screen, settings, score values self.screen = screen self.ai_settings = ai_settings self.possible_scores = ai_settings.ufo_point_values self.score = None # images, score text self.ss = spritesheet('images/SpriteSheet.png') self.image = self.ss.image_at((64, 0, 32, 32)) self.rect = self.image.get_rect() self.score_image = None self.font = SysFont(None, 32, italic=True) self.prep_score() # death frames self.death_frames = [] self.death_index = None self.death_frames.append(self.ss.image_at((32, 64, 32, 32))) self.death_frames.append(self.score_image) self.last_frame = None self.wait_interval = 500 # sound self.entrance_sound = pygame.mixer.Sound('sound/ufo_highpitch.wav') self.death_sound = pygame.mixer.Sound('sound/invaderkilled.wav') self.channel = pygame.mixer.Channel(3) self.channel.set_volume(0.01) # initial position, speed/direction self.speed = (choice([-1, 1])) self.rect.x = 0 if self.speed > 0 else ai_settings.screen_width self.rect.y = ai_settings.screen_height * 0.1 # death flag self.dead = False if sound: self.channel.play(self.entrance_sound, loops=-1) def kill(self): self.channel.stop() super().kill() def death_animation(self): self.channel.stop() self.channel.play(self.death_sound) self.dead = True self.death_index = 0 self.image = self.death_frames[self.death_index] self.last_frame = pygame.time.get_ticks() def get_score(self): """Get a random score from the UFO's possible score values""" self.score = choice(self.possible_scores) return self.score def prep_score(self): score_str = str(self.get_score()) self.score_image = self.font.render(score_str, True, (255, 0, 0), self.ai_settings.bg_color) def update(self): if not self.dead: self.rect.x += self.speed screen_rect = self.screen.get_rect() if self.rect.left >= screen_rect.right and self.speed > 0: self.kill() elif self.rect.right <= screen_rect.left and self.speed < 0: self.kill() else: time_test = pygame.time.get_ticks() if abs(time_test - self.last_frame) > self.wait_interval: self.last_frame = time_test self.death_index += 1 if self.death_index >= len(self.death_frames): self.kill() else: self.image = self.death_frames[self.death_index] self.wait_interval += 500 def blitme(self): self.screen.blit(self.image, self.rect)
class Ghosts(Sprite): def __init__(self, screen, color): super(Ghosts, self).__init__() self.color = color # ghost type self.screen = screen self.height = 35 self.width = 35 self.reset() Cyan_sheet = SheetSprites.sheetSprites('images/Cyan.png') Yellow_sheet = SheetSprites.sheetSprites('images/Yellow.png') Pink_sheet = SheetSprites.sheetSprites('images/Pink.png') Red_sheet = SheetSprites.sheetSprites('images/Red.png') Scared_sheet = SheetSprites.sheetSprites('images/Ghost_power.png') Eyes_sheet = SheetSprites.sheetSprites('images/Ghost_die.png') self.left_image = [] self.right_image = [] self.up_image = [] self.down_image = [] self.Scared = [ Scared_sheet.image_at((0, 0, 32, 38)), Scared_sheet.image_at((0, 38, 32, 38)), Scared_sheet.image_at((0, 76, 32, 38)), Scared_sheet.image_at((0, 114, 32, 38)) ] self.eyes = [ Eyes_sheet.image_at((0, 0, 23, 12)), Eyes_sheet.image_at((0, 12, 23, 12)), Eyes_sheet.image_at((0, 24, 23, 12)), Eyes_sheet.image_at((0, 36, 23, 12)) ] if color == "red": self.left_image = [ Red_sheet.image_at((0, 76, 32, 38)), Red_sheet.image_at((0, 228, 32, 38)) ] self.right_image = [ Red_sheet.image_at((0, 190, 32, 38)), Red_sheet.image_at((0, 266, 32, 38)) ] self.up_image = [ Red_sheet.image_at((0, 0, 32, 38)), Red_sheet.image_at((0, 114, 32, 38)) ] self.down_image = [ Red_sheet.image_at((0, 38, 32, 38)), Red_sheet.image_at((0, 152, 32, 38)) ] elif color == "cyan": self.left_image = [ Cyan_sheet.image_at((0, 76, 32, 38)), Cyan_sheet.image_at((0, 228, 32, 38)) ] self.right_image = [ Cyan_sheet.image_at((0, 190, 32, 38)), Cyan_sheet.image_at((0, 266, 32, 38)) ] self.up_image = [ Cyan_sheet.image_at((0, 0, 32, 38)), Cyan_sheet.image_at((0, 114, 32, 38)) ] self.down_image = [ Cyan_sheet.image_at((0, 38, 32, 38)), Cyan_sheet.image_at((0, 152, 32, 38)) ] elif color == "Yellow": self.left_image = [ Yellow_sheet.image_at((0, 76, 32, 38)), Yellow_sheet.image_at((0, 228, 32, 38)) ] self.right_image = [ Yellow_sheet.image_at((0, 190, 32, 38)), Yellow_sheet.image_at((0, 266, 32, 38)) ] self.up_image = [ Yellow_sheet.image_at((0, 0, 32, 38)), Yellow_sheet.image_at((0, 114, 32, 38)) ] self.down_image = [ Yellow_sheet.image_at((0, 38, 32, 38)), Yellow_sheet.image_at((0, 152, 32, 38)) ] elif color == "pink": self.left_image = [ Pink_sheet.image_at((0, 76, 32, 38)), Pink_sheet.image_at((0, 228, 32, 38)) ] self.right_image = [ Pink_sheet.image_at((0, 190, 32, 38)), Pink_sheet.image_at((0, 266, 32, 38)) ] self.up_image = [ Pink_sheet.image_at((0, 0, 32, 38)), Pink_sheet.image_at((0, 114, 32, 38)) ] self.down_image = [ Pink_sheet.image_at((0, 38, 32, 38)), Pink_sheet.image_at((0, 152, 32, 38)) ] self.rect = pygame.transform.scale( self.up_image[0], (self.height, self.width)).get_rect() self.rect.x, self.rect.y = 330, 315 self.rect.left -= self.rect.width self.rect.top -= self.rect.height self.image = [None, None] self.image = self.up_image self.moving_up = True self.moving_down = False self.moving_left = False self.moving_right = False self.last_move = "up/down" self.last_intersection = None self.speed = 1 # ghosts are blue self.afraid = False # ghosts are eyes self.DEAD = False self.value = 0 self.font = SysFont(None, 16, italic=True) self.score_image = self.font.render(str(self.value), True, (255, 255, 255), (0, 0, 0)) # how long to show score self.frames = 0 def update(self): if self.moving_left == True: self.rect.x -= self.speed self.image = self.left_image elif self.moving_right == True: self.rect.x += self.speed self.image = self.right_image elif self.moving_up == True: self.rect.y -= self.speed self.image = self.up_image elif self.moving_down == True: self.rect.y += self.speed self.image = self.down_image def blitghosts(self): if self.DEAD: if self.moving_left: self.screen.screen.blit(self.eyes[2], self.rect) elif self.moving_right: self.screen.screen.blit(self.eyes[3], self.rect) elif self.moving_up: self.screen.screen.blit(self.eyes[1], self.rect) elif self.moving_down: self.screen.screen.blit(self.eyes[0], self.rect) elif self.afraid: if self.frames <= 720: if pygame.time.get_ticks() % 200 <= 50: self.screen.screen.blit(self.Scared[2], self.rect) elif pygame.time.get_ticks() % 200 <= 100: self.screen.screen.blit(self.Scared[3], self.rect) elif pygame.time.get_ticks() % 200 <= 150: self.screen.screen.blit(self.Scared[2], self.rect) else: self.screen.blit(self.Scared[3], self.rect) elif self.frames <= 960: if pygame.time.get_ticks() % 200 <= 50: self.screen.blit(self.Scared[0], self.rect) elif pygame.time.get_ticks() % 200 <= 100: self.screen.blit(self.Scared[1], self.rect) elif pygame.time.get_ticks() % 200 <= 150: self.screen.blit(self.Scared[2], self.rect) else: self.screen.blit(self.Scared[3], self.rect) else: if pygame.time.get_ticks() % 200 <= 50: self.screen.blit(self.image[0], self.rect) elif pygame.time.get_ticks() % 200 <= 100: self.screen.blit(self.image[1], self.rect) elif pygame.time.get_ticks() % 200 <= 150: self.screen.blit(self.image[0], self.rect) else: self.screen.blit(self.image[1], self.rect) if self.frames <= 60 and self.DEAD: self.screen.blit(self.score_image, self.rect) self.frames += 1 if self.frames <= 960 and self.afraid: self.frames += 1 elif self.frames > 960 and self.afraid: self.afraid = False self.frames = 0 def resetPosition(self): self.moving_up = True # Start with the ghosts going up self.moving_down = False self.moving_left = False self.moving_right = False self.rect.x, self.rect.y = 300, 300 self.afraid = False self.DEAD = False def reset(self): pass
class Plotter: def __init__(self, bot: 'Bot'): self.bot = bot self.bot.add_callback(self.run) pygame.init() self.win_size = (bot.game.map.width * CELL_SIZE, bot.game.map.height * CELL_SIZE) self.update_display_size() pygame.mouse.set_cursor(*pygame.cursors.tri_right) self.font = SysFont("vcrosdmono", 16) self.clock = pygame.time.Clock() self.speed_up = DEFAULT_SPEEDUP self.pause = False self.selected = None def run(self): self.clock.tick(int(FPS * self.speed_up) if not self.pause else 60) keys_mod = pygame.key.get_mods() for e in pygame.event.get(): if e.type == pygame.QUIT: raise SystemExit("QUIT") elif e.type == pygame.KEYDOWN: self.key_handler(e, keys_mod) elif e.type == pygame.KEYUP: self.key_handler(e, keys_mod, True) if e.type == pygame.MOUSEBUTTONUP: self.mouse_handler(e) self.screen.fill(BLACK) if not self.selected: self.draw_halite() else: self.draw_selected() self.draw_bases() self.draw_ships() label = self.font.render(self.info, 0, (255, 0, 0)) self.screen.blit(label, (0, 0)) mouse = pygame.mouse.get_pos() pos = mul_tuple(mouse, 1 / CELL_SIZE, integer=True) halite_hover = self.font.render(str(self.bot.game.map[pos].halite_amount), 0, GREY) self.screen.blit(halite_hover, mouse) display.update() return not self.pause def draw_halite(self): for cell in self.bot.game.map: pygame.draw.rect( self.screen, mul_tuple((250, 250, 250), cell.halite_amount / constants.MAX_HALITE, integer=True), pos2rect(cell.position) ) def draw_selected(self): if isinstance(self.selected, Ship): debug = self.bot.debug_maps.get(self.selected.id, None) if not debug: self.draw_halite() return max_value = max(debug.values()) for position, halite in debug.items(): pygame.draw.rect( self.screen, mul_tuple((255, 255, 255), halite / max_value, integer=True), pos2rect(position) ) def draw_ships(self): for n, player in self.bot.game.players.items(): color = PLAYERS[n] for ship in player.get_ships(): # noinspection PyTypeChecker p = ship.position * CELL_SIZE + (CELL_SIZE // 2, CELL_SIZE // 2) pygame.draw.circle( self.screen, color, (p.x, p.y), round(CELL_SIZE / 2.5) ) self.screen.blit(self.font.render(str(ship.id), 0, GREY), (p.x, p.y)) if ship.halite_amount: pygame.draw.circle( self.screen, WHITE, (p.x, p.y), round(CELL_SIZE / 2.5 * (ship.halite_amount / constants.MAX_HALITE)) ) if ship.target: pygame.draw.lines( self.screen, mul_tuple(color, .7, integer=True), False, ( tuple(ship.position * CELL_SIZE + CELL_SIZE // 2), tuple(ship.target * CELL_SIZE + CELL_SIZE // 2) ), 1 ) def draw_bases(self): for n, player in self.bot.game.players.items(): color = PLAYERS[n] for base in (player.shipyard,): pygame.draw.rect( self.screen, color, pos2rect(base.position), 1 ) def update_display_size(self): self.screen = display.set_mode(self.win_size, pygame.DOUBLEBUF | pygame.RESIZABLE) display.flip() def key_handler(self, e, m: int, up=False): if not up: logging.debug(f"Press {e.unicode}") if m & pygame.KMOD_ALT and e.key == pygame.K_F4: raise SystemExit("QUIT") elif e.unicode == ',': # '<' self.speed_up /= 2 elif e.unicode == '.': # '>' self.speed_up *= 2 elif e.key == pygame.K_SPACE: self.pause = not self.pause def mouse_handler(self, e): map_pos = tuple(map(int, mul_tuple(e.pos, 1 / CELL_SIZE))) cell = self.bot.game.map[map_pos] logging.info(f"Cell: pos={cell.position} halite={cell.halite_amount}") if cell.ship: ship = cell.ship logging.info(f"Ship: id={ship.id} halite={ship.halite_amount}") if ship.owner == self.bot.game.me.id: self.selected = ship else: self.selected = None @property def info(self): return f"{self.bot.game.turn_number}/{constants.MAX_TURNS} X{self.speed_up:.0f} |" \ f" G: {self.bot.game.players[0].halite_amount:>5d} | " \ f" R: {self.bot.game.players[1].halite_amount:>5d}"
class Scoreboard: def __init__(self, ai_settings: Settings, screen: SurfaceType, stats: GameStats): self._screen = screen self._screen_rect = screen.get_rect() self._ai_settings = ai_settings self._stats = stats self._text_color = 90, 200, 50 self._font = SysFont(None, 48) self.prep_score() self.prep_high_score() self.prep_level() self.prep_ships() def prep_score(self): rounded_score = int(round(self._stats.score, -1)) score_str = "{:,}".format(rounded_score) self.score_image = self._font.render(score_str, True, self._text_color, self._ai_settings.bg_color) self._score_rect = self.score_image.get_rect() self._score_rect.right = self._screen_rect.right - 20 self._score_rect.top = 20 def prep_high_score(self): high_score = int(round(self._stats.high_score, -1)) high_score_str = "{:,}".format(high_score) self._high_score_image = self._font.render(high_score_str, True, self._text_color, self._ai_settings.bg_color) # Center high score at the top of the screen self._high_score_rect = self._high_score_image.get_rect() self._high_score_rect.centerx = self._screen_rect.centerx self._high_score_rect.top = self._score_rect.top def prep_level(self): self._level_image = self._font.render(str(self._stats.level), True, self._text_color, self._ai_settings.bg_color) self._level_rect = self._level_image.get_rect() self._level_rect.right = self._score_rect.right self._level_rect.top = self._score_rect.bottom + 10 def prep_ships(self): self.ships = Group() for ship_number in range(self._stats.ships_left): ship = Ship(self._ai_settings, self._screen) ship.rect.x = 10 + ship_number * ship.rect.width ship.rect.y = 10 self.ships.add(ship) def show_score(self): self._screen.blit(self.score_image, self._score_rect) self._screen.blit(self._high_score_image, self._high_score_rect) self._screen.blit(self._level_image, self._level_rect) self.ships.draw(self._screen)
class Scoreboard: """Initialize sb""" def __init__(self, ai_settings, screen, stats): self.screen = screen self.screen_rect = screen.get_rect() self.ai_settings = ai_settings self.stats = stats # Font self.text_color = (238, 232, 170) self.font = SysFont(None, 48) # set score image self.score_image = None self.score_rect = None # set hs image self.hs_image = None self.hs_rect = None # level image self.level_image = None self.level_rect = None # ships left self.ships = None # initialize score, high score, level, ships self.prep_score() self.prep_hs() self.prep_level() self.prep_ships() def prep_score(self): """rendering score as image""" rounded_score = int(round(self.stats.score, -1)) score_str = 'Score: {:,}'.format(rounded_score) self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color) # Display the score in the top right corner self.score_rect = self.score_image.get_rect() self.score_rect.right = self.screen_rect.right - 20 self.score_rect.top = 20 def prep_hs(self): """Turn high score into a rendered image""" high_score = int(round(self.stats.hs, -1)) high_score_str = 'High Score: {:,}'.format(high_score) self.hs_image = self.font.render(high_score_str, True, self.text_color, self.ai_settings.bg_color) # Center high score at top of the screen self.hs_rect = self.hs_image.get_rect() self.hs_rect.centerx = self.screen_rect.centerx self.hs_rect.top = self.score_rect.top def prep_level(self): """rendering level as image""" self.level_image = self.font.render('Level: ' + str(self.stats.level), True, self.text_color, self.ai_settings.bg_color) # Position level below score self.level_rect = self.level_image.get_rect() self.level_rect.right = self.score_rect.right self.level_rect.top = self.score_rect.bottom + 10 def prep_ships(self): """display ship""" self.ships = Group() for ship_number in range(self.stats.ships_left): ship = Ship(self.ai_settings, self.screen) ship.rect.x = 10 + ship_number * (ship.rect.width + 5) ship.rect.y = 10 self.ships.add(ship) def show_score(self): """display score""" self.screen.blit(self.score_image, self.score_rect) self.screen.blit(self.hs_image, self.hs_rect) self.screen.blit(self.level_image, self.level_rect) # display ships self.ships.draw(self.screen)
class Ghosts(Sprite): def __init__(self, screen, color): super(Ghosts, self).__init__() self.color = color # ghost type self.screen = screen self.height = 35 self.width = 35 Cyan_SS = SpriteSheet.spritesheet('images/Cyan/CyanSpriteSheet.png') Orange_SS = SpriteSheet.spritesheet('images/Orange/OrangeSpriteSheet.png') Pink_SS = SpriteSheet.spritesheet('images/Pink/PinkSpriteSheet.png') Red_SS = SpriteSheet.spritesheet('images/Red/RedSpriteSheet.png') Freight_ss = SpriteSheet.spritesheet('images/PowerPelletSpriteSheet.png') Eyes_ss = SpriteSheet.spritesheet('images/EyesSpriteSheet.png') self.left_image = [] self.right_image = [] self.up_image = [] self.down_image = [] self.freight = [Freight_ss.image_at((0,0,32,38)), Freight_ss.image_at((0,38,32,38)), Freight_ss.image_at((0,76,32,38)), Freight_ss.image_at((0,114,32,38))] self.eyes = [Eyes_ss.image_at((0,0,23,12)), Eyes_ss.image_at((0,12,23,12)), Eyes_ss.image_at((0,24,23,12)), Eyes_ss.image_at((0,36,23,12))] if color == "red": self.left_image = [Red_SS.image_at((0,76,32,38)), Red_SS.image_at((0,228, 32,38))] self.right_image = [Red_SS.image_at((0, 190, 32, 38)), Red_SS.image_at((0, 266, 32, 38))] self.up_image = [Red_SS.image_at((0, 0, 32, 38)), Red_SS.image_at((0, 114, 32, 38))] self.down_image = [Red_SS.image_at((0, 38, 32, 38)), Red_SS.image_at((0, 152, 32, 38))] elif color == "cyan": self.left_image = [Cyan_SS.image_at((0, 76, 32, 38)), Cyan_SS.image_at((0, 228, 32, 38))] self.right_image = [Cyan_SS.image_at((0, 190, 32, 38)), Cyan_SS.image_at((0, 266, 32, 38))] self.up_image = [Cyan_SS.image_at((0, 0, 32, 38)), Cyan_SS.image_at((0, 114, 32, 38))] self.down_image = [Cyan_SS.image_at((0, 38, 32, 38)), Cyan_SS.image_at((0, 152, 32, 38))] elif color == "orange": self.left_image = [Orange_SS.image_at((0, 76, 32, 38)), Orange_SS.image_at((0, 228, 32, 38))] self.right_image = [Orange_SS.image_at((0, 190, 32, 38)), Orange_SS.image_at((0, 266, 32, 38))] self.up_image = [Orange_SS.image_at((0, 0, 32, 38)), Orange_SS.image_at((0, 114, 32, 38))] self.down_image = [Orange_SS.image_at((0, 38, 32, 38)), Orange_SS.image_at((0, 152, 32, 38))] elif color == "pink": self.left_image = [Pink_SS.image_at((0, 76, 32, 38)), Pink_SS.image_at((0, 228, 32, 38))] self.right_image = [Pink_SS.image_at((0, 190, 32, 38)), Pink_SS.image_at((0, 266, 32, 38))] self.up_image = [Pink_SS.image_at((0, 0, 32, 38)), Pink_SS.image_at((0, 114, 32, 38))] self.down_image = [Pink_SS.image_at((0, 38, 32, 38)), Pink_SS.image_at((0, 152, 32, 38))] self.rect = pygame.transform.scale(self.up_image[0], (self.height, self.width)).get_rect() self.rect.x, self.rect.y = 330, 315 self.rect.left -= self.rect.width self.rect.top -= self.rect.height self.image = [None, None] #image placeholder self.image = self.up_image #start with ghost looking up self.moving_up = True #Start with the ghosts going up self.moving_down = False self.moving_left = False self.moving_right = False self.last_move = "up/down" self.last_intersection = None self.speed = 1 # ghosts are blue self.afraid = False # ghosts are eyes self.DEAD = False self.value = 0 self.font = SysFont(None, 16, italic=True) self.score_image = self.font.render(str(self.value), True, (255, 255, 255), (0, 0, 0)) # how long to show score self.frames = 0 def update(self): if self.moving_left == True: self.rect.x -= self.speed self.image = self.left_image elif self.moving_right == True: self.rect.x += self.speed self.image = self.right_image elif self.moving_up == True: self.rect.y -= self.speed self.image = self.up_image elif self.moving_down == True: self.rect.y += self.speed self.image = self.down_image def blitghosts(self): if(self.DEAD): if(self.moving_left): self.screen.blit(self.eyes[2], self.rect) elif (self.moving_right): self.screen.blit(self.eyes[3], self.rect) elif (self.moving_up): self.screen.blit(self.eyes[1], self.rect) elif (self.moving_down): self.screen.blit(self.eyes[0], self.rect) elif(self.afraid): if(self.frames <= 720): if pygame.time.get_ticks() % 200 <= 50: self.screen.blit(self.freight[2], self.rect) elif pygame.time.get_ticks() % 200 <= 100: self.screen.blit(self.freight[3], self.rect) elif pygame.time.get_ticks() % 200 <= 150: self.screen.blit(self.freight[2], self.rect) else: self.screen.blit(self.freight[3], self.rect) elif(self.frames <= 960): if pygame.time.get_ticks() % 200 <= 50: self.screen.blit(self.freight[0], self.rect) elif pygame.time.get_ticks() % 200 <= 100: self.screen.blit(self.freight[1], self.rect) elif pygame.time.get_ticks() % 200 <= 150: self.screen.blit(self.freight[2], self.rect) else: self.screen.blit(self.freight[3], self.rect) else: if pygame.time.get_ticks() % 200 <= 50: self.screen.blit(self.image[0], self.rect) elif pygame.time.get_ticks() % 200 <= 100: self.screen.blit(self.image[1], self.rect) elif pygame.time.get_ticks() % 200 <= 150: self.screen.blit(self.image[0], self.rect) else: self.screen.blit(self.image[1], self.rect) if(self.frames <= 60 and self.DEAD): self.screen.blit(self.score_image, self.rect) self.frames += 1 if(self.frames <= 960 and self.afraid): self.frames += 1 elif(self.frames > 960 and self.afraid): self.afraid = False self.frames = 0 def resetPosition(self): self.moving_up = True # Start with the ghosts going up self.moving_down = False self.moving_left = False self.moving_right = False self.rect.x, self.rect.y = 300, 300 self.afraid = False self.DEAD = False def playAfraidSound(self): mixer.Channel(1).play(pygame.mixer.Sound('sounds/ghosts_ambient.wav')) def playDeathSound(self): mixer.Channel(1).play(pygame.mixer.Sound('sounds/ghost_eaten.wav')) def playRetreatSound(self): mixer.Channel(1).play(pygame.mixer.Sound('sounds/ghosts_ambient_scared1.wav'))