class_name WorldChatBox extends PanelContainer enum Mode { ADVANCEABLE, TIMED } const SCENE = preload("res://ui/component/WorldChatBox.tscn") signal chatboxClosed var mode:Mode = Mode.TIMED var worldTarget:Node3D = null var _timer:float = 0.0 var _label:Label func _ready() -> void: _label = $MarginContainer/Label UI.addChatBox(self) visible = false func showTimed(text:String, duration:float) -> void: mode = Mode.TIMED _timer = duration _label.text = text visible = true func showAdvanceable(text:String) -> void: mode = Mode.ADVANCEABLE _label.text = text visible = true func showAndWait(text:String) -> void: showAdvanceable(text) await chatboxClosed func close() -> void: UI.removeChatBox(self) chatboxClosed.emit() queue_free() func _updateWorldPosition() -> void: if worldTarget == null: return var camera:Camera3D = get_viewport().get_camera_3d() if camera == null: return var screenPos:Vector2 = camera.unproject_position(worldTarget.global_position + Vector3(0, 2.5, 0)) var viewportSize:Vector2 = get_viewport().get_visible_rect().size position = screenPos - size * 0.5 position.x = clamp(position.x, 0.0, viewportSize.x - size.x) position.y = clamp(position.y, 0.0, viewportSize.y - size.y) func _process(delta:float) -> void: if !visible: return _updateWorldPosition() match mode: Mode.TIMED: _timer -= delta if _timer <= 0.0: close() Mode.ADVANCEABLE: if Input.is_action_just_pressed("interact"): close()