コード例 #1
0
class Player(Mob):
    def __init__(self):
        (max_health, health_states, radius, body, MAX_VEL, ACC, gun_type,
         bg_radius, superpower) = PLAYER_PARAMS[(0, 0)]

        Mob.__init__(self,
                     name='Player',
                     x=c.SCR_W2,
                     y=c.SCR_H2,
                     health=0,
                     health_states=health_states,
                     bubbles=0,
                     radius=radius,
                     body=body,
                     gun_type=gun_type)

        self.pos = np.array([self.x, self.y], dtype=float)
        self.MAX_VEL = MAX_VEL
        self.vel_x, self.vel_y = 0, 0
        self.ACC = ACC
        self.acc_x, self.acc_y = 0, 0
        self.MU = c.MU
        self.mu_x, self.mu_y = 0, 0
        self.moving_left = False
        self.moving_right = False
        self.moving_up = False
        self.moving_down = False
        self.superpower = superpower_factory(superpower)
        self.is_shooting = False
        self.bullets = []
        self.homing_bullets = []
        self.shurikens = []
        self.is_max_tank = False
        self.max_health = max_health
        self.bg_radius = bg_radius
        self.armor_on = [False]
        self.invisible = [False]
        self.state = (0, 0)
        self.states_history = [(0, 0)]

    def handler(self, e_type, key):
        if key == pg.K_a:
            self.moving_left = True if e_type == pg.KEYDOWN else False
        elif key == pg.K_d:
            self.moving_right = True if e_type == pg.KEYDOWN else False
        elif key == pg.K_w:
            self.moving_up = True if e_type == pg.KEYDOWN else False
        elif key == pg.K_s:
            self.moving_down = True if e_type == pg.KEYDOWN else False
        elif key == 1:
            self.is_shooting = False if e_type == pg.MOUSEBUTTONUP else True
        elif key == pg.K_SPACE:
            self.superpower.on = True if e_type == pg.KEYDOWN else False

    def move(self, dx, dy):
        self.pos += np.array([dx, dy])

    def stop(self):
        self.vel_x = 0
        self.vel_y = 0

    def is_ready_to_upgrade(self):
        return not self.is_max_tank and self.health >= self.max_health

    def get_mouse_pos(self):
        """
        :return: Mouse position relative to the center of the room
        """
        pos = pg.mouse.get_pos()
        mouse_pos = self.pos + np.array((pos[0] - c.SCR_W2, pos[1] - c.SCR_H2))
        return mouse_pos

    def rotate_body(self, dt):
        if self.moving_left == self.moving_right:
            if self.moving_up and not self.moving_down:
                dest_angle = 0.5 * pi
            elif not self.moving_up and self.moving_down:
                dest_angle = -0.5 * pi
            else:
                dest_angle = None

        elif self.moving_left and not self.moving_right:
            if self.moving_up and not self.moving_down:
                dest_angle = 0.75 * pi
            elif not self.moving_up and self.moving_down:
                dest_angle = -0.75 * pi
            else:
                dest_angle = pi

        else:
            if self.moving_up and not self.moving_down:
                dest_angle = 0.25 * pi
            elif not self.moving_up and self.moving_down:
                dest_angle = -0.25 * pi
            else:
                dest_angle = 0

        if dest_angle is not None:
            self.body.rotate(dest_angle, dt)

    def update_body(self, dt):
        mouse_pos = self.get_mouse_pos()
        self.rotate_body(dt)
        self.body.update(*self.pos, dt, mouse_pos)

    def setup(self, max_health, health_states, radius, body, MAX_VEL, ACC,
              gun_type, bg_radius, superpower):

        self.gun = guns_factory(gun_type)
        self.superpower = superpower_factory(superpower)
        self.max_health = max_health
        self.health = 0
        self.health_states = health_states
        self.radius = radius
        self.body = Body(body)
        self.bg_radius = bg_radius
        self.MAX_VEL = MAX_VEL
        self.ACC = ACC
        self.armor_on = [False]
        self.invisible = [False]

    def collide_bullet(self, x, y):
        radius = self.bg_radius if self.armor_on[0] else self.radius
        return circle_collidepoint(*self.pos, radius, x, y)

    def collide_bubble(self, x, y):
        return circle_collidepoint(*self.pos, self.radius // 2, x, y)

    def in_latest_state(self):
        return self.state == self.states_history[-1]

    def handle_injure(self, damage):
        if not self.armor_on[0]:
            super().handle_injure(damage)

    def make_body_frozen(self):
        for i in range(-6, 0):
            self.body.circles[i].is_visible = True

    def make_body_unfrozen(self):
        for i in range(-6, 0):
            self.body.circles[i].is_visible = False

    def make_frozen(self):
        self.frost_time = 0
        if not self.is_frozen:
            self.is_frozen = True
            self.MAX_VEL *= 0.2
            self.ACC *= 0.2
            self.make_body_frozen()

    def make_unfrozen(self):
        if self.is_frozen:
            self.is_frozen = False
            self.frost_time = 0
            self.MAX_VEL *= 5
            self.ACC *= 5
            self.make_body_unfrozen()

    def set_transportation_vel(self, alpha, max_vel):
        self.vel_x = max_vel * cos(alpha)
        self.vel_y = -max_vel * sin(alpha)

    def clear_bullets(self):
        """
        Method is called when player is transported to the next room.
        Deletes all player's bullets except orbiting shurikens.

        """
        self.bullets = []
        self.homing_bullets = []

        needless_shurikens = []
        index = 0
        for shuriken in self.shurikens:
            if not shuriken.is_orbiting:
                needless_shurikens.append(index)
            index += 1
        needless_shurikens.reverse()
        for index in needless_shurikens:
            self.shurikens.pop(index)

    def upgrade(self, new_state, state=None):
        self.shurikens = []
        if new_state:
            self.states_history.append(state)
            self.state = state
            self.moving_left = False
            self.moving_right = False
            self.moving_up = False
            self.moving_down = False
            self.is_shooting = False
        else:
            self.state = self.states_history[self.state[0] + 1]

        self.setup(*PLAYER_PARAMS[self.state])
        if new_state:
            self.is_shooting = False

        if self.state[0] == 5:
            self.is_max_tank = True

        if self.is_frozen:
            self.MAX_VEL *= 0.2
            self.ACC *= 0.2
            self.make_body_frozen()
        else:
            self.make_body_unfrozen()

    def downgrade(self):
        self.shurikens = []
        if self.state[0] >= 1:
            self.is_max_tank = False
            self.state = self.states_history[self.state[0] - 1]
            self.setup(*PLAYER_PARAMS[self.state])
            self.health = self.max_health - 1
            self.change_body()

            if self.is_frozen:
                self.MAX_VEL *= 0.2
                self.ACC *= 0.2
                self.make_body_frozen()
            else:
                self.make_body_unfrozen()
        else:
            self.health = 0

    def get_next_states(self):
        i, j = self.state[0], self.state[1]

        if self.state == (2, 3):
            return (i + 1, j), (i + 1, j + 1), (i + 1, j + 2)

        if i == 1 or self.state == (4, 0):
            return (i + 1, j), (i + 1, j + 1)

        elif self.state == (4, 5):
            return (i + 1, j - 1), (i + 1, j)

        elif self.state == (3, 5):
            return (i + 1, j - 2), (i + 1, j - 1), (i + 1, j)

        elif j == 0 or self.state == (0, 0):
            return (i + 1, j), (i + 1, j + 1), (i + 1, j + 2)

        return (i + 1, j - 1), (i + 1, j), (i + 1, j + 1)

    def delete_needless_bullets(self):
        """
        Deletes bullets that hit a target
        (or are outside the room) from the list.

        """
        needless_bullets = []
        index = 0
        for bullet in self.bullets:
            if bullet.is_outside() or bullet.hit_the_target:
                needless_bullets.append(index)
            index += 1

        needless_bullets.reverse()
        for index in needless_bullets:
            self.bullets.pop(index)

    def delete_needless_homing_bullets(self, mobs, top_effects):
        """
        Deletes homing bullets with health <= 0 (or if they hit a target) from the list.
        If there are no mobs in the room, deletes all homing bullets.
        Adds special effects in the places the needless homing bullets were.

        """
        needless_bullets = []
        index = 0
        for bullet in self.homing_bullets:
            if not mobs or bullet.health <= 0 or bullet.hit_the_target:
                needless_bullets.append(index)
                if not bullet.hit_the_target:
                    add_effect('RedHitCircle', top_effects, bullet.x, bullet.y)
            index += 1

        needless_bullets.reverse()
        for index in needless_bullets:
            self.homing_bullets.pop(index)

    def delete_needless_shurikens(self):
        """
        Deletes all shurikens that hit a target
        (or are outside the room and not orbiting) from the list.

        """
        needless_shurikens = []
        index = 0
        for shuriken in self.shurikens:
            if not shuriken.is_orbiting and shuriken.is_outside(
            ) or shuriken.hit_the_target:
                needless_shurikens.append(index)
            index += 1
        needless_shurikens.reverse()
        for index in needless_shurikens:
            self.shurikens.pop(index)

    def add_bullets(self, dt, sound_player, mobs):
        """
        Adds new bullets generated by gun to the list.
        If there are new bullets, plays a "player_shot" sound.

        """
        sound_player.reset()

        self.gun.update_time(dt)
        old_length = len(self.bullets)

        if self.is_shooting and not self.invisible[0]:
            target = self.get_mouse_pos()
            self.gun.append_bullets(*self.pos, target, self.bullets,
                                    self.body.body_angle)

        if self.gun.automatic and len(mobs):
            self.gun.append_bullets_auto(*self.pos, mobs, self.bullets,
                                         self.body.body_angle)

        if len(self.bullets) > old_length:
            sound_player.play_sound('player_bullet_shot')

    def update_bullets(self, dt, mobs, sound_player):
        self.add_bullets(dt, sound_player, mobs)
        fragments = []

        for bullet in self.bullets:
            if bullet.frangible:
                params = [dt, fragments]
            else:
                params = [dt]
            bullet.update(*params)

        self.bullets.extend(fragments)
        self.delete_needless_bullets()

    def update_homing_bullets(self, dt, mobs, top_effects):
        target = (mobs[-1].x, mobs[-1].y) if len(mobs) else (0, 0)
        for bullet in self.homing_bullets:
            params = [dt, *target]
            bullet.update(*params)

        self.delete_needless_homing_bullets(mobs, top_effects)

    def update_shurikens(self, dt, mobs):
        for shuriken in self.shurikens:
            shuriken.update(dt, *self.pos, mobs)

        self.delete_needless_shurikens()

    def update_acc(self):
        if not self.moving_right ^ self.moving_left:
            self.acc_x = -copysign(1,
                                   self.vel_x) * self.MU if self.vel_x else 0
        elif abs(self.vel_x) == self.MAX_VEL:
            self.acc_x = 0
        else:
            self.acc_x = -self.ACC if self.moving_left else self.ACC

        if not self.moving_up ^ self.moving_down:
            self.acc_y = -copysign(1,
                                   self.vel_y) * self.MU if self.vel_y else 0
        elif abs(self.vel_y) == self.MAX_VEL:
            self.acc_y = 0
        else:
            self.acc_y = -self.ACC if self.moving_up else self.ACC

    def update_pos(self, dt):
        dx = self.vel_x * dt + self.acc_x * dt * dt / 2
        dy = self.vel_y * dt + self.acc_y * dt * dt / 2
        self.move(dx, dy)

    def update_vel(self, dt):
        self.vel_x += self.acc_x * dt
        if self.vel_x * (self.vel_x - self.acc_x * dt) < 0:
            self.vel_x = 0
        elif abs(self.vel_x) > self.MAX_VEL:
            self.vel_x = copysign(1, self.vel_x) * self.MAX_VEL

        self.vel_y += self.acc_y * dt
        if self.vel_y * (self.vel_y - self.acc_y * dt) < 0:
            self.vel_y = 0
        elif abs(self.vel_y) > self.MAX_VEL:
            self.vel_y = copysign(1, self.vel_y) * self.MAX_VEL

    def update_superpower(self,
                          dt,
                          mobs,
                          top_effects,
                          bottom_effects,
                          camera,
                          transportation=False):
        params = []
        if self.superpower.id == 1:
            params = [dt, self.armor_on, top_effects]

        elif self.superpower.id in [2, 9]:
            params = [dt, self.pos, self.bullets]

        elif self.superpower.id in [3, 4]:
            params = [dt, self.pos, mobs, top_effects, bottom_effects, camera]

        elif self.superpower.id == 5:
            params = [dt, self.pos, top_effects, camera]

        elif self.superpower.id == 6:
            params = [dt, self.invisible, self.body]

        elif self.superpower.id in [7, 8]:
            params = [dt, self.pos, self.homing_bullets, self.health, 0]

        elif self.superpower.id == 10:
            params = [dt, self.pos, self.shurikens]

        elif self.superpower.id == 11:
            params = [
                dt, self.pos, self.homing_bullets, self.health,
                self.body.body_angle
            ]

        elif self.superpower.id == 12:
            params = [
                dt, *self.pos, self.body.body_angle,
                self.get_mouse_pos(), self.bullets
            ]

        elif self.superpower.id == 13:
            params = [dt, *self.pos, self.get_mouse_pos(), self.bullets]

        elif self.superpower.id == 14:
            params = [dt, *self.pos, self.bullets]

        if not transportation or self.superpower.id in [6, 10]:
            self.superpower.update(*params)

    def update(self, dt, mobs, top_effects, bottom_effects, camera,
               sound_player):
        self.update_acc()
        self.update_pos(dt)
        self.update_vel(dt)
        self.update_superpower(dt, mobs, top_effects, bottom_effects, camera)
        self.update_body(dt)
        self.update_bullets(dt, mobs, sound_player)
        self.update_homing_bullets(dt, mobs, top_effects)
        self.update_shurikens(dt, mobs)
        self.update_frozen_state(dt)

    def draw(self, surface, dx, dy):
        for bullet in self.bullets:
            if not bullet.vel:
                bullet.draw(surface, dx, dy)

        self.body.draw(surface, dx, dy)

        for bullet in self.bullets:
            if bullet.vel:
                bullet.draw(surface, dx, dy)

        for bullet in self.homing_bullets:
            bullet.draw(surface, dx, dy)

        for shuriken in self.shurikens:
            shuriken.draw(surface, dx, dy)
コード例 #2
0
            

while 1:
    pygame.time.delay(20)

    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()


    if(pygame.mouse.get_pressed()[0] and last_ball_done): 
        ball = Body( pygame.mouse.get_pos(),base_ball_size,screen )
        balls.append(ball)
        last_ball_done = False
    
    if(pygame.mouse.get_pressed()[0]):
        ball.enlarge()

    if(not (pygame.mouse.get_pressed()[0] or last_ball_done)): 
        ball.finish(pygame.mouse.get_pos())
        last_ball_done = True


    screen.fill(black)
    collisions(balls)
    for ball in balls:
        print(ball.forces)
        if (ball.done):
            ball.move()
        ball.draw()

    pygame.display.flip()
コード例 #3
0
class StatsWindow:
    def __init__(self):
        self.captions = []

        self.tank_data = None
        self.tank_name = None
        self.tank_desc = None

        self.player_bodies = PLAYER_BODIES
        self.tank_body = None

    def set_captions(self, language):
        pg.font.init()
        font_1 = pg.font.SysFont('Arial', 35, True)
        font_2 = pg.font.SysFont('Arial', 28, True)
        if language == 'English':
            captions = eng.ENG_STATSWINDOW_CAPTIONS
        else:
            captions = rus.RUS_STATSWINDOW_CAPTIONS

        self.captions.append(font_1.render(captions[0], True, WHITE))
        self.captions.append(font_2.render(captions[1], True, WHITE))
        self.captions.append(font_2.render(captions[2], True, WHITE))

    def set_tank_data(self, language):
        if language == 'English':
            self.tank_data = eng.ENG_UPGRADE_TEXT
        else:
            self.tank_data = rus.RUS_UPGRADE_TEXT

    def set_language(self, language):
        self.set_captions(language)
        self.set_tank_data(language)

    def setup_tank_name(self, player_state):
        pg.font.init()
        font = pg.font.SysFont('Arial', 26, True)
        self.tank_name = font.render(self.tank_data[player_state][0], True,
                                     WHITE)

    def setup_tank_desc(self, player_state):
        self.tank_desc = (TextBox(self.tank_data[player_state][3], c.FONT_2,
                                  20, False, WHITE, (120, 205), False),
                          TextBox(self.tank_data[player_state][1], 'Arial', 22,
                                  True, WHITE, (120, 410), False),
                          TextBox(self.tank_data[player_state][2], 'Arial', 22,
                                  True, WHITE, (430, 410), False),
                          TextBox(self.tank_data[player_state][4], c.FONT_2,
                                  20, False, WHITE, (120, 463), False),
                          TextBox(self.tank_data[player_state][5], c.FONT_2,
                                  20, False, WHITE, (430, 463), False))

    def setup(self, player_state):
        self.setup_tank_name(player_state)
        self.setup_tank_desc(player_state)
        self.tank_body = Body(self.player_bodies[player_state])

    def update(self, dt):
        self.tank_body.update(595, 260, dt, (605, 260))

    def draw_captions(self, screen):
        screen.blit(self.captions[0], (320, 110))
        screen.blit(self.captions[1], (120, 370))
        screen.blit(self.captions[2], (430, 370))

    def draw_tank_name(self, screen):
        screen.blit(self.tank_name, (120, 170))

    def draw_tank_desc(self, screen):
        for text in self.tank_desc:
            text.draw(screen)

    @staticmethod
    def draw_player_background(screen):
        pg.draw.circle(screen, WHITE, (595, 260), 93)
        pg.draw.circle(screen, PAUSEMENU_PLAYER_BG, (595, 260), 89)

    def draw(self, screen):
        self.draw_captions(screen)
        self.draw_tank_name(screen)
        self.draw_tank_desc(screen)
        self.draw_player_background(screen)
        self.tank_body.draw(screen)
コード例 #4
0
class Bubble:
    def __init__(self, x, y, alpha, gravity_r=0, type_marker=0):
        self.x = x
        self.y = y
        self.radius = data.BUBBLE_RADIUS[type_marker]
        self.health = data.BUBBLE_HEALTH[type_marker]
        self.vel = uniform(0.7, 1.7) * data.BUBBLE_MAX_VEL
        self.max_vel = data.BUBBLE_MAX_VEL
        self.acc = data.BUBBLE_ACC
        self.alpha = alpha
        self.gravity_r = gravity_r
        self.in_player_gravity = False

        self.body = Body(data.BUBBLE_BODY[type_marker])
        self.body.randomise_body_scale()

    def is_on_screen(self, dx, dy):
        if -self.radius <= self.x-dx <= c.SCR_W+self.radius and \
           -self.radius <= self.y-dy <= c.SCR_H+self.radius:
            return True
        return False

    def is_outside(self):
        return not circle_collidepoint(c.SCR_W2, c.SCR_H2, c.ROOM_RADIUS,
                                       self.x, self.y)

    def check_player_pos(self, player_x, player_y):
        if hypot(self.x - player_x, self.y - player_y) <= self.gravity_r:
            self.in_player_gravity = True
            self.acc = data.BUBBLE_ACC
        else:
            self.in_player_gravity = False

    def maximize_vel(self):
        self.vel = 2 * data.BUBBLE_MAX_VEL

    def go_to_player(self, x, y, dt):
        self.alpha = calculate_angle(self.x, self.y, x, y)

        dr = self.vel * dt + self.acc * dt * dt / 2
        dist = hypot(self.x - x, self.y - y)
        if dr > dist:
            self.x = x
            self.y = y
        else:
            self.x += dr * cos(self.alpha)
            self.y -= dr * sin(self.alpha)

        self.vel += self.acc * dt
        if self.vel >= self.max_vel:
            self.vel = self.max_vel
            self.acc = 0

    def slow_down(self, dt):
        self.acc = -data.BUBBLE_ACC
        dr = self.vel * dt + self.acc * dt * dt / 2
        self.x += dr * cos(self.alpha)
        self.y -= dr * sin(self.alpha)

        dv = self.acc * dt
        if self.vel * (self.vel + dv) < 0:
            self.vel = 0
            self.acc = 0
        else:
            self.vel += dv

    def move(self, dx, dy):
        self.x += dx
        self.y += dy
        self.body.move(dx, dy)

    def update(self, x, y, dt):
        if self.vel or self.is_on_screen(x - c.SCR_W2, y - c.SCR_H2):
            self.check_player_pos(x, y)
            if self.in_player_gravity:
                self.go_to_player(x, y, dt)
            elif self.vel:
                self.slow_down(dt)

            self.body.update(self.x, self.y, dt)

    def draw(self, surface, dx=0, dy=0):
        if self.is_on_screen(dx, dy):
            self.body.draw(surface, dx, dy)
コード例 #5
0
ファイル: room.py プロジェクト: wushiwang/Underwater-Battles
class Room:
    def __init__(self):
        """
        List of bullets is made separately from list of mobs, because
        when mob is dead and deleted, its bullets should continue existing.
        'new_mobs' is a temporary list of mobs, which is created
        to draw the mobs of room player is being transported to.
        When player is transported, self.mobs = self.new_mobs.copy().
        Text is a text surface of room, containing rules of the game.
        Screen rectangle is used to check if mob's rectangle collides
        with it. If yes, then a mob is drawn.
        Gravity radius is a radius of circle around player, in which bubbles
        gravitate to player.
        'Bottom effects' are drawn below player, mobs, bubbles and bullets,
        other effects are 'Top effects'.
        """
        self.bubbles = []
        self.mobs = []
        self.new_mobs = []
        self.bullets = []
        self.homing_bullets = []
        self.bottom_effects = []
        self.top_effects = []
        self.text = None
        self.setup_text('')
        self.screen_rect = pg.Rect(0, 0, c.SCR_W, c.SCR_H)
        self.gravity_radius = 150
        self.boss_skeleton = Body(BOSS_SKELETON_BODY)
        self.boss_skeleton.update(c.SCR_W2, c.SCR_H2, 0, (0, 0), 0.5 * pi)
        self.boss_position_marker = 0

    def reset(self, new_game=False):
        """
        Method is called when a new game is started
        or a new room is visited. Resets all room data.
        """
        self.bubbles = []
        self.bullets = []
        self.homing_bullets = []
        self.top_effects = []
        self.bottom_effects = []
        self.mobs = [] if new_game else self.new_mobs.copy()
        self.new_mobs = []
        if new_game:
            self.boss_position_marker = 0

    @staticmethod
    def encode_mobs(mobs):
        """
        :param mobs: list of objects (mobs)
        :return: dictionary [mob_name] -> number of mobs
        """
        mobs_dict = defaultdict(int)
        for mob in mobs:
            mobs_dict[mob.name] += 1
        return mobs_dict

    @staticmethod
    def decode_mobs(mobs_dict):
        """
        :param mobs_dict: dictionary [mob_name] -> number of mobs
        :return: list of objects (mobs)
        """
        mobs = []
        for mob_name in mobs_dict.keys():
            for i in range(mobs_dict[mob_name]):
                mobs.append(m.mob_factory(mob_name))
        return mobs

    def check_boss(self):
        if self.boss_position_marker in [1, 2]:
            self.boss_position_marker -= 1
        for mob in self.new_mobs:
            if mob.name in ['BossLeg', 'BossHead', 'BossHand']:
                self.boss_position_marker = 2
                break

    def setup_new_mobs(self, new_mobs):
        """
        :param new_mobs: dictionary of new mobs, generated by Level Generator
        """
        self.new_mobs = self.decode_mobs(new_mobs)
        self.check_boss()

    def setup_text(self, text):
        """
        :param text: list of strings
        sets background room text, explaining the rules of the game
        """
        self.text = TextBox(text, c.FONT_1, 47, True, WHITE, (400, 110))

    def delete_needless_bullets(self):
        """
        Method removes those bullets from list, that hit a target or are outside the room,
        and reduces the length of list to 100, if it is > 100.
        So the size of list becomes limited to avoid
        the situation of infinite filling the list.
        """
        tmp_bullets = []
        index = 0
        for bullet in self.bullets:
            if bullet.is_outside() or bullet.hit_the_target:
                tmp_bullets.append(index)
            index += 1

        tmp_bullets.reverse()
        for index in tmp_bullets:
            self.bullets.pop(index)

        while len(self.bullets) > 100:
            self.bullets.pop(0)

    def delete_dead_homing_bullets(self):
        """
        Method deletes homing bullets with not
        positive health from list of homing bullets.
        """
        dead_bullets = []
        index = 0
        for bullet in self.homing_bullets:
            if bullet.health <= 0 or bullet.hit_the_target:
                dead_bullets.append(index)
            index += 1

        dead_bullets.reverse()
        for index in dead_bullets:
            self.homing_bullets.pop(index)

    def delete_needless_bubbles(self):
        """
        removes those bubbles from list, which are outside
        the room, so that player can't eat them
        """
        tmp_bubbles = []
        for index in range(len(self.bubbles)):
            if self.bubbles[index].is_outside():
                tmp_bubbles.append(index)
                tmp_bubbles.reverse()
        for index in tmp_bubbles:
            self.bubbles.pop(index)

    @staticmethod
    def delete_needless_effects(effects):
        """
        removes those effects from the given
        list, which have stopped running
        """
        tmp_effects = []
        for index in range(len(effects)):
            if not effects[index].running:
                tmp_effects.append(index)
        tmp_effects.reverse()
        for index in tmp_effects:
            effects.pop(index)

    def delete_dead_mobs(self):
        """
        Method deletes mobs with not positive health from
        list of mobs and replaces them with bubbles.
        """
        dead_mobs = []
        index = 0
        for mob in self.mobs:
            if mob.health <= 0:
                dead_mobs.append(index)
                self.add_bubbles(mob.x, mob.y, mob.bubbles)
            index += 1

        dead_mobs.reverse()
        for index in dead_mobs:
            self.mobs.pop(index)

    def update_bullets(self, dt):
        for bullet in self.bullets:
            bullet.update(dt)

        self.delete_needless_bullets()

    def update_homing_bullets(self, player_x, player_y, dt):
        for bullet in self.homing_bullets:
            bullet.update(dt, player_x, player_y)

        self.delete_dead_homing_bullets()

    def update_bubbles(self, x, y, dt):
        for bubble in self.bubbles:
            bubble.update(x, y, dt)

        self.delete_needless_bubbles()

    def update_effects(self, dt):
        for effect in self.top_effects:
            effect.update(dt)
        for effect in self.bottom_effects:
            effect.update(dt)

        self.delete_needless_effects(self.top_effects)
        self.delete_needless_effects(self.bottom_effects)

    def handle_bullet_explosion(self, x, y):
        """
        Changes mobs' states according to their positions relative
        to the explosion, and adds appropriate effects.
        :param x: x-coord of bullet
        :param y: y-coord of bullet

        """
        for mob in self.mobs:
            if hypot(x - mob.x, y - mob.y) <= 200:
                mob.health -= 20
                mob.change_body()
                add_effect('BigHitLines', self.top_effects, mob.x, mob.y)
        add_effect('PowerfulExplosion', self.bottom_effects, x, y)
        add_effect('Flash', self.top_effects)

    def move_objects(self, offset):
        """
        Method is called when the player is being transported
        to the next room. The objects of previous room become
        moved by the given offset to be drawn properly during
        player's transportation
        """
        for bubble in self.bubbles:
            bubble.move(*offset)

        for mob in self.mobs:
            mob.move(*offset)

        for bullet in self.bullets:
            bullet.move(*offset)

        for bullet in self.homing_bullets:
            bullet.move(*offset)

        self.boss_skeleton.update(c.SCR_W2, c.SCR_H2, 0, (0, 0), 0.5 * pi)
        if self.boss_position_marker == 1:
            self.boss_skeleton.move(*offset)

    def setup_gravity(self, gravity_radius):
        """
        Sets the new radius of player's gravitational field
        :param gravity_radius: radius of circle, in which
               the player's gravity exists
        """
        if self.mobs:
            self.gravity_radius = gravity_radius

            for bubble in self.bubbles:
                bubble.gravity_r = gravity_radius

    def maximize_gravity(self):
        """
        Method is called when all mobs in the room are dead.
        The radius of player's gravitational field is set equal to
        the diameter of room, so that every bubble starts
        gravitating to player regardless of his position in the room.
        Also speeds of bubbles are maximized to reach player faster.
        """

        for bubble in self.bubbles:
            bubble.gravity_r = 2 * c.ROOM_RADIUS
            bubble.maximize_vel()

    def update_mobs(self, player_x, player_y, dt):
        generated_mobs = []
        target = [player_x, player_y]
        for mob in self.mobs:
            mob.update(target, self.bullets, self.homing_bullets,
                       generated_mobs, self.screen_rect, dt)

        self.mobs.extend(generated_mobs)
        self.delete_dead_mobs()

    def update_new_mobs(self, player_x, player_y, dt):
        """
        Method updates positions and bodies of mobs of the room,
        player is being transported to.
        """
        target = (player_x, player_y)
        for mob in self.new_mobs:
            mob.update_pos(dt)
            mob.gamma = mob.count_gamma()
            if mob.body_rect.colliderect(self.screen_rect):
                mob.update_body(dt, target)

    def set_screen_rect(self, pos):
        self.screen_rect.center = pos

    def game_is_over(self):
        return self.boss_position_marker == 2 and not self.mobs

    def update(self, player_pos, dt):
        self.set_screen_rect(player_pos)

        self.update_mobs(*player_pos, dt)
        self.update_bubbles(*player_pos, dt)
        self.update_bullets(dt)
        self.update_homing_bullets(*player_pos, dt)
        self.update_effects(dt)

        if not self.mobs:
            self.maximize_gravity()

    def add_bubbles(self, mob_x, mob_y, bubbles):
        """
        :param mob_x: x coord of dead mob
        :param mob_y: y coord of dead mobs
        :param bubbles: list of the number of bubbles of 3 types: small, medium, big
        """
        for type_marker in range(len(bubbles)):
            for i in range(bubbles[type_marker]):
                angle = uniform(0, 2 * pi)
                self.bubbles.append(
                    Bubble(mob_x, mob_y, angle, self.gravity_radius,
                           type_marker))

    def draw_text(self, surface, dx, dy):
        self.text.draw(surface, dx, dy)

    def draw_bubbles(self, surface, dx, dy):
        for bubble in self.bubbles:
            bubble.draw(surface, dx, dy)

    def draw_mobs(self, surface, dx, dy):
        for mob in self.mobs:
            if mob.body_rect.colliderect(self.screen_rect):
                mob.body.draw(surface, dx, dy)

    def draw_new_mobs(self, surface, dx, dy):
        for mob in self.new_mobs:
            if mob.body_rect.colliderect(self.screen_rect):
                mob.body.draw(surface, dx, dy)

    def draw_boss_skeleton(self, surface, dx, dy):
        if self.boss_position_marker:
            self.boss_skeleton.draw(surface, dx, dy)

    def draw_bullets(self, surface, dx, dy):
        for bullet in self.bullets:
            bullet.draw(surface, dx, dy)

        for bullet in self.homing_bullets:
            bullet.draw(surface, dx, dy)

    def draw_top_effects(self, surface, dx, dy):
        for effect in self.top_effects:
            effect.draw(surface, dx, dy)

    def draw_bottom_effects(self, surface, dx, dy):
        for effect in self.bottom_effects:
            effect.draw(surface, dx, dy)