Improved UI textbox
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
class_name DialogueChoiceBox extends PanelContainer
|
||||
|
||||
const SCENE:PackedScene = preload("res://ui/component/DialogueChoiceBox.tscn")
|
||||
const MAX_WIDTH:float = 120.0
|
||||
|
||||
signal chosen(response:DialogueResponse)
|
||||
|
||||
var _responses:Array[DialogueResponse] = []
|
||||
var _entity:Entity = null
|
||||
var _selectedIndex:int = 0
|
||||
var _hasLetGoOfInteract:bool = true
|
||||
|
||||
@onready var _list:VBoxContainer = $VBoxContainer/List
|
||||
|
||||
func _ready() -> void:
|
||||
size.x = MAX_WIDTH
|
||||
visible = false
|
||||
|
||||
func setup(responses:Array[DialogueResponse], entity:Entity) -> void:
|
||||
_entity = entity
|
||||
_responses = responses.filter(func(r): return r.is_allowed)
|
||||
_selectedIndex = 0
|
||||
_hasLetGoOfInteract = !Input.is_action_pressed("interact")
|
||||
|
||||
for child in _list.get_children():
|
||||
child.queue_free()
|
||||
|
||||
for response in _responses:
|
||||
var label:Label = Label.new()
|
||||
label.text = response.text
|
||||
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_list.add_child(label)
|
||||
|
||||
size.x = MAX_WIDTH
|
||||
visible = true
|
||||
_updateSelection()
|
||||
|
||||
func _process(_delta:float) -> void:
|
||||
if not visible:
|
||||
return
|
||||
_updateWorldPosition()
|
||||
_processInput()
|
||||
|
||||
func _processInput() -> void:
|
||||
if Input.is_action_just_released("interact"):
|
||||
_hasLetGoOfInteract = true
|
||||
|
||||
if Input.is_action_just_pressed("ui_up") or Input.is_action_just_pressed("move_forward"):
|
||||
_selectedIndex = max(0, _selectedIndex - 1)
|
||||
_updateSelection()
|
||||
|
||||
if Input.is_action_just_pressed("ui_down") or Input.is_action_just_pressed("move_back"):
|
||||
_selectedIndex = min(_responses.size() - 1, _selectedIndex + 1)
|
||||
_updateSelection()
|
||||
|
||||
if _hasLetGoOfInteract and Input.is_action_just_pressed("interact"):
|
||||
_confirm()
|
||||
|
||||
func _confirm() -> void:
|
||||
if _responses.is_empty():
|
||||
return
|
||||
var response:DialogueResponse = _responses[_selectedIndex]
|
||||
chosen.emit(response)
|
||||
visible = false
|
||||
queue_free()
|
||||
|
||||
func _updateSelection() -> void:
|
||||
var children:Array = _list.get_children()
|
||||
for i in children.size():
|
||||
var label:Label = children[i]
|
||||
if i == _selectedIndex:
|
||||
label.add_theme_color_override("font_color", Color.YELLOW)
|
||||
else:
|
||||
label.remove_theme_color_override("font_color")
|
||||
|
||||
func _updateWorldPosition() -> void:
|
||||
if _entity == null:
|
||||
return
|
||||
var camera:Camera3D = get_viewport().get_camera_3d()
|
||||
if camera == null:
|
||||
return
|
||||
var worldPos:Vector3 = _entity.global_position + Vector3(0, 2.5, 0)
|
||||
var screenPos:Vector2 = camera.unproject_position(worldPos)
|
||||
var viewportSize:Vector2 = get_viewport().get_visible_rect().size
|
||||
position = screenPos - Vector2(size.x * 0.5, size.y)
|
||||
position.x = clamp(position.x, 0.0, viewportSize.x - size.x)
|
||||
position.y = clamp(position.y, 0.0, viewportSize.y - size.y)
|
||||
Reference in New Issue
Block a user