extends CharacterBody2D class_name Player const MAX_REACH = 100 const HOLDING_ITEM_SPRITE_SIZE = 20. signal player_updated(player: Player) signal upgraded var planet : Planet # mis à jour par la classe Planet @export var speed = 350 var max_energy : int = 3 var has_just_received_instruction : bool = false # pour récupérer les zones dans les action_area, une frame doit être passée depuis la création de la zone var controlling_player : bool = true : set(v): controlling_player = v velocity = Vector2.ZERO var instruction : Instruction = null var energy : int = max_energy : set(v): energy = v player_updated.emit(self) @onready var inventory : Inventory = Inventory.new() @onready var preview_zone : Area2D = null @onready var action_zone : Area2D = null func _ready(): player_updated.emit(self) inventory.inventory_changed.connect(_on_inventory_updated) Pointer.player = self # Méthode déclenchée par la classe planet func _start_pass_day(): controlling_player = false instruction = null # Méthode déclenchée par la classe planet func _pass_day(): full_recharge() # Méthode déclenchée par la classe planet func _end_pass_day(): controlling_player = true func _process(_delta): if controlling_player: var old_velocity=velocity calculate_direction() if instruction and instruction.can_be_done(self) and not has_just_received_instruction: instruction.do(self) instruction = null move_preview_zone(get_global_mouse_position()) has_just_received_instruction = false # Sound if old_velocity.length()==0 and velocity.length()!=0: play_sfx("move") else: velocity = Vector2.ZERO move_and_slide() func _on_inventory_updated(_inventory: Inventory): if inventory.get_item(): setup_preview_zone(inventory.get_item().use_zone_radius) var item_texture = inventory.get_item().icon %ItemSprite.texture = item_texture %ItemSprite.scale = Vector2( 1./(item_texture.get_width()/HOLDING_ITEM_SPRITE_SIZE), 1./(item_texture.get_height()/HOLDING_ITEM_SPRITE_SIZE) ) %HideEyes.visible = inventory.get_item() != null %ItemSprite.visible = inventory.get_item() != null emit_signal("player_updated", self) func calculate_direction(): var input_direction: Vector2 = Input.get_vector("move_left", "move_right", "move_up", "move_down") if input_direction.length() != 0: instruction = null if instruction: input_direction = self.global_position.direction_to(instruction.position) velocity = input_direction * speed if input_direction.x: flip_character(input_direction.x > 0) func flip_character(face_right = true): $Sprite.flip_h = not face_right %ItemSprite.position.x = abs(%ItemSprite.position.x) * (1 if face_right else -1) %HideEyes.position.x = abs(%ItemSprite.position.x) * (1 if face_right else -1) func can_interact(interactable : Interactable): return interactable.can_interact(self) func try_interact(interactable : Interactable): has_just_received_instruction = true instruction = InteractableInstruction.new( interactable ) func try_move(move_to : Vector2): instruction = MoveInstruction.new(move_to) func get_item(item : Item): inventory.set_item(item) play_sfx("pick") func drop_item(): var item_to_drop = inventory.pop_item() planet.drop_item(item_to_drop, global_position) play_sfx("drop") func delete_item(item: Item): inventory.remove_item(item) func try_use_item(item : Item, use_position : Vector2): has_just_received_instruction = true setup_action_zone(use_position, item.use_zone_radius) instruction = ItemActionInstruction.new( use_position, item ) func preview_can_use_item(item : Item) -> bool: return can_use_item_on_zone(item, preview_zone) func can_use_item_on_zone(item : Item, zone: Area2D) -> bool: return ( inventory.has_item(item) and (energy - item.use_energy) >= 0 and item.can_use(self, zone) ) func use_item(item : Item): if can_use_item_on_zone(item, action_zone): var is_item_used = item.use(self, action_zone) if is_item_used: energy -= item.use_energy if item.is_one_time_use(): delete_item(item) func upgrade_max_energy(amount = 1): max_energy += amount upgraded.emit() player_updated.emit(self) func recharge(amount : int = max_energy): energy = energy + amount upgraded.emit() func full_recharge(): energy = max(energy, max_energy) func generate_action_zone(radius : int = 0) -> Area2D: var area2D = Area2D.new() var collision_shape = CollisionShape2D.new() var circle_shape = CircleShape2D.new() circle_shape.radius = radius collision_shape.shape = circle_shape area2D.add_child(collision_shape) get_parent().add_child(area2D) return area2D func setup_preview_zone(zone_radius : int) -> Area2D: if preview_zone: preview_zone.queue_free() preview_zone = generate_action_zone(zone_radius) return preview_zone func setup_action_zone(zone_position : Vector2, zone_radius : int) -> Area2D: if action_zone: action_zone.queue_free() action_zone = generate_action_zone(zone_radius) action_zone.global_position = zone_position return action_zone func move_preview_zone(zone_position : Vector2): if preview_zone: preview_zone.global_position = zone_position func detect_area_in_preview_zone() -> Array: return preview_zone.get_overlapping_areas() func detect_area_in_action_zone() -> Array: if action_zone: return action_zone.get_overlapping_areas() return [] func play_sfx(sound : String): match sound: "dig": $Audio/AudioStreamPlayer_dig.play() "harvest": $Audio/AudioStreamPlayer_harvest.play() "pick": $Audio/AudioStreamPlayer_pick_up.play() "drop": $Audio/AudioStreamPlayer_drop.play() "move": $Audio/AudioStreamPlayer_movement.play() class Instruction: var position : Vector2 func _init(_pos : Vector2): position = _pos func can_be_done(player : Player): return player.global_position.distance_to(position) < 10 func do(_player : Player): pass class MoveInstruction extends Instruction: pass class ItemActionInstruction extends Instruction: var item = Item func _init(_pos : Vector2, _item : Item): position = _pos item = _item func can_be_done(player : Player): return player.global_position.distance_to(position) < player.MAX_REACH func do(player : Player): player.use_item(item) class InteractableInstruction extends Instruction: var interactable = Interactable func _init(_interactable : Interactable): interactable = _interactable position = interactable.global_position func can_be_done(player : Player): return player.global_position.distance_to(position) < player.MAX_REACH func do(player : Player): interactable.interact(player)