创建新工程
This commit is contained in:
262
scripts/DialogueBox.gd
Normal file
262
scripts/DialogueBox.gd
Normal file
@@ -0,0 +1,262 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user