def create_some_random_pos(actor_cls, n, actor_type, actor_list, game, probability_each=100): """Creates some actors of the specified type in random positions of the board.""" ITERATIONS_MAX = 12 cell_size = lib_jp.Size(w=actor_cls.size.w, h=actor_cls.size.h) cell_size_with_border = lib_jp.Size( w=cell_size.w + Actor.CELL_SCREEN_SECURITY_SIZE, h=cell_size.h + Actor.CELL_SCREEN_SECURITY_SIZE) cell_total_security_border = lib_jp.Size( w=actor_cls.cell_added_size.w + Actor.CELL_SCREEN_SECURITY_SIZE, h=actor_cls.cell_added_size.h + Actor.CELL_SCREEN_SECURITY_SIZE) if len(actor_list) >= actor_cls.max_qty_on_board: return elif n + len(actor_list) >= actor_cls.max_qty_on_board: n = actor_cls.max_qty_on_board - len(actor_list) iterations = 0 for _ in range(n): if probability_each < 100 and randint(1, 100) > probability_each: continue actor_added = False iterations = 0 actor_obj = None while not actor_added and (iterations <= ITERATIONS_MAX): iterations += 1 x = randint(cell_total_security_border.w, Settings.screen_width - cell_size_with_border.w) y = randint( Settings.screen_near_top + cell_total_security_border.h, Settings.screen_height - cell_size_with_border.h) # Check if there is some sprite in this position position_not_taken = True rect1 = pg.Rect(x, y, cell_size.w, cell_size.h) if actor_cls.actor_type != ActorType.BAT: # Apples and mines cannot collide with any kind of sprite for sprite in game.active_sprites: if rect1.colliderect(sprite.rect): position_not_taken = False break else: # Bats cannot collide with snakes and other bats for sprite in game.snakes: if rect1.colliderect(sprite.rect): position_not_taken = False break if position_not_taken: for sprite in game.bats: if rect1.colliderect(sprite.rect): position_not_taken = False break if position_not_taken: actor_obj = actor_cls(x, y, actor_type, game=game) if actor_obj.actor_type == ActorType.BAT: actor_obj.change_x = randint(3, 5) actor_obj.change_y = randint(3, 5) actor_obj.initialize_boundaries() actor_added = True
def init(cls): if Settings.cell_size < 6: cls.cell_added_size = lib_jp.Size(w=round(5*Bat.cell_size_ratio), h=5) elif Settings.cell_size < 9: cls.cell_added_size = lib_jp.Size(w=round(3*Bat.cell_size_ratio), h=3) cls.size = lib_jp.Size(w=round(Settings.cell_size * Bat.cell_size_ratio * Bat.cell_size_multiplier + cls.cell_added_size.w), h=round(Settings.cell_size * Bat.cell_size_multiplier + cls.cell_added_size.h)) cls._resize_images_on_cache()
def clean(cls): cls.screen_width = 1260 cls.screen_height = 903 cls.screen_aspect_ratio = cls.screen_width / cls.screen_height cls.screen_aspect_ratio_portrait = cls.screen_height / cls.screen_width cls.screen_height_adjusted = None cls.screen_width_adjusted = None cls.portrait_mode = False cls.cell_size = CELL_DEFAULT_SIZE cls.cell_size_ratio = cls.screen_width * cls.screen_height / CELL_DEFAULT_SIZE cls.fps = FPS_DEFAULT cls.fps_paused = 14 cls.speed_pct = 100 cls.is_full_screen = False cls.im_screen_help = 'im_screen_help' cls.im_bg_start_game = 'im_bg_start_game' cls.snake_body_len_start = 5 cls.snake_body_len_max = 700 cls.score_to_win = SCORE_MAX_TO_WIN cls.screen_near_top = None cls.screen_near_bottom = None cls.screen_near_right = None cls.grid_width = None cls.grid_height = None cls.screen_bar_near_top = None cls.snake1_position_ini = None cls.snake2_position_ini = None cls.font_size1 = None cls.font_size2 = None cls.font_spc_btn_chars1 = None cls.font_spc_btn_chars2 = None # scores tuple with label and value x positions cls.score_pos_health1_xy = [15, 15] cls.score_pos_lives1 = [150, 190] cls.score_pos_apples1 = [240, 273] cls.score_pos_score1 = [340, 375] cls.score_pos_level = [498, 538] cls.score_pos_health2_xy = [644, 15] cls.score_pos_lives2 = [784, 824] cls.score_pos_apples2 = [884, 917] cls.score_pos_score2 = [984, 1021] cls.score_pos_health_size = [100, 15] cls.score_pos_power_size = cls.score_pos_health_size cls.font_pos_factor = 1 # position or size factor for some text to render cls.font_pos_factor_t2 = 1 # position or size factor for some other text to render cls.score_pos_apples_y = None cls.score_pos_apples_size = [18, 18] cls.score_pos_bullets_size = [16, 16] cls.score_pos_bullets_y = None cls.logo_jp_std_size = lib_jp.Size(w=244, h=55) cls.help_key_size = lib_jp.Size(w=218, h=57)
def init(cls): cls.size = lib_jp.Size( w=int(Settings.cell_size * Bullet.cell_size_ratio * Bullet.cell_size_multiplier + cls.cell_added_size.w), h=int(Settings.cell_size * Bullet.cell_size_multiplier + cls.cell_added_size.h)) cls._resize_images_on_cache()
def init(cls): cls.size = lib_jp.Size(w=Settings.cell_size + cls.cell_added_size.w, h=Settings.cell_size + cls.cell_added_size.h) cls._resize_images_on_cache()
class RecoveryPotion(pg.sprite.Sprite): """Represents a recovery potion.""" actor_type = ActorType.RECOVERY_POTION cell_added_size = lib_jp.Size(w=8, h=8) # Added size to the defined cell size. size = None sprite_images = {} max_qty_on_board = 10 def __init__(self, x, y, rec_potion_type, game): super().__init__() self.images_sprite_no = 1 self.frame = 0 self.rect = None self.rec_potion_type = rec_potion_type self.game = game self.rec_potion_type_txt = None self.qty = randint(15, 100) self.stat_type = None # the kind of stat. it replenishes self.rec_potion_type_txt = self.rec_potion_type.value self.stat_type = self.rec_potion_type if self.rec_potion_type == RecoveryPotionType.T1_HEALTH: rec_potion_type_short = 't1' elif self.rec_potion_type == RecoveryPotionType.T2_POWER: rec_potion_type_short = 't2' if not RecoveryPotion.sprite_images.get(self.rec_potion_type): image = pg.image.load(resources.file_name_get(name='im_rec_potion_', subname=rec_potion_type_short, num=1)).convert() image = pg.transform.smoothscale(image, RecoveryPotion.size) image.set_colorkey(Color.BLACK) RecoveryPotion.sprite_images[self.rec_potion_type] = image else: image = RecoveryPotion.sprite_images[self.rec_potion_type] self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # Add rec_potion to the active sprite list self.game.active_sprites.add(self) self.game.rec_potions.add(self) self.game.normal_items.add(self) @classmethod def init(cls): cls.size = lib_jp.Size(w=Settings.cell_size + cls.cell_added_size.w, h=Settings.cell_size + cls.cell_added_size.h) cls._resize_images_on_cache() @classmethod def resize_images(cls): if not RecoveryPotion.sprite_images: return for key, image in RecoveryPotion.sprite_images.items(): if RecoveryPotion.size.w != image.get_size()[0] or RecoveryPotion.size.h != image.get_size()[1]: RecoveryPotion.sprite_images[key] = pg.transform.smoothscale(image, RecoveryPotion.size) @classmethod def create_some_random_pos(cls, n, rec_potion_type, rec_potion_list, game, probability_each=100): Actor.create_some_random_pos(actor_cls=cls, n=n, actor_type=rec_potion_type, actor_list=rec_potion_list, game=game, probability_each=probability_each) @classmethod def _resize_images_on_cache(cls): if not cls.sprite_images: return for key, image in cls.sprite_images.items(): if cls.size.w != image.get_size()[0] or cls.size.h != image.get_size()[1]: cls.sprite_images[key] = pg.transform.smoothscale(image, cls.size) @staticmethod def create_some(rec_potions, rec_potion_list, game): for rec_potion in rec_potions: rec_potion_list.add(RecoveryPotion(rec_potion[0], rec_potion[1], rec_potion[2], game))
class Mine(pg.sprite.Sprite): """Represents a mine.""" actor_type = ActorType.MINE cell_added_size = lib_jp.Size(w=5, h=5) # Added size to the defined cell size. size = None sprite_images = {} max_qty_on_board = None def __init__(self, x, y, mine_type, game): super().__init__() self.images_sprite_no = 1 self.frame = 0 self.rect = None self.mine_type = mine_type self.game = game self.mine_type_txt = None self.attack_power = None self.health_total = None self.health = None if self.mine_type == MineType.T1_AQUA: self.mine_type_txt = 'mines_t01' mine_type_short = 't1' self.health_total = 12 self.attack_power = MINE_T01_ATTACK_POWER elif self.mine_type == MineType.T2_LILAC: self.mine_type_txt = 'mines_t02' mine_type_short = 't2' self.health_total = 25 self.attack_power = MINE_T02_ATTACK_POWER if not Mine.sprite_images.get(self.mine_type): image_quality = '_md' if Settings.cell_size >= consts.CELL_SIZE_MIN_FOR_IM_MD else '' image = pg.image.load(resources.file_name_get(name='im_mine_', subname=mine_type_short, quality=image_quality, num=1)).convert() image = pg.transform.smoothscale(image, Mine.size) image.set_colorkey(Color.BLACK) Mine.sprite_images[self.mine_type] = image else: image = Mine.sprite_images[self.mine_type] self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.health = self.health_total # Add mine to the active sprite list self.game.active_sprites.add(self) self.game.mines.add(self) @classmethod def init(cls): cls.size = lib_jp.Size(w=Settings.cell_size + cls.cell_added_size.w, h=Settings.cell_size + cls.cell_added_size.h) cls._resize_images_on_cache() @classmethod def resize_images(cls): Mine.calculate_max_qty_on_board() if not Mine.sprite_images: return for key, image in Mine.sprite_images.items(): if Mine.size.w != image.get_size()[0] or Mine.size.h != image.get_size()[1]: Mine.sprite_images[key] = pg.transform.smoothscale(image, Mine.size) @classmethod def calculate_max_qty_on_board(cls): cls.max_qty_on_board = 5 + ((Settings.screen_width * Settings.screen_height) // (Settings.cell_size * Settings.cell_size * consts.MAX_DIVIDER_MINES_ON_BOARD)) if cls.max_qty_on_board > consts.MAX_MINES_ON_BOARD: cls.max_qty_on_board = consts.MAX_MINES_ON_BOARD @classmethod def create_some_random_pos(cls, n, mine_type, mine_list, game, probability_each=100): Actor.create_some_random_pos(actor_cls=cls, n=n, actor_type=mine_type, actor_list=mine_list, game=game, probability_each=probability_each) @classmethod def _resize_images_on_cache(cls): cls.calculate_max_qty_on_board() if not cls.sprite_images: return for key, image in cls.sprite_images.items(): if cls.size.w != image.get_size()[0] or cls.size.h != image.get_size()[1]: cls.sprite_images[key] = pg.transform.smoothscale(image, cls.size) @staticmethod def create_some(mines, mine_list, game): for mine in mines: mine_list.add(Mine(mine[0], mine[1], mine[2], game))
class Apple(pg.sprite.Sprite): """Represents an apple.""" actor_type = ActorType.APPLE cell_added_size = lib_jp.Size(w=5, h=5) # Added size to the defined cell size. size = None sprite_images = {} max_qty_on_board = None def __init__(self, x, y, apple_type, game): super().__init__() self.images_sprite_no = 1 self.frame = 0 self.rect = None self.apple_type = apple_type self.game = game self.apple_type_txt = None if self.apple_type == AppleType.T1_RED: self.apple_type_txt = 'apples_t01' apple_type_short = 't1' elif self.apple_type == AppleType.T2_GREEN: self.apple_type_txt = 'apples_t02' apple_type_short = 't2' elif self.apple_type == AppleType.T3_YELLOW: self.apple_type_txt = 'apples_t03' apple_type_short = 't3' if not Apple.sprite_images.get(self.apple_type): image_quality = '_md' if Settings.cell_size >= consts.CELL_SIZE_MIN_FOR_IM_MD else '' image = pg.image.load(resources.file_name_get(name='im_apple_', subname=apple_type_short, quality=image_quality, num=1)).convert() image = pg.transform.smoothscale(image, Apple.size) image.set_colorkey(Color.BLACK) Apple.sprite_images[self.apple_type] = image else: image = Apple.sprite_images[self.apple_type] self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # Add apple to the active sprite list self.game.active_sprites.add(self) self.game.apples.add(self) self.game.normal_items.add(self) @classmethod def init(cls): cls.size = lib_jp.Size(w=Settings.cell_size + cls.cell_added_size.w, h=Settings.cell_size + cls.cell_added_size.h) cls._resize_images_on_cache() @classmethod def calculate_max_qty_on_board(cls): cls.max_qty_on_board = 5 + ((Settings.screen_width * Settings.screen_height) // (Settings.cell_size * Settings.cell_size * consts.MAX_DIVIDER_APPLES_ON_BOARD)) if cls.max_qty_on_board > consts.MAX_APPLES_ON_BOARD: cls.max_qty_on_board = consts.MAX_APPLES_ON_BOARD @classmethod def create_some_random_pos(cls, n, apple_type, apple_list, game, probability_each=100): Actor.create_some_random_pos(actor_cls=cls, n=n, actor_type=apple_type, actor_list=apple_list, game=game, probability_each=probability_each) @classmethod def _resize_images_on_cache(cls): cls.calculate_max_qty_on_board() if not cls.sprite_images: return for key, image in cls.sprite_images.items(): if cls.size.w != image.get_size()[0] or cls.size.h != image.get_size()[1]: cls.sprite_images[key] = pg.transform.smoothscale(image, cls.size) @staticmethod def create_some(apples, apple_list, game): for apple in apples: apple_list.add(Apple(apple[0], apple[1], apple[2], game))
class Cartridge(pg.sprite.Sprite): """Represents a cartridge.""" actor_type = ActorType.CARTRIDGE cell_added_size = lib_jp.Size(w=6, h=6) # Added size to the defined cell size. size = None sprite_images = {} max_qty_on_board = 10 def __init__(self, x, y, cartridge_type, game): super().__init__() self.images_sprite_no = 1 self.frame = 0 self.rect = None self.cartridge_type = cartridge_type self.game = game self.cartridge_type_txt = None self.bullet_type = None # the kind of bullet it replenishes self.cartridge_type_txt = self.cartridge_type.value if self.cartridge_type == CartridgeType.T1_LASER1: cartridge_type_short = 't1' self.bullet_type = BulletType.T1_LASER1 self.qty = randint(5, 15) elif self.cartridge_type == CartridgeType.T2_LASER2: cartridge_type_short = 't2' self.bullet_type = BulletType.T2_LASER2 self.qty = randint(4, 15) elif self.cartridge_type == CartridgeType.T3_PHOTONIC: cartridge_type_short = 't3' self.bullet_type = BulletType.T3_PHOTONIC self.qty = randint(2, 5) elif self.cartridge_type == CartridgeType.T4_NEUTRONIC: cartridge_type_short = 't4' self.bullet_type = BulletType.T4_NEUTRONIC self.qty = randint(2, 5) if not Cartridge.sprite_images.get(self.cartridge_type): image = pg.image.load( resources.file_name_get(name='im_cartridge_', subname=cartridge_type_short, num=1)).convert() image = pg.transform.smoothscale(image, Cartridge.size) image.set_colorkey(Color.BLACK) Cartridge.sprite_images[self.cartridge_type] = image else: image = Cartridge.sprite_images[self.cartridge_type] self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # Add cartridge to the active sprite list self.game.active_sprites.add(self) self.game.cartridges.add(self) self.game.normal_items.add(self) @classmethod def init(cls): cls.size = lib_jp.Size(w=Settings.cell_size + cls.cell_added_size.w, h=Settings.cell_size + cls.cell_added_size.h) cls._resize_images_on_cache() @classmethod def resize_images(cls): if not Cartridge.sprite_images: return for key, image in Cartridge.sprite_images.items(): if (Cartridge.size.w != image.get_size()[0] or Cartridge.size.h != image.get_size()[1]): Cartridge.sprite_images[key] = pg.transform.smoothscale( image, Cartridge.size) @classmethod def create_some_random_pos(cls, n, cartridge_type, cartridge_list, game, probability_each=100): Actor.create_some_random_pos(actor_cls=cls, n=n, actor_type=cartridge_type, actor_list=cartridge_list, game=game, probability_each=probability_each) @classmethod def _resize_images_on_cache(cls): if not cls.sprite_images: return for key, image in cls.sprite_images.items(): if cls.size.w != image.get_size( )[0] or cls.size.h != image.get_size()[1]: cls.sprite_images[key] = pg.transform.smoothscale( image, cls.size) @staticmethod def create_some(cartridges, cartridge_list, game): for cartridge in cartridges: cartridge_list.add( Cartridge(cartridge[0], cartridge[1], cartridge[2], game))
def calculate_settings(cls, screen_width=None, screen_height=None, full_screen=None, cell_size=None, speed_pct=None, snake_body_len_start=None, snake_body_len_max=None, score_to_win=None, portrait_mode=None): def _calculate_max_screen_size(screen_width, screen_height): screen_max_width = min([SCREEN_MAX_WIDTH, cls.display_start_width]) screen_max_height = min( [SCREEN_MAX_HEIGHT, cls.display_start_height]) if screen_width and screen_width.isdigit(): cls.screen_width = int(screen_width) if cls.screen_width < SCREEN_MIN_WIDTH: cls.screen_width = SCREEN_MIN_WIDTH elif cls.screen_width > screen_max_width: cls.screen_width = screen_max_width if not screen_height or not screen_height.isdigit(): cls.screen_height = int(cls.screen_width / cls.screen_aspect_ratio) if cls.screen_height > screen_max_height: cls.screen_height = screen_max_height if screen_height and screen_height.isdigit(): cls.screen_height = int(screen_height) if cls.screen_height < SCREEN_MIN_HEIGHT: cls.screen_height = SCREEN_MIN_HEIGHT elif cls.screen_height > screen_max_height: cls.screen_height = screen_max_height if not cls.portrait_mode: cls.screen_width = int(cls.screen_height * cls.screen_aspect_ratio) else: cls.screen_width = int(cls.screen_height / cls.screen_aspect_ratio) if not screen_width or not screen_width.isdigit(): cls.screen_width = int(cls.screen_height * cls.screen_aspect_ratio) cls.clean() # Define screen values to resize the screen and images if necessary _calculate_max_screen_size(screen_width, screen_height) if portrait_mode: cls.portrait_mode = True if cls.screen_height < cls.screen_width: cls.screen_width, cls.screen_height = cls.screen_height, cls.screen_width _calculate_max_screen_size(str(cls.screen_width), str(cls.screen_height)) # Examine portrait mode if cls.screen_width < cls.screen_height: cls.im_screen_help = 'im_screen_help_vertical' cls.im_bg_start_game = 'im_bg_start_game_vertical' cls.screen_aspect_ratio = cls.screen_aspect_ratio_portrait cls.screen_height_adjusted = cls.screen_width cls.screen_width_adjusted = int(cls.screen_width * cls.screen_aspect_ratio_portrait) else: cls.screen_width_adjusted = int(cls.screen_height * cls.screen_aspect_ratio) cls.screen_height_adjusted = cls.screen_height # Resizes adjusted screen values for images if they are to high if cls.screen_height_adjusted > cls.screen_height: cls.screen_width_adjusted -= cls.screen_height_adjusted - cls.screen_height cls.screen_height_adjusted -= cls.screen_height_adjusted - cls.screen_height if cls.screen_width_adjusted > cls.screen_width: cls.screen_height_adjusted -= cls.screen_width_adjusted - cls.screen_width cls.screen_width_adjusted -= cls.screen_width_adjusted - cls.screen_width # Set full screen or windowed screen cls.is_full_screen = True if full_screen else False # Resizes cell if cell_size and cell_size.isdigit(): cls.cell_size = int(cell_size) if cls.cell_size < CELL_MIN_SIZE: cls.cell_size = CELL_MIN_SIZE elif cls.cell_size > CELL_MAX_SIZE: cls.cell_size = CELL_MAX_SIZE else: cls.cell_size = round(cls.screen_width * cls.screen_height / cls.cell_size_ratio) if cls.cell_size > CELL_DEFAULT_SIZE * 1.15: cls.cell_size = round(CELL_DEFAULT_SIZE * 1.15) elif cls.cell_size < CELL_DEFAULT_SIZE / 3.9: cls.cell_size = round(CELL_DEFAULT_SIZE / 2.1) elif cls.cell_size < CELL_DEFAULT_SIZE / 2: cls.cell_size = round(CELL_DEFAULT_SIZE / 1.9) # Set fps if speed_pct and speed_pct.isdigit(): cls.speed_pct = speed_pct cls.fps = int(cls.fps * int(speed_pct) / 100) if cls.fps < FPS_MIN: cls.fps = FPS_MIN elif cls.fps > FPS_MAX: cls.fps = FPS_MAX # Set snake body initial attributes if snake_body_len_start and snake_body_len_start.isdigit(): cls.snake_body_len_start = int(snake_body_len_start) if cls.snake_body_len_start < 1: cls.snake_body_len_start = 1 if snake_body_len_max and snake_body_len_max.isdigit(): cls.snake_body_len_max = int(snake_body_len_max) if cls.snake_body_len_max < cls.snake_body_len_start: cls.snake_body_len_max = cls.snake_body_len_start + 1 # Set score to win if score_to_win and score_to_win.isdigit(): cls.score_to_win = int(score_to_win) if cls.score_to_win < SCORE_MIN_TO_WIN: cls.score_to_win = SCORE_MIN_TO_WIN elif cls.score_to_win > SCORE_MAX_TO_WIN: cls.score_to_win = SCORE_MAX_TO_WIN # Set positions for images and text cls.screen_near_bottom = cls.screen_height - cls.cell_size + 1 cls.screen_near_right = cls.screen_width - cls.cell_size + 1 cls.grid_width = cls.screen_width // cls.cell_size cls.grid_height = cls.screen_height // cls.cell_size cls.screen_bar_near_top = 10 cls.snake1_position_ini = (cls.cell_size * 14, cls.screen_height // 5) cls.snake2_position_ini = (cls.cell_size * 14, cls.screen_height // 5 + cls.cell_size * 5) # Font sizes for scores, etc cls.font_size1 = 24 cls.font_size2 = 36 cls.font_spc_btn_chars1 = 15 cls.font_spc_btn_chars2 = 21 cls.score_pos_apples_y = cls.screen_bar_near_top + 5 cls.score_pos_bullets_y = cls.screen_bar_near_top + 29 # Adapt size of images and text for some tested scenarios if cls.screen_width <= SCREEN_MAX_WIDTH: if cls.screen_width < 341: cls.font_pos_factor = 0.29 elif cls.screen_width < 381: cls.font_pos_factor = 0.33 elif cls.screen_width < 420: cls.font_pos_factor = 0.35 elif cls.screen_width < 491: cls.font_pos_factor = 0.38 elif cls.screen_width < 540: cls.font_pos_factor = 0.44 elif cls.screen_width < 580: cls.font_pos_factor = 0.48 elif cls.screen_width < 650: cls.font_pos_factor = 0.51 elif cls.screen_width < 780: cls.font_pos_factor = 0.59 elif cls.screen_width < 860: cls.font_pos_factor = 0.67 elif cls.screen_width < 920: cls.font_pos_factor = 0.78 elif cls.screen_width < 1025: cls.font_pos_factor = 0.84 elif cls.screen_width < 1151: cls.font_pos_factor = 0.904 elif cls.screen_width < 1201: cls.font_pos_factor = 0.91 else: cls.font_pos_factor = 1.05 cls.font_pos_factor_t2 = cls.font_pos_factor if not cls.portrait_mode and cls.screen_width / cls.screen_height >= 2.5: cls.font_pos_factor_t2 = 0.55 cls.screen_bar_near_top = int(cls.screen_bar_near_top * cls.font_pos_factor) # Set score text and images positions and size cls.font_size1 = int(cls.font_size1 * cls.font_pos_factor) cls.font_size2 = int(cls.font_size2 * cls.font_pos_factor) cls.font_spc_btn_chars1 = int(cls.font_spc_btn_chars1 * cls.font_pos_factor) cls.font_spc_btn_chars2 = int(cls.font_spc_btn_chars2 * cls.font_pos_factor) cls.score_pos_lives1[0] = int(cls.score_pos_lives1[0] * cls.font_pos_factor) cls.score_pos_apples1[0] = int(cls.score_pos_apples1[0] * cls.font_pos_factor) cls.score_pos_score1[0] = int(cls.score_pos_score1[0] * cls.font_pos_factor) cls.score_pos_health1_xy[0] = int(cls.score_pos_health1_xy[0] * cls.font_pos_factor) cls.score_pos_level[0] = int(cls.score_pos_level[0] * cls.font_pos_factor) cls.score_pos_apples_y = int(cls.score_pos_apples_y * cls.font_pos_factor) cls.score_pos_bullets_y = int(cls.score_pos_bullets_y * cls.font_pos_factor) cls.score_pos_lives2[0] = int(cls.score_pos_lives2[0] * cls.font_pos_factor) cls.score_pos_apples2[0] = int(cls.score_pos_apples2[0] * cls.font_pos_factor) cls.score_pos_score2[0] = int(cls.score_pos_score2[0] * cls.font_pos_factor) cls.score_pos_health2_xy[0] = int(cls.score_pos_health2_xy[0] * cls.font_pos_factor) cls.score_pos_health_size[0] = int(cls.score_pos_health_size[0] * cls.font_pos_factor) cls.score_pos_health_size[1] = int(cls.score_pos_health_size[1] * cls.font_pos_factor) cls.score_pos_apples_size[0] = int(cls.score_pos_apples_size[0] * cls.font_pos_factor) cls.score_pos_apples_size[1] = int(cls.score_pos_apples_size[1] * cls.font_pos_factor) cls.score_pos_bullets_size[0] = int(cls.score_pos_bullets_size[0] * cls.font_pos_factor) cls.score_pos_bullets_size[1] = int(cls.score_pos_bullets_size[1] * cls.font_pos_factor) cls.score_pos_lives1[1] = int(cls.score_pos_lives1[1] * cls.font_pos_factor) cls.score_pos_apples1[1] = int(cls.score_pos_apples1[1] * cls.font_pos_factor) cls.score_pos_score1[1] = int(cls.score_pos_score1[1] * cls.font_pos_factor) cls.score_pos_level[1] = int(cls.score_pos_level[1] * cls.font_pos_factor) cls.score_pos_lives2[1] = int(cls.score_pos_lives2[1] * cls.font_pos_factor) cls.score_pos_apples2[1] = int(cls.score_pos_apples2[1] * cls.font_pos_factor) cls.score_pos_score2[1] = int(cls.score_pos_score2[1] * cls.font_pos_factor) cls.score_pos_health1_xy[1] = int(cls.score_pos_health1_xy[1] * cls.font_pos_factor) cls.score_pos_health2_xy[1] = int(cls.score_pos_health2_xy[1] * cls.font_pos_factor) elif cls.screen_width > 1350: cls.font_pos_factor = 1.2 cls.score_pos_lives1[0] = int(cls.score_pos_lives1[0] * cls.font_pos_factor) cls.score_pos_apples1[0] = int(cls.score_pos_apples1[0] * cls.font_pos_factor) cls.score_pos_score1[0] = int(cls.score_pos_score1[0] * cls.font_pos_factor) cls.score_pos_health1_xy[0] = int(cls.score_pos_health1_xy[0] * cls.font_pos_factor) cls.score_pos_level[0] = int(cls.score_pos_level[0] * cls.font_pos_factor) cls.score_pos_apples_y = int(cls.score_pos_apples_y * cls.font_pos_factor) cls.score_pos_bullets_y = int(cls.score_pos_bullets_y * cls.font_pos_factor) cls.score_pos_lives2[0] = int(cls.score_pos_lives2[0] * cls.font_pos_factor) cls.score_pos_apples2[0] = int(cls.score_pos_apples2[0] * cls.font_pos_factor) cls.score_pos_score2[0] = int(cls.score_pos_score2[0] * cls.font_pos_factor) cls.score_pos_health2_xy[0] = int(cls.score_pos_health2_xy[0] * cls.font_pos_factor) cls.score_pos_lives1[1] = int(cls.score_pos_lives1[1] * cls.font_pos_factor) cls.score_pos_apples1[1] = int(cls.score_pos_apples1[1] * cls.font_pos_factor) cls.score_pos_score1[1] = int(cls.score_pos_score1[1] * cls.font_pos_factor) cls.score_pos_level[1] = int(cls.score_pos_level[1] * cls.font_pos_factor) cls.score_pos_lives2[1] = int(cls.score_pos_lives2[1] * cls.font_pos_factor) cls.score_pos_apples2[1] = int(cls.score_pos_apples2[1] * cls.font_pos_factor) cls.score_pos_score2[1] = int(cls.score_pos_score2[1] * cls.font_pos_factor) cls.score_pos_health1_xy[1] = int(cls.score_pos_health1_xy[1] * cls.font_pos_factor) cls.score_pos_health2_xy[1] = int(cls.score_pos_health2_xy[1] * cls.font_pos_factor) if cls.screen_height <= SCREEN_MAX_HEIGHT: if cls.screen_height < 231: cls.screen_near_top = int(cls.screen_height * 0.187) elif cls.screen_height < 251: cls.screen_near_top = int(cls.screen_height * 0.17) elif cls.screen_height < 301: cls.screen_near_top = int(cls.screen_height * 0.143) elif cls.screen_height < 351: cls.screen_near_top = int(cls.screen_height * 0.128) elif cls.screen_height < 421: cls.screen_near_top = int(cls.screen_height * 0.1) elif cls.screen_height < 481: cls.screen_near_top = int(cls.screen_height * 0.087) elif cls.screen_height < 541: cls.screen_near_top = int(cls.screen_height * 0.079) elif cls.screen_height < 651: cls.screen_near_top = int(cls.screen_height * 0.068) elif cls.screen_height < 781: cls.screen_near_top = int(cls.screen_height * 0.057) elif cls.screen_height < 861: cls.screen_near_top = int(cls.screen_height * 0.050) elif cls.screen_height < 981: cls.screen_near_top = int(cls.screen_height * 0.046) else: cls.screen_near_top = int(cls.screen_height * 0.04) cls.screen_near_top = int(cls.screen_near_top * cls.font_pos_factor * 2) # Sprite health bar size and relative position cls.score_pos_power_size = cls.score_pos_health_size cls.sprite_health_bar_size = lib_jp.Size(w=8 + cls.cell_size * 1.8, h=2 + cls.cell_size / 2.5) cls.sprite_health_bar_pos_rel = lib_jp.Point( x=-1 + cls.cell_size * 1.2 if cls.cell_size * 1.2 > 8 else 8, y=cls.cell_size * 0.8 if cls.cell_size * 0.8 < 9 else 9)
class Bat(pg.sprite.Sprite): """Represents a bat.""" actor_type = ActorType.BAT cell_added_size = lib_jp.Size(w=0, h=0) # Added size to the defined cell size. cell_size_multiplier = 2.6 cell_size_ratio = 1.79 size = None sprite_images = {} max_qty_on_board = consts.MAX_BATS_ON_BOARD def __init__(self, x, y, bat_type, game, change_x=0, change_y=0): super().__init__() self.images_sprite_no = 4 self.frame = randint(0, self.images_sprite_no - 1) self.rect = None self.bat_type = bat_type self.game = game self.bat_type_txt = None self.attack_power = None self.health_total = None self.health = None self.boundary_left = None self.boundary_right = None self.boundary_top = None self.boundary_bottom = None self.change_x = change_x self.change_y = change_y self.direction = consts.DIRECTION_RIGHT self.animate_timer = pg.time.get_ticks() self.drop_item_pct = 100 walking_frames = [] if self.bat_type == BatType.T1_BLUE: self.bat_type_txt = 'bats_t01' bat_type_short = 't1' self.attack_power = 10 self.health_total = 90 self.drop_item_pct = 100 elif self.bat_type == BatType.T2_LILAC: self.bat_type_txt = 'bats_t02' bat_type_short = 't2' self.attack_power = 13 self.health_total = 120 self.drop_item_pct = 100 elif self.bat_type == BatType.T3_RED: self.bat_type_txt = 'bats_t03' bat_type_short = 't3' self.attack_power = 18 self.health_total = 240 self.drop_item_pct = 100 if not Bat.sprite_images.get(self.bat_type): image_quality = '_md' if Settings.cell_size >= consts.CELL_SIZE_MIN_FOR_IM_MD else '' for i in range(self.images_sprite_no): image = pg.image.load(resources.file_name_get(name='im_bat_', subname=bat_type_short, quality=image_quality, num=i+1)).convert() image = pg.transform.smoothscale(image, Bat.size) image.set_colorkey(Color.BLACK) walking_frames.append(image) Bat.sprite_images[self.bat_type] = (image, walking_frames) else: image = Bat.sprite_images[self.bat_type][0] if self.change_x > 0: self.direction = consts.DIRECTION_RIGHT elif self.change_x < 0: self.direction = consts.DIRECTION_LEFT self.image = Bat.sprite_images[self.bat_type][1][0] self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.initialize_boundaries() self.health = self.health_total # Add bat to the active sprite list self.game.active_sprites.add(self) self.game.bats.add(self) def initialize_boundaries(self): if self.change_x: self.boundary_left = 0 self.boundary_right = Settings.screen_width - self.rect.w if self.change_y: self.boundary_top = Settings.screen_near_top self.boundary_bottom = Settings.screen_height - self.rect.h def update(self): self.rect.x += self.change_x self.rect.y += self.change_y # Calculate frame of the animated sprite if self.game.current_time - self.animate_timer > Settings.fps * 5: self.animate_timer = self.game.current_time self.frame = self.frame + 1 if self.frame < self.images_sprite_no - 1 else 0 self.image = Bat.sprite_images[self.bat_type][1][self.frame] # Check boundaries and see if we need to reverse direction. if self.change_y: if self.rect.bottom > self.boundary_bottom or self.rect.top < self.boundary_top: self.change_y *= -1 self.direction = consts.DIRECTION_UP if self.change_y < 0 else consts.DIRECTION_DOWN if self.change_x: if self.rect.x < self.boundary_left or self.rect.x > self.boundary_right: self.change_x *= -1 self.direction = consts.DIRECTION_LEFT if self.change_x < 0 else consts.DIRECTION_RIGHT # Check if it hit any bullet bullet_hit_list = pg.sprite.spritecollide(self, self.game.bullets, False) for bullet in bullet_hit_list: bullet.kill() self.health -= bullet.attack_power if self.health < 1: self.game.sound_effects and resources.Resource.bat_scream_sound.play() self.kill() bullet.owner.stats['bats'] += 1 bullet.owner.stats[self.bat_type_txt] += 1 bullet.owner.stats['score'] += ExperiencePoints.xp_points[self.bat_type_txt] else: self.game.sound_effects and resources.Resource.bullet_hit_sound.play() def draw_health(self): Actor.draw_health(self) def drop_item(self): pass @classmethod def init(cls): if Settings.cell_size < 6: cls.cell_added_size = lib_jp.Size(w=round(5*Bat.cell_size_ratio), h=5) elif Settings.cell_size < 9: cls.cell_added_size = lib_jp.Size(w=round(3*Bat.cell_size_ratio), h=3) cls.size = lib_jp.Size(w=round(Settings.cell_size * Bat.cell_size_ratio * Bat.cell_size_multiplier + cls.cell_added_size.w), h=round(Settings.cell_size * Bat.cell_size_multiplier + cls.cell_added_size.h)) cls._resize_images_on_cache() @classmethod def create_some_random_pos(cls, n, bat_type, bat_list, game, probability_each=100): Actor.create_some_random_pos(actor_cls=cls, n=n, actor_type=bat_type, actor_list=bat_list, game=game, probability_each=probability_each) @classmethod def _resize_images_on_cache(cls): if not cls.sprite_images: return for key, tuple_images in cls.sprite_images.items(): if (cls.size.w != tuple_images[0].get_size()[0] or cls.size.h != tuple_images[0].get_size()[1]): cls.sprite_images[key] = pg.transform.smoothscale(tuple_images[0], cls.size)
class Bullet(pg.sprite.Sprite): """Represents a bullet.""" actor_type = ActorType.BULLET cell_added_size = lib_jp.Size(w=-1, h=-1) # Added size to the defined cell size. cell_size_multiplier = 1 cell_size_ratio = 1 size = None sprite_images = {} power_min_to_use = { BulletType.T1_LASER1: 1, BulletType.T2_LASER2: 10, BulletType.T3_PHOTONIC: 20, BulletType.T4_NEUTRONIC: 35, } power_consumption = { BulletType.T1_LASER1: 0.2, BulletType.T2_LASER2: 0.5, BulletType.T3_PHOTONIC: 3, BulletType.T4_NEUTRONIC: 7, } def __init__(self, x, y, bullet_type, game, owner, change_x=0, change_y=0): super().__init__() self.images_sprite_no = 1 self.frame = randint(0, self.images_sprite_no - 1) self.rect = None self.bullet_type = bullet_type self.game = game self.owner = owner self.bullet_type_txt = None self.health_total = 100 self.health = self.health_total self.attack_power = None self.bullet_range = BULLET_STD_RANGE self.boundary_left = None self.boundary_right = None self.boundary_top = None self.boundary_bottom = None self.change_x = change_x self.change_y = change_y self.direction = None self.animate_timer = self.game.current_time self.bullet_type_txt = self.bullet_type.value if self.bullet_type == BulletType.T1_LASER1: bullet_type_short = 't1' self.attack_power = BULLET_POWER_BASE self.bullet_range = int(self.bullet_range * 1.25) elif self.bullet_type == BulletType.T2_LASER2: bullet_type_short = 't2' self.attack_power = BULLET_POWER_BASE * 1.4 self.bullet_range = int(self.bullet_range * 1.15) elif self.bullet_type == BulletType.T3_PHOTONIC: bullet_type_short = 't3' self.attack_power = BULLET_POWER_BASE * 3.4 elif self.bullet_type == BulletType.T4_NEUTRONIC: bullet_type_short = 't4' self.attack_power = BULLET_POWER_BASE * 4.5 if not Bullet.sprite_images.get( (self.bullet_type, consts.DIRECTION_RIGHT)): image_quality = '_md' if Settings.cell_size >= consts.CELL_SIZE_MIN_FOR_IM_MD else '' image = pg.image.load( resources.file_name_get(name='im_bullet_', subname=bullet_type_short, quality=image_quality, num=1)).convert() image = pg.transform.smoothscale(image, Bullet.size) image.set_colorkey(Color.BLACK) Bullet.sprite_images[(self.bullet_type, consts.DIRECTION_RIGHT)] = image image = pg.image.load( resources.file_name_get(name='im_bullet_', subname=bullet_type_short, quality=image_quality, num=1)).convert() image = pg.transform.flip(image, True, False) image = pg.transform.smoothscale(image, Bullet.size) image.set_colorkey(Color.BLACK) Bullet.sprite_images[(self.bullet_type, consts.DIRECTION_LEFT)] = image image = pg.image.load( resources.file_name_get(name='im_bullet_', subname=bullet_type_short, quality=image_quality, num=1)).convert() image = pg.transform.rotate(image, 90) image = pg.transform.smoothscale(image, Bullet.size) image.set_colorkey(Color.BLACK) Bullet.sprite_images[(self.bullet_type, consts.DIRECTION_UP)] = image image = pg.image.load( resources.file_name_get(name='im_bullet_', subname=bullet_type_short, quality=image_quality, num=1)).convert() image = pg.transform.rotate(image, 270) image = pg.transform.smoothscale(image, Bullet.size) image.set_colorkey(Color.BLACK) Bullet.sprite_images[(self.bullet_type, consts.DIRECTION_DOWN)] = image if self.change_x > 0: self.direction = consts.DIRECTION_RIGHT elif self.change_x < 0: self.direction = consts.DIRECTION_LEFT elif self.change_y > 0: self.direction = consts.DIRECTION_DOWN elif self.change_y < 0: self.direction = consts.DIRECTION_UP self.image = Bullet.sprite_images[(self.bullet_type, consts.DIRECTION_RIGHT)] self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.initialize_boundaries() # Add bullet to the active sprite list self.game.active_sprites.add(self) self.game.bullets.add(self) def initialize_boundaries(self): if self.change_x: self.boundary_left = 0 self.boundary_right = Settings.screen_width - self.rect.w if self.change_y: self.boundary_top = 0 self.boundary_bottom = Settings.screen_height - self.rect.h def update(self): self.rect.x += self.change_x self.rect.y += self.change_y self.image = Bullet.sprite_images[(self.bullet_type, self.direction)] # Check boundaries and see if we need to kill the bullet if self.boundary_left is not None: if (self.change_x < 0 and self.rect.x < self.boundary_left) \ or (self.change_x >= 0 and self.rect.x > self.boundary_right): self.kill() if self.boundary_top is not None: if (self.change_y < 0 and self.rect.y < self.boundary_top) \ or (self.change_y >= 0 and self.rect.y > self.boundary_bottom): self.kill() # Check if it hit any normal item (apples, cartridges, recovery potions...) item_hit_list = pg.sprite.spritecollide(self, self.game.normal_items, False) for item in item_hit_list: self.game.sound_effects and resources.Resource.bullet_hit_sound.play( ) self.kill() item.kill() # Check if it hit any mine mine_hit_list = pg.sprite.spritecollide(self, self.game.mines, False) for mine in mine_hit_list: self.game.sound_effects and resources.Resource.bullet_hit_sound.play( ) self.kill() mine.health -= self.attack_power if mine.health < 1: self.owner.stats[mine.mine_type_txt] += 1 self.owner.stats['mines'] += 1 self.owner.stats['score'] += ExperiencePoints.xp_points[ mine.mine_type_txt] mine.kill() # Check if it hit any other bullet bullet_hit_list = pg.sprite.spritecollide(self, self.game.bullets, False) for bullet in bullet_hit_list: if bullet is not self: self.game.sound_effects and resources.Resource.bullet_hit_sound.play( ) self.kill() bullet.kill() @classmethod def init(cls): cls.size = lib_jp.Size( w=int(Settings.cell_size * Bullet.cell_size_ratio * Bullet.cell_size_multiplier + cls.cell_added_size.w), h=int(Settings.cell_size * Bullet.cell_size_multiplier + cls.cell_added_size.h)) cls._resize_images_on_cache() @classmethod def shot(cls, bullet_type, change_x, change_y, owner, game): if bullet_type == BulletType.T1_LASER1: game.sound_effects and resources.Resource.bullet_t1_sound.play() elif bullet_type == BulletType.T2_LASER2: game.sound_effects and resources.Resource.bullet_t2_sound.play() elif bullet_type == BulletType.T3_PHOTONIC: game.sound_effects and resources.Resource.bullet_t3_sound.play() elif bullet_type == BulletType.T4_NEUTRONIC: game.sound_effects and resources.Resource.bullet_t4_sound.play() Bullet( x=owner.rect.x + (change_x and ((owner.rect.w + 1) * int(change_x / math.fabs(change_x))) or 0), y=owner.rect.y + (not change_x and ((owner.rect.h + 1) * int(change_y / math.fabs(change_y))) or 0), bullet_type=bullet_type, game=game, change_x=change_x, change_y=not change_x and change_y or 0, owner=owner) @classmethod def _resize_images_on_cache(cls): if not cls.sprite_images: return for key, image in cls.sprite_images.items(): if cls.size.w != image.get_size( )[0] or cls.size.h != image.get_size()[1]: cls.sprite_images[key] = pg.transform.smoothscale( image, cls.size)