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)
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)