Example #1
0
class Claw(Kinetic):
    def __init__(self, boss, is_left):
        super(Claw, self).__init__(96, 128, 56, 74, 200)
        self.boss = boss
        self.is_left = is_left

        self.sprite = Sprite(self.x, self.y, SpriteType.CRAB_BOSS_ARM)

        if self.is_left:
            self.set_location(self.x - 16, self.y + 6)
        else:
            self.sprite.flip_horizontally(True)
            self.set_location(self.x + 5 * 16, self.y + 6)

        self.initial_y = self.sprite.y
        self.windup = False
        self.slamming = False
        self.cooldown = False
        self.needs_setup = True

    def set_location(self, x, y):
        super(Claw, self).set_location(x, y)
        self.sprite.set_location(self.x, self.y)

    def _apply_force(self, delta_time):
        pass

    def _update_collision_rectangles(self):
        self.collision_width = 3
        self.collision_rectangles = [
            Rect(self.x + 2, self.y - self.collision_width * 2, self.width - 4,
                 self.collision_width * 2),
            Rect(self.x + 2, self.y + self.height, self.width - 4,
                 self.collision_width * 2),
            Rect(self.x - self.collision_width, self.y + self.collision_width,
                 self.collision_width, self.height - self.collision_width * 2),
            Rect(self.x + self.width, self.y + self.collision_width,
                 self.collision_width, self.height - self.collision_width * 2)
        ]

    def _collision(self, scene_data):
        if (self.slamming and not scene_data.actor.attacked
                and scene_data.actor.bounds.colliderect(self.bounds)):
            scene_data.actor.get_yeeted()

    def __update_ai(self, delta_time, scene_data):
        if self.boss.injured:
            return

        if self.boss.crab_smash:
            if self.needs_setup:
                if self.y > self.initial_y - 40:
                    self.set_location(self.x, self.y - self.move_speed * 1.25)
                else:
                    self.needs_setup = False
                    self.boss.sync_smash += 1

            elif self.boss.sync_smash >= 2:
                if self.y + self.height < scene_data.scene_bounds.height - 8:
                    self.set_location(self.x, self.y + self.move_speed * 4)
                else:
                    self.needs_setup = True
                    self.cooldown = True
                    self.boss.special_attack = True

                    play_sound("stomp.wav", 0.5)

            return

        if (not self.boss.hurt and not self.slamming and not self.cooldown
                and scene_data.actor.y > self.initial_y
                and scene_data.actor.x >= self.x
                and scene_data.actor.x <= self.x + self.width):
            self.windup = True

        if self.windup:
            if self.y > self.initial_y - 40:
                if self.boss.state_index == 4:
                    self.set_location(self.x, self.y - self.move_speed * 0.6)
                else:
                    self.set_location(self.x, self.y - self.move_speed * 0.4)
            else:
                self.slamming = True
                self.windup = False

        if self.slamming:
            if self.y + self.height < scene_data.scene_bounds.height - 8:
                self.set_location(self.x, self.y + self.move_speed * 3)
            else:
                self.cooldown = True
                self.slamming = False

                play_sound("stomp.wav")
                self.boss.idle_timer.reset()
                self.boss.idle_timer.start()

        if self.cooldown:
            if self.y > self.initial_y:
                if self.boss.state_index == 4:
                    self.set_location(self.x, self.y - self.move_speed * 0.15)
                else:
                    self.set_location(self.x, self.y - self.move_speed * 0.07)
            else:
                self.cooldown = False

    def update(self, delta_time, scene_data):
        self._calculate_scaled_speed(delta_time)
        self._apply_force(delta_time)
        self._update_collision_rectangles()
        self._collision(scene_data)
        self.__update_ai(delta_time, scene_data)

    def draw(self, surface):
        if globals.debugging:
            self._draw_collision_rectangles(surface)
            draw_rectangle(surface, self.bounds, CameraType.DYNAMIC,
                           self.color, 4)
        else:
            self.sprite.draw(surface, CameraType.STATIC)
Example #2
0
class Player(Actor):
    def __init__(self, x, y):
        super(Player, self).__init__(x, y, 12, 28, 100)
        self.sprite = Sprite(self.x - 10, self.y - 16, SpriteType.PLAYER)
        self.walk_animation = Animation(6, 6, 100)
        self.direction = Direction.NONE
        self.area = None
        self.query_result = None

        self.default_jump_height = 16 * 4
        self.jump_duration = 1
        self.default_run_acceleration = 10
        self.default_ground_friction = 7
        self.default_air_friction = 1

        self.jump_initial_velocity = 0
        self.gravity = 0
        self.lateral_acceleration = 0
        self.ground_friction = 0
        self.air_friction = 0

        self.grounded = False
        self.jumping = False
        self.attempt_block_shift = False
        self.attacked = False
        self.restart = False
        self.pause = False
        self.transitioning = False

        self.restart_delay = Timer(2600)
        self.queue_restart = False

    def revive(self):
        self.grounded = False
        self.jumping = False
        self.attempt_block_shift = False
        self.attacked = False
        self.restart = False
        self.queue_restart = False

        self.velocity = Vector2(0, 0)
        self.sprite.set_frame(0, 6)

    def get_yeeted(self):
        self.__finessed_by_enemy()

    def _calculate_scaled_speed(self, delta_time):
        super(Player, self)._calculate_scaled_speed(delta_time)

        time = 1 / delta_time * self.jump_duration

        self.jump_initial_velocity = 4 * self.default_jump_height / time
        self.gravity = 8 * self.default_jump_height / time**2

        self.lateral_acceleration = self.default_run_acceleration * delta_time
        self.ground_friction = self.default_ground_friction * delta_time
        self.air_friction = self.default_air_friction * delta_time

    def set_location(self, x, y):
        super(Player, self).set_location(x, y)
        self.sprite.set_location(self.x - 10, self.y - 16)

    def _apply_force(self, delta_time):

        if self.transitioning:
            return

        if not self.pause:
            self.velocity.y += self.gravity
        else:
            self.velocity.y += self.gravity * 0.6

        self.set_location(self.x + self.velocity.x, self.y + self.velocity.y)

    def _update_input(self, delta_time):
        if self.attacked:
            return

        if not self.pause and pressing(
                InputType.LEFT) and not pressing(InputType.RIGHT):
            self.velocity.x -= self.lateral_acceleration
            if self.velocity.x < -self.move_speed:
                self.velocity.x = -self.move_speed

            if not self.jumping:
                self.sprite.set_frame(self.walk_animation.current_frame, 6)

            self.direction = Direction.LEFT

        elif not self.pause and pressing(
                InputType.RIGHT) and not pressing(InputType.LEFT):
            self.velocity.x += self.lateral_acceleration
            if self.velocity.x > self.move_speed:
                self.velocity.x = self.move_speed

            if not self.jumping:
                self.sprite.set_frame(self.walk_animation.current_frame, 6)

            self.direction = Direction.RIGHT

        elif ((not pressing(InputType.LEFT) and not pressing(InputType.RIGHT))
              or (pressing(InputType.LEFT) and pressing(InputType.RIGHT))):
            if self.grounded:
                self.velocity.lerp(Vector2(0, self.velocity.y),
                                   self.ground_friction)
            else:
                self.velocity.lerp(Vector2(0, self.velocity.y),
                                   self.air_friction)

            if self.velocity.x > -0.1 and self.velocity.x < 0.1:
                self.velocity.x = 0

            self.sprite.set_frame(0, 6)

        if not self.grounded:
            if self.velocity.y < 0:
                self.sprite.set_frame(6, 6)
            if self.velocity.y > 0:
                self.sprite.set_frame(7, 6)
        else:
            if self.velocity.x == 0:
                if pressing(InputType.UP):
                    self.sprite.set_frame(8, 6)
                if pressing(InputType.DOWN):
                    self.sprite.set_frame(9, 6)

        if self.direction == Direction.LEFT:
            self.sprite.flip_horizontally(True)
        elif self.direction == Direction.RIGHT:
            self.sprite.flip_horizontally(False)

        if pressed(InputType.A) and self.grounded and not self.jumping:
            self.__jump(delta_time)
            self.jumping = True

        if self.jumping and self.velocity.y < -self.jump_initial_velocity / 2 and not pressing(
                InputType.A):
            self.velocity.y = -self.jump_initial_velocity / 2
            self.jumping = False

        if pressed(InputType.X):
            self.attempt_block_shift = True

    def __rectanlge_collision_logic(self, entity):
        # Bottom
        if self.velocity.y < 0 and self.collision_rectangles[0].colliderect(
                entity.bounds):
            self.set_location(self.x, entity.bounds.bottom)
            self.velocity.y = 0
        # Top
        if self.velocity.y > 0 and self.collision_rectangles[1].colliderect(
                entity.bounds):
            self.set_location(self.x, entity.bounds.top - self.bounds.height)
            self.grounded = True
            self.jumping = False
            self.velocity.y = 0

        # Right
        if self.velocity.x < 0 and self.collision_rectangles[2].colliderect(
                entity.bounds):
            self.set_location(entity.bounds.right, self.y)
            self.velocity.x = 0
        # Left
        if self.velocity.x > 0 and self.collision_rectangles[3].colliderect(
                entity.bounds):
            self.set_location(entity.bounds.left - self.bounds.width, self.y)
            self.velocity.x = 0

    def _collision(self, scene_data):
        if self.attacked:
            return

        if self.x < 3:
            self.set_location(3, self.y)

        if (globals.debugging):
            for e in scene_data.entities:
                e.set_color(Color.WHITE)

        self.area = Rect(self.x - 16, self.y - 32, self.width + 16 * 2,
                         self.height + 32 * 2)

        self.grounded = False
        self.query_result = scene_data.entity_quad_tree.query(self.area)

        if self.attempt_block_shift:
            self.__shift_blocks(scene_data)

        self.attempt_block_shift = False

        for e in self.query_result:
            if e is self:
                continue

            if (globals.debugging):
                e.set_color(Color.RED)

            if isinstance(e, Block):
                self.__rectanlge_collision_logic(e)
                self._update_collision_rectangles()

            if isinstance(e, QBlock):
                if e.active:
                    self.__rectanlge_collision_logic(e)
                    self._update_collision_rectangles()

            if isinstance(e, BossCrab):
                if (not e.hurt and not self.grounded and self.velocity.y > 0
                        and self.collision_rectangles[1].colliderect(
                            e.bounds)):
                    e.bop_on_head()
                    self.velocity.y = -self.jump_initial_velocity * 0.35
                    if not e.injured:
                        play_sound("pain.wav", 0.4)
                    else:
                        play_sound("pain.wav", 0.2)

        self.query_result = scene_data.kinetic_quad_tree.query(self.area)
        for e in self.query_result:
            if e is self:
                continue

            if (globals.debugging):
                e.set_color(Color.RED)

            if isinstance(e, Crab):
                if not e.dead:
                    if (not e.aggravated and not self.grounded
                            and self.velocity.y > 0
                            and self.collision_rectangles[1].colliderect(
                                e.bounds)):
                        e.squish()
                        self.velocity.y = -self.jump_initial_velocity * 0.35
                        play_sound("bop.wav")

                    elif e.aggravated and self.bounds.colliderect(e.bounds):
                        self.__finessed_by_enemy()

    def __jump(self, delta_time):
        self.velocity.y = -self.jump_initial_velocity
        play_sound("jump.wav")

    def __shift_blocks(self, scene_data):
        for e in self.query_result:
            if e is self:
                continue

            if isinstance(e, QBlock):
                if self.bounds.colliderect(e.bounds):
                    play_sound("shift_fail.wav")
                    return

        for e in scene_data.entities:
            if isinstance(e, QBlock):
                e.toggle()
            elif isinstance(e, Crab):
                e.toggle_aggravation()

        play_sound("shift.wav")

    def __finessed_by_enemy(self):
        self.attacked = True
        self.velocity.y = -self.jump_initial_velocity * 0.5
        self.sprite.set_frame(10, 6)

        self.__play_mocking_music()

    def __play_mocking_music(self):
        if not self.queue_restart:
            play_song("fin.wav")
            self.queue_restart = True
            self.restart_delay.reset()
            self.restart_delay.start()

    def __update_death(self, delta_time, scene_data):
        if self.y + self.height > scene_data.scene_bounds.height:
            self.attacked = True
            self.__play_mocking_music()
        #if self.y + self.height > scene_data.scene_bounds.height + 64 + 128 + 64:
        #    self.restart = True

        if self.queue_restart:
            self.restart_delay.update(delta_time)
            if self.restart_delay.done:
                self.restart = True
                self.queue_restart = False

    def __update_animation(self, delta_time):
        self.walk_animation.update(delta_time)

    def update(self, delta_time, scene_data):
        self._calculate_scaled_speed(delta_time)
        self._update_input(delta_time)
        self._apply_force(delta_time)
        self._update_collision_rectangles()
        self._collision(scene_data)
        self.__update_death(delta_time, scene_data)
        self.__update_animation(delta_time)

    def draw(self, surface):
        if globals.debugging:
            self._draw_collision_rectangles(surface)
            draw_rectangle(surface, self.bounds, CameraType.DYNAMIC,
                           self.color)
            if self.area != None:
                draw_rectangle(surface, self.area, CameraType.DYNAMIC,
                               Color.BLACK, 1)
        else:
            self.sprite.draw(surface, CameraType.DYNAMIC)