@tool extends Node2D enum State { IDLE, WINDING_UP, ATTACK, RECOVER, } @export var idle_distance: float @export_custom(PROPERTY_HINT_NONE, "radians_as_degrees") var idle_rotate_speed: float @export var wind_up_time: float @export var wind_up_distance: float @export var attack_time: float @export var attack_distance: float @export var recover_time: float @export_range(0,1,1,"or_greater") var detection_radius: float: set(value): detection_radius = value if not is_inside_tree(): await tree_entered var shape = detector_shape.shape as CircleShape2D if shape: shape.radius = detection_radius @export_group("Internal References") @export var head: Node2D @export var head_pivot: Node2D @export var detector_shape: CollisionShape2D var state: State = State.IDLE var tween: Tween = null var tracked_player: Player = null var idle_angle: float = 0.0 var target_pos: Vector2 = Vector2.ZERO var progress: float = 0.0 func _process(delta: float) -> void: if Engine.is_editor_hint(): return match state: State.IDLE: idle_angle = fposmod(idle_angle + idle_rotate_speed * delta, TAU) head_pivot.rotation = idle_angle State.WINDING_UP: target_pos = tracked_player.global_position var angle = (global_position - target_pos).angle() progress += delta / wind_up_time head_pivot.rotation = lerp_angle(head_pivot.rotation, angle, progress) State.RECOVER: progress += delta / recover_time head_pivot.rotation = lerp_angle(head_pivot.rotation, idle_angle, progress) func _start_attack() -> void: state = State.WINDING_UP if tween: tween.kill() tween = create_tween().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS) tween.tween_property(head, ^"position:x", wind_up_distance, wind_up_time) tween.tween_property(self, ^"state", State.ATTACK, 0.0) tween.tween_property(head, ^"position:x", -attack_distance, attack_time).set_trans(Tween.TRANS_BOUNCE) tween.tween_property(self, ^"state", State.RECOVER, 0.0) tween.tween_property(head, ^"position:x", idle_distance, recover_time) tween.tween_property(self, ^"state", State.IDLE, 0.0) func _on_player_detector_body_entered(body: Node2D) -> void: if body is Player: if state == State.IDLE: tracked_player = body _start_attack()