263 lines
7.2 KiB
GDScript
263 lines
7.2 KiB
GDScript
extends Control
|
|
class_name DialogueBox
|
|
## 对话框 UI
|
|
## 显示对话消息和输入界面
|
|
|
|
# UI 元素
|
|
var message_display: RichTextLabel
|
|
var message_input: LineEdit
|
|
var send_button: Button
|
|
var close_button: Button
|
|
var target_label: Label
|
|
var container: VBoxContainer
|
|
var scroll_container: ScrollContainer
|
|
|
|
# 状态
|
|
var current_target_name: String = ""
|
|
|
|
# 信号
|
|
signal message_sent(message: String)
|
|
signal dialogue_closed()
|
|
|
|
func _ready():
|
|
"""初始化对话框"""
|
|
_create_ui()
|
|
hide()
|
|
|
|
func _process(_delta):
|
|
"""每帧检查焦点状态"""
|
|
# 简化焦点管理,避免干扰按钮点击
|
|
pass
|
|
|
|
func _input(event):
|
|
"""处理对话框的输入事件"""
|
|
# 只有在对话框可见时才处理输入
|
|
if not visible:
|
|
return
|
|
|
|
# ESC键关闭对话框
|
|
if event is InputEventKey and event.pressed:
|
|
if event.keycode == KEY_ESCAPE:
|
|
_on_close_pressed()
|
|
get_viewport().set_input_as_handled() # 阻止事件继续传播
|
|
return
|
|
|
|
# 不要处理鼠标事件,让按钮自己处理
|
|
if event is InputEventMouseButton:
|
|
return
|
|
|
|
## 创建 UI 元素
|
|
func _create_ui():
|
|
"""创建对话框的所有 UI 元素"""
|
|
# 设置为居中显示
|
|
anchor_left = 0.5
|
|
anchor_top = 0.5
|
|
anchor_right = 0.5
|
|
anchor_bottom = 0.5
|
|
offset_left = -250
|
|
offset_top = -200
|
|
offset_right = 250
|
|
offset_bottom = 200
|
|
|
|
# 创建背景
|
|
var panel = Panel.new()
|
|
panel.anchor_right = 1.0
|
|
panel.anchor_bottom = 1.0
|
|
add_child(panel)
|
|
|
|
# 创建主容器
|
|
container = VBoxContainer.new()
|
|
container.anchor_right = 1.0
|
|
container.anchor_bottom = 1.0
|
|
container.offset_left = 10
|
|
container.offset_top = 10
|
|
container.offset_right = -10
|
|
container.offset_bottom = -10
|
|
add_child(container)
|
|
|
|
# 标题栏
|
|
var title_bar = HBoxContainer.new()
|
|
container.add_child(title_bar)
|
|
|
|
# 对话目标标签
|
|
target_label = Label.new()
|
|
target_label.text = "对话"
|
|
target_label.add_theme_font_size_override("font_size", 18)
|
|
target_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
title_bar.add_child(target_label)
|
|
|
|
# 关闭按钮
|
|
close_button = Button.new()
|
|
close_button.text = "X"
|
|
close_button.custom_minimum_size = Vector2(30, 30)
|
|
close_button.mouse_filter = Control.MOUSE_FILTER_STOP # 确保按钮能接收鼠标事件
|
|
close_button.focus_mode = Control.FOCUS_ALL # 确保按钮可以获得焦点
|
|
close_button.pressed.connect(_on_close_pressed)
|
|
title_bar.add_child(close_button)
|
|
|
|
# 间距
|
|
container.add_child(_create_spacer(10))
|
|
|
|
# 消息显示区域(带滚动)
|
|
scroll_container = ScrollContainer.new()
|
|
scroll_container.custom_minimum_size = Vector2(0, 250)
|
|
scroll_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
container.add_child(scroll_container)
|
|
|
|
message_display = RichTextLabel.new()
|
|
message_display.bbcode_enabled = true
|
|
message_display.scroll_following = true
|
|
message_display.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
message_display.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
scroll_container.add_child(message_display)
|
|
|
|
# 间距
|
|
container.add_child(_create_spacer(10))
|
|
|
|
# 输入区域
|
|
var input_container = HBoxContainer.new()
|
|
container.add_child(input_container)
|
|
|
|
# 消息输入框
|
|
message_input = LineEdit.new()
|
|
message_input.placeholder_text = "输入消息..."
|
|
message_input.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
message_input.max_length = 500
|
|
message_input.text_submitted.connect(_on_message_submitted)
|
|
# 连接焦点丢失信号,自动重新获取焦点
|
|
message_input.focus_exited.connect(_on_input_focus_exited)
|
|
input_container.add_child(message_input)
|
|
|
|
# 发送按钮
|
|
send_button = Button.new()
|
|
send_button.text = "发送"
|
|
send_button.custom_minimum_size = Vector2(80, 0)
|
|
send_button.mouse_filter = Control.MOUSE_FILTER_STOP # 确保按钮能接收鼠标事件
|
|
send_button.focus_mode = Control.FOCUS_ALL # 确保按钮可以获得焦点
|
|
send_button.pressed.connect(_on_send_pressed)
|
|
input_container.add_child(send_button)
|
|
|
|
print("Send button created and connected")
|
|
|
|
## 创建间距
|
|
func _create_spacer(height: float) -> Control:
|
|
"""创建垂直间距"""
|
|
var spacer = Control.new()
|
|
spacer.custom_minimum_size = Vector2(0, height)
|
|
return spacer
|
|
|
|
## 开始对话
|
|
func start_dialogue(target_name: String):
|
|
"""
|
|
开始对话并显示对话框
|
|
@param target_name: 对话目标的名称
|
|
"""
|
|
current_target_name = target_name
|
|
target_label.text = "与 " + target_name + " 对话"
|
|
message_display.clear()
|
|
message_input.clear()
|
|
|
|
show()
|
|
# 延迟获取焦点,确保对话框完全显示后再获取
|
|
call_deferred("_ensure_input_focus")
|
|
|
|
## 添加消息到显示区域
|
|
func add_message(sender: String, message: String):
|
|
"""
|
|
添加消息到对话显示区域
|
|
@param sender: 发送者名称
|
|
@param message: 消息内容
|
|
"""
|
|
var timestamp = Time.get_time_string_from_system()
|
|
var color = "[color=cyan]" if sender == "你" else "[color=yellow]"
|
|
var formatted_message = "%s[%s] %s:[/color] %s\n" % [color, timestamp, sender, message]
|
|
|
|
# 使用call_deferred确保UI更新不会被阻塞
|
|
message_display.call_deferred("append_text", formatted_message)
|
|
|
|
# 延迟滚动到底部,确保文本已添加
|
|
call_deferred("_scroll_to_bottom")
|
|
|
|
## 关闭对话框
|
|
func close_dialogue():
|
|
"""关闭对话框"""
|
|
hide()
|
|
message_input.clear()
|
|
current_target_name = ""
|
|
|
|
## 发送按钮点击
|
|
func _on_send_pressed():
|
|
"""发送按钮被点击"""
|
|
print("=== SEND BUTTON PRESSED ===")
|
|
|
|
if not message_input:
|
|
print("ERROR: message_input is null")
|
|
return
|
|
|
|
var message = message_input.text.strip_edges()
|
|
print("Message text: '", message, "'")
|
|
|
|
if message.is_empty():
|
|
print("Empty message, focusing input")
|
|
_ensure_input_focus()
|
|
return
|
|
|
|
print("Processing message: ", message)
|
|
|
|
# 立即显示玩家消息
|
|
add_message("你", message)
|
|
|
|
# 发射信号给对话系统处理
|
|
print("Emitting message_sent signal")
|
|
message_sent.emit(message)
|
|
|
|
# 清空输入框并重新获取焦点
|
|
message_input.clear()
|
|
call_deferred("_ensure_input_focus")
|
|
|
|
print("=== SEND BUTTON PROCESSING COMPLETE ===")
|
|
|
|
## 关闭按钮点击
|
|
func _on_close_pressed():
|
|
"""关闭按钮被点击"""
|
|
print("=== CLOSE BUTTON PRESSED ===")
|
|
dialogue_closed.emit()
|
|
close_dialogue()
|
|
print("=== CLOSE BUTTON PROCESSING COMPLETE ===")
|
|
|
|
## 消息输入框回车
|
|
func _on_message_submitted(_text: String):
|
|
"""消息输入框按下回车"""
|
|
print("Enter key pressed") # 调试日志
|
|
_on_send_pressed()
|
|
|
|
## 滚动到底部
|
|
func _scroll_to_bottom():
|
|
"""滚动消息显示区域到底部"""
|
|
if scroll_container and scroll_container.get_v_scroll_bar():
|
|
var v_scroll = scroll_container.get_v_scroll_bar()
|
|
v_scroll.value = v_scroll.max_value
|
|
|
|
|
|
|
|
## 确保输入框焦点
|
|
func _ensure_input_focus():
|
|
"""确保输入框获得并保持焦点"""
|
|
if message_input and visible:
|
|
# 使用call_deferred确保在UI更新完成后获取焦点
|
|
message_input.call_deferred("grab_focus")
|
|
|
|
## 输入框焦点丢失处理
|
|
func _on_input_focus_exited():
|
|
"""当输入框失去焦点时的处理"""
|
|
# 简化焦点管理,避免干扰按钮操作
|
|
# 只在特定情况下重新获取焦点
|
|
if visible and message_input:
|
|
# 延迟检查,给按钮操作时间完成
|
|
await get_tree().create_timer(0.1).timeout
|
|
if visible and message_input:
|
|
var focused_control = get_viewport().gui_get_focus_owner()
|
|
# 只有当没有任何控件获得焦点时才重新获取
|
|
if not focused_control:
|
|
message_input.grab_focus()
|