class_name LoadingZone extends Area3D const FLOOR_CHECK_DISTANCE: float = 100.0 const FLOOR_ANTICLIP: float = 0.25 const RAYCAST_ANTICLIP: float = 5.0 const AREA_ANTICLIP: float = 1.0 const SCENE_START_TIMEOUT: float = 1.0 enum ActiveState { DISABLED, ENABLED, DROPOFF_ONLY } @export var active_state := ActiveState.ENABLED @onready var bounds := ( $'CollisionShape3D' as CollisionShape3D ).shape as BoxShape3D func dropoff_site() -> Transform3D: var raycast := PhysicsRayQueryParameters3D.new() raycast.from = ( global_position + basis.z*(bounds.size.z/2.0 + AREA_ANTICLIP) + basis.y*RAYCAST_ANTICLIP ) raycast.to = raycast.from - basis.y*FLOOR_CHECK_DISTANCE var chk := get_world_3d().direct_space_state.intersect_ray(raycast) return Transform3D(basis.orthonormalized(), ( global_position if chk.is_empty() else chk.position + basis.y*FLOOR_ANTICLIP )) func dropoff(what: Node3D, use_model_front: bool = true) -> void: what.transform = dropoff_site() if use_model_front: what.basis = what.basis.rotated(what.basis.y, PI) func pickup(node: Node) -> void: if ( active_state == ActiveState.ENABLED and PlayerControl.enabled() and node == PlayerControl.get_runner() ): Storyboard.try_follow_map_connection(name) func enable() -> void: if active_state != ActiveState.DROPOFF_ONLY: active_state = ActiveState.ENABLED func disable() -> void: if active_state != ActiveState.DROPOFF_ONLY: active_state = ActiveState.DISABLED func enabled() -> bool: return bool(active_state == ActiveState.ENABLED) func _ready() -> void: _connect_pickup_after_timeout.call_deferred() func _connect_pickup_after_timeout() -> void: await Wait.seconds(SCENE_START_TIMEOUT) body_entered.connect(pickup)