@tool extends Node2D @export var watching_node: Node2D @export var upside_down := false @export var eye_texture: Texture2D: set(val): eye_texture = val if is_node_ready(): eye_sprite.texture = eye_texture @export_range(0.2, 2.0) var eye_scale := 1.0: set(val): eye_scale = val if is_node_ready(): eye_sprite.scale = Vector2(eye_scale, eye_scale) @export var radius := 30.0: set(val): radius = val if is_node_ready(): _setup_eye_direction() @export var angle_range := 0.9 @export var debug_real_time_update := false @onready var eye_sprite := $眼睛 as Sprite2D func _ready() -> void: eye_sprite.texture = eye_texture eye_sprite.scale = Vector2(eye_scale, eye_scale) _setup_eye_direction() func _physics_process(_delta: float) -> void: if not watching_node or (Engine.is_editor_hint() and not debug_real_time_update): return _setup_eye_direction() func _setup_eye_direction(): if not watching_node: eye_sprite.position.y = radius return # set eye_sprite position at the arrow head from self's position to watching_node's position var direction = watching_node.global_position - global_position var min_range var max_range if upside_down: # mirror x-axis direction = Vector2(direction.x, -direction.y) min_range = -PI + angle_range max_range = -angle_range else: min_range = angle_range max_range = PI - angle_range var angle = direction.angle() # fit in angle_range if angle < min_range: angle = min_range - angle elif angle > max_range: angle = max_range - angle else: angle = 0.0 eye_sprite.position = direction.normalized().rotated(angle) * radius