extends CanvasLayer @export var side_change_speed: float = 15 @export var screen_inset: float = 100 var _cursor_scene := preload("res://scenes/ui/cursor_base.tscn") var _cursors: Dictionary @onready var _single_cursor: Control = $CursorBase func _ready() -> void: Input.mouse_mode = Input.MOUSE_MODE_HIDDEN func _process(delta: float) -> void: if not Referencer.players or not Referencer.main_camera: var mouse_pos := get_viewport().get_mouse_position() _single_cursor.position = mouse_pos - _single_cursor.size / 2 _single_cursor.visible = true return _single_cursor.visible = false call_deferred("_handle_cursors", delta) func _handle_cursors(delta: float) -> void: for player_index in range(Referencer.players_count): _handle_cursor(player_index, delta) func _init_player_cursor(id: int) -> void: var cursor_node: Control = _cursor_scene.instantiate() as Control add_child(cursor_node) _cursors[id] = PlayerCursor.new( cursor_node, cursor_node.get_node("CursorBat") as Control, cursor_node.get_node("CursorArrow") as Control ) func _handle_cursor(player_index: int, delta: float) -> void: var player := Referencer.players[player_index] var id := player.get_instance_id() if not _cursors.has(id): _init_player_cursor(id) return var cursor_pos_world := player.attack.global_position + player.aiming.aim_offset var cursor_pos_screen := Referencer.main_camera.unproject_position(cursor_pos_world) var clamp_corner_min := Vector2.ZERO var clamp_corner_max := get_viewport().get_visible_rect().size if player.input_mode_is(Inputer.Mode.CONTROLLER): clamp_corner_min += Vector2(screen_inset, screen_inset) clamp_corner_max -= Vector2(screen_inset, screen_inset) var cursor: PlayerCursor = _cursors[id] cursor.base.position = ( cursor_pos_screen.clamp(clamp_corner_min, clamp_corner_max) - cursor.base.size / 2 ) cursor.side = lerpf( cursor.side as float, (PI / 2.0) * (1.0 if player.attack.side == PlayerAttack.Side.LEFT else -1.0), side_change_speed * delta ) var aim_offset_normalized := player.aiming.aim_offset.normalized() var bat_rotation_point_screen := Referencer.main_camera.unproject_position( ( cursor_pos_world + aim_offset_normalized.rotated(Vector3.UP, cursor.side as float) ) ) var arrow_rotation_point_screen := Referencer.main_camera.unproject_position( cursor_pos_world + aim_offset_normalized ) cursor.bat.rotation = cursor_pos_screen.angle_to_point(bat_rotation_point_screen) cursor.arrow.rotation = cursor_pos_screen.angle_to_point( arrow_rotation_point_screen ) class PlayerCursor: var base: Control var bat: Control var arrow: Control var side: float = 0 func _init(_base: Control, _bat: Control, _arrow: Control) -> void: base = _base bat = _bat arrow = _arrow