Пример #1
0
 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
Пример #2
0
 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()
Пример #3
0
 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)
Пример #4
0
 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()
Пример #5
0
 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()
Пример #6
0
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))
Пример #7
0
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))
Пример #8
0
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))
Пример #9
0
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))
Пример #10
0
    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)
Пример #11
0
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)
Пример #12
0
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)