extends CharacterBody2D class_name Player signal damaged const SPEED = 60 const KICK_SPEED = 300 const THROW_DISTANCE = 3 @export var Bomb: PackedScene = preload("res://Scenes/Entities/Bombs/Bomb__Normal.tscn") @export var bomb_power: int = 2 @export var maxHealth: int = 12 @export var health: int = self.maxHealth @export var extraHealth: int = 5 var is_invincible = false var held_bomb: Bomb var DIRECTION = Vector2.DOWN var collision_area: Area2D func _ready(): add_to_group("player") set_up_direction(Vector2.UP) motion_mode = CharacterBody2D.MOTION_MODE_FLOATING collision_area = Utilities.Collision.Area.new(self, $CollisionShape2D) collision_area.connect("collided", Callable(self, "_collide")) add_child(collision_area) func _process(delta): if Input.is_action_pressed("ui_left"): velocity.x -= SPEED $AnimatedSprite2D.play("left") self.DIRECTION = Vector2.LEFT if Input.is_action_pressed("ui_right"): velocity.x += SPEED $AnimatedSprite2D.play("right") self.DIRECTION = Vector2.RIGHT if Input.is_action_pressed("ui_up"): velocity.y -= SPEED $AnimatedSprite2D.play("up") self.DIRECTION = Vector2.UP if Input.is_action_pressed("ui_down"): velocity.y += SPEED $AnimatedSprite2D.play("down") self.DIRECTION = Vector2.DOWN if velocity.x < 0 && velocity.y < 0: $AnimatedSprite2D.play("tl") elif velocity.x > 0 && velocity.y < 0: $AnimatedSprite2D.play("tr") elif velocity.x < 0 && velocity.y > 0: $AnimatedSprite2D.play("bl") elif velocity.x > 0 && velocity.y > 0: $AnimatedSprite2D.play("br") if Input.is_action_just_pressed("ui_accept"): if self.held_bomb: self.throw_bomb() else: var interacted = false var areas = $InteractionArea.get_overlapping_areas() for area in areas: if area.is_in_group("bombs"): var bomb = area.get_parent() self.pick_up_bomb(bomb) interacted = true break if not interacted: self.plant_bomb() self.collide(move_and_collide(velocity * delta)) velocity = velocity.lerp(Vector2(0, 0), 1) func plant_bomb(): var bomb = Bomb.instantiate() bomb.position = Utilities.get_level_position_grid(self) bomb.power = self.bomb_power self.add_collision_exception_with(bomb) bomb.connect("body_exited", func(body): if body.is_in_group("player") and not self.held_bomb: self.remove_collision_exception_with(bomb) ) get_tree().get_current_scene().add_child(bomb) func pick_up_bomb(bomb: Bomb): get_tree().get_current_scene().remove_child(bomb) bomb.position = Vector2(0, 0) bomb.set_collision_layer_value(Utilities.Collision.Layer.BOMB, false) self.add_collision_exception_with(bomb) self.add_child(bomb) self.held_bomb = bomb bomb.connect("exploded", func(bomb): if self.held_bomb == bomb: self.held_bomb = null ) func throw_bomb(): var bomb = self.held_bomb self.remove_child(bomb) var target_position = null var target_intersection = true var additional_distance = 0 while target_intersection: target_position = Utilities.from_grid_to_position( Utilities.from_position_to_grid(self.position) + ((self.THROW_DISTANCE + additional_distance) * self.DIRECTION) ) var query = PhysicsPointQueryParameters2D.new() query.set_position(target_position) target_intersection = get_world_2d().direct_space_state.intersect_point(query) additional_distance += 1 bomb.position = target_position get_tree().get_current_scene().add_child(bomb) bomb.set_collision_layer_value(Utilities.Collision.Layer.BOMB, true) (func(): self.remove_collision_exception_with(bomb)).call_deferred() self.held_bomb = null func collide(collision: KinematicCollision2D): if not collision: return var collider = collision.get_collider() if collider.is_in_group("bombs"): self.kick_bomb(collider) func kick_bomb(bomb): var diff = Utilities.get_level_position(self) - Utilities.get_level_position(bomb) if diff.x > 0: bomb.velocity.x -= KICK_SPEED elif diff.x < 0: bomb.velocity.x += KICK_SPEED elif diff.y > 0: bomb.velocity.y -= KICK_SPEED elif diff.y < 0: bomb.velocity.y += KICK_SPEED func take_damage(amount): if self.held_bomb: self.held_bomb.call_deferred("explode") if self.is_invincible: return self.set_invincibility() if self.extraHealth > 0: if amount > self.extraHealth: self.health -= amount - self.extraHealth self.extraHealth = 0 else: self.extraHealth -= amount else: self.health -= amount self.emit_signal("damaged", self.health) func set_invincibility(): $Invincibility.start() $AnimatedSprite2D.set_modulate(Color(10, 10, 10, 1)) self.is_invincible = true func _on_invincibility_timeout(): $AnimatedSprite2D.set_modulate(Color(1, 1, 1, 1)) self.is_invincible = false func _collide(area: Area2D): if area.is_in_group("explosions"): self.take_damage(2) elif area.is_in_group("enemies"): self.take_damage(1)