创建新工程

This commit is contained in:
moyin
2025-12-05 19:00:14 +08:00
commit ff4fa5fffd
227 changed files with 32804 additions and 0 deletions

262
scripts/DialogueBox.gd Normal file
View 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()