@icon("res://assets/icons/player.svg") class_name Player extends CharacterBody2D ## Signals signal ball_dropped signal grab_attempted signal turn_finished ## Export variables @export var attributes: PlayerAttributes ## The attributes resource that defines the player's abilities, vitals etc. ## Regular variables var current_ball: Ball: set = set_current_ball var ball_within_reach: bool = false var has_ball: bool = false: set = set_has_ball var is_active: bool = false: set = set_active var desired_velocity: Vector2 var player_label_offset: Vector2 ## Onready variables ## Child nodes @onready var player_camera: Camera2D = $PlayerCamera @onready var player_hands: Node2D = $PlayerHands @onready var player_left_hand: RemoteTransform2D = %PlayerLeftHand @onready var player_right_hand: RemoteTransform2D = %PlayerRightHand @onready var player_label: PlayerLabel = $PlayerLabel @onready var player_nav: NavigationAgent2D = $PlayerNav @onready var player_reach: Area2D = $PlayerReach @onready var nav_target_sprite: Sprite2D = $NavTargetSprite @onready var player_sprite: Sprite2D = $PlayerSprite @onready var player_ui: CanvasLayer = $PlayerUI ## -- Overrides -- ## func _ready() -> void: _connect_signals() if attributes: _apply_attributes() player_label_offset = player_label.position func _process(_delta: float) -> void: player_label.global_position = global_position + player_label_offset if is_active: nav_target_sprite.global_position = get_global_mouse_position() func _physics_process(_delta: float) -> void: desired_velocity = global_position.direction_to(player_nav.get_next_path_position()) * attributes.movement_speed * 100.0 player_nav.velocity = desired_velocity func _input(event: InputEvent) -> void: if event.is_action_pressed("end_turn"): end_turn() if event.is_action_pressed("drop_ball"): if has_ball: drop_ball(current_ball) else: print_debug("%s can't drop the ball" % attributes.player_name) if event.is_action_pressed("grab_ball"): if ball_within_reach: attempt_grab(current_ball) else: print_debug("%s can't grab the ball" % attributes.player_name) if event is InputEventMouseButton and event.is_pressed() and event.button_index == 1: var click_position_global = get_global_mouse_position() print_debug("%s wants to navigate to %s" % [attributes.player_name, click_position_global]) player_nav.target_position = click_position_global var target_distance = player_nav.distance_to_target() print_debug("That's %s pixels/cm away" % target_distance) ## -- ACTIONS -- ## func attempt_grab(_b: Ball) -> void: print_debug("%s will attempt to grab the ball" % attributes.player_name) grab_attempted.emit() func drop_ball(_b: Ball) -> void: print_debug("%s will attempt to drop the ball" % attributes.player_name) for hand in player_hands.get_children(): hand = hand as RemoteTransform2D hand.remote_path = NodePath("") ball_dropped.emit() func end_turn() -> void: print_debug("%s says: I'd like my turn to end." % attributes.player_name) is_active = false turn_finished.emit() ## -- SETTERS -- ## func set_active(active: bool) -> void: is_active = active if is_active: print_debug("%s says: 'My turn!'" % attributes.player_name) player_camera.enabled = true player_camera.make_current() nav_target_sprite.visible = true player_nav.avoidance_priority = 0.0 set_process_input(true) else: print_debug("%s says: 'It's not my turn'" % attributes.player_name) player_camera.enabled = false nav_target_sprite.visible = false player_nav.avoidance_priority = 0.5 set_process_input(false) func set_current_ball(b: Ball) -> void: current_ball = b print_debug("%s sees the game ball" % attributes.player_name) func set_has_ball(h_b: bool) -> void: has_ball = h_b if has_ball: print_debug("%s says: I have the ball" % attributes.player_name) if attributes.player_handedness == Globals.PlayerHandedness.LEFT: player_left_hand.remote_path = player_left_hand.get_path_to(current_ball) else: player_right_hand.remote_path = player_right_hand.get_path_to(current_ball) else: print_debug("%s says: I no longer have the ball" % attributes.player_name) if attributes.player_handedness == Globals.PlayerHandedness.LEFT: player_left_hand.remote_path = NodePath("") else: player_right_hand.remote_path = NodePath("") ## -- RECEIVERS -- ## func on_player_reach_body_entered(body: PhysicsBody2D) -> void: if body is Player: print_debug((body.attributes.player_name) + " has entered %s's reach area" % attributes.player_name) func on_player_reach_area_entered(area: CollisionObject2D) -> void: if area is Ball: print_debug("The ball has entered %s's reach area" % attributes.player_name) ball_within_reach = true current_ball = area func on_player_reach_body_exited(body: PhysicsBody2D) -> void: if body is Player: print_debug((body.attributes.player_name) + " has exited %s's reach area" % attributes.player_name) func on_player_reach_area_exited(area: CollisionObject2D) -> void: if area is Ball: print_debug("The ball has exited %s's reach area" % attributes.player_name) ball_within_reach = false func on_velocity_computed(safe_velocity: Vector2) -> void: velocity = safe_velocity move_and_slide() ## -- HELPERS -- ## func _apply_attributes() -> void: player_label.player_name = attributes.player_name player_label.player_number = attributes.player_number player_label.player_position = attributes.player_position player_sprite.texture = attributes.player_texture func _connect_signals() -> void: player_nav.connect("velocity_computed", on_velocity_computed) player_reach.connect("body_entered", on_player_reach_body_entered) player_reach.connect("body_exited", on_player_reach_body_exited) player_reach.connect("area_entered", on_player_reach_area_entered) player_reach.connect("area_exited", on_player_reach_area_exited)