学习空间/界面与对白:让输入不会穿透
玩家与交互 / LESSON 16

界面与对白:让输入不会穿透

先做清楚可关闭的文本面板,再扩展复杂对白。

基础约 8 分钟阅读,实作另计7 节现在学
CONCEPT MAP先看一眼知识之间的联系
先看一眼知识之间的联系01检查面板依赖02打开并交焦点03锁定世界输入04关闭通知05恢复控制
界面显示与玩家控制需要成对切换;每一条失败或关闭路径都要有明确的恢复结果。

01世界空间与界面空间

调查文字通常不应随着世界摄像机一起飘走。可用 CanvasLayer 承载屏幕 UI,下面放 Control。Control 用锚点、偏移与容器安排布局。不要用大量固定像素坐标硬拼全部界面,否则窗口改变尺寸后容易遮挡或挤出屏幕。

02本课只做一个面板

建议节点结构 text
CanvasLayer
└── PanelContainer      # 挂 dialogue_practice.gd
    └── VBoxContainer
        ├── Label
        └── Button      # 文本:继续 / 关闭

将 PanelContainer 放到屏幕下方,设置合适的最小宽度;Label 开启合适的自动换行,按钮保持可见。面板脚本在启动时显示,不假定上一课已与它集成。

03带关闭信号的最小脚本

dialogue_practice.gd gdscript
extends PanelContainer
signal closed

@onready var body_label: Label = $VBoxContainer/Label
@onready var close_button: Button = $VBoxContainer/Button

func _ready() -> void:
    close_button.pressed.connect(_close)
    show_text("教学占位文字。这里不确定任何正式剧情。")

func show_text(value: String) -> void:
    body_label.text = value
    show()
    close_button.grab_focus()

func _close() -> void:
    hide()
    closed.emit()

这个脚本只管显示和关闭。正式接入时,由场景协调者在打开面板时锁定玩家输入,在 closed 信号后释放;不要让面板硬编码所有 Player 的绝对路径。

04输入锁不是“暂停按钮”四个字

只在 _unhandled_input 接收动作不保证玩家停止移动:Input.get_vector 读取的是输入状态,所以玩家仍需检查 input_locked 或明确的模式状态。若以后暂停 SceneTree,还需确保关闭 UI 自己在暂停时仍能接收输入。先做局部输入锁,避免初学时混入整树暂停的更多条件。

  1. 鼠标点击与键盘焦点都能关闭面板。
  2. 窗口变窄时长文本不遮住按钮。
  3. 接入练习玩家后测试对话中不能走动,关闭后可以恢复。
  4. 连续开关三次,确认没有重复连接或永久锁死。

05用长文本主动挤压界面,而不是只测一句话

先用一句短说明确认面板出现,再换成三段较长中文,最后加入一串较长的英文资源名。观察面板是否越出窗口、按钮是否被挤走、文字是否能完整阅读。界面不能只在你写的第一句占位文字上好看,因为正式对白长度会变化。需要决定内容如何换行、面板如何限制尺寸,以及超出区域时如何阅读。

  1. 把测试窗口分别调成较宽和较窄,保持同一段内容。
  2. 检查文字边距、按钮可见性和鼠标点击范围,而不只看面板背景。
  3. 用键盘移动焦点并确认按钮,观察有没有落到看不见的控件。
  4. 在实际显示尺寸下读一遍,确认不是只有放大截图才清晰。这里测试的是布局能力,不替正式字体与画面比例定案。

06打开和关闭面板,要有同一位协调者收尾

面板显示文字是一种职责,玩家是否允许移动是另一种职责。可以让练习房间的协调脚本在打开面板时设置输入锁,在收到 closed 后恢复;面板本身只发出“我关闭了”这个事实。这样更容易找到输入状态的唯一修改位置,不必让每个按钮都去寻找 Player。

在纸上写出一次完整配对:请求显示、设置内容、锁定移动、把焦点交给关闭按钮;收到关闭、隐藏内容、恢复移动、恢复合适的焦点。接着故意让“缺少面板引用”这条路径发生,确认不会先锁住玩家再永久等待一个根本不会出现的关闭信号。可以先检查依赖再改变状态;重点是每个提前返回都要说明是否已经产生了需要撤销的副作用。

07防止打开面板的那次按键顺手把它关掉

如果同一个按键既调查物件又确认对白,需要特别观察事件是否在同一轮处理里被多个对象响应。玩家只按一下却看不见面板,有可能不是没打开,而是打开后立刻关闭了。给打开和关闭各加一条带来源的临时日志,先确认真实顺序,再决定由哪个输入入口处理当前模式下的操作。

连续执行五轮“靠近—打开—关闭—离开”,其中一轮持续按住按键,一轮用鼠标关闭,一轮在窗口失焦后返回。对话中不能继续走动,关闭后也不能永久锁住;每次主动确认只推进约定的一步。完成记录应同时说明界面是否正确显示与输入模式是否正确恢复。只用 _unhandled_input 不会自动阻止 Input.get_vector 读取按键状态,因此玩家移动脚本仍需遵守明确的输入锁或模式判断。

动手后,再勾选

不是“我看懂了”,而是你在独立练习里做出并检查过。

CHECK YOUR UNDERSTANDING

换一个情景,你会怎么判断?

面板打开后,玩家仍用 get_vector 移动,应该检查什么?

用自己的话,留一条笔记

可以写“我之前以为……,现在发现……”,或者记录还没解决的问题。

仅保存在此浏览器0 / 20000

回到资料核对

本课是解释与练习,不替代对应版本的官方手册。网页实验不运行 Godot;未标明实机验证的代码,仍需在独立工程中检查。

把这课收进你的理解里。

标记已读不会自动勾选实作,也不代表游戏功能已经完成。

输入一个你想弄明白的问题。

按 Esc 关闭 · 标题、关键词和正文一起搜索