GODOT-简单对话系统

📌 为什么继承 Resource

  • Resource 是一个轻量的对象类型,通常用于保存数据(比如对话、配置、技能数据等),而不是控制场景中的节点逻辑。

  • 如果你想创建一个可以被序列化、保存并重复使用的数据结构,比如:

    • 一个对话系统中的每段对话
    • 游戏角色的配置文件
    • 技能、任务、物品等定义
      那么继承 Resource 是一种很合适的做法。

``

extends 复制代码
class_name Dialogue  # 定义一个可在全局使用的资源类,文件名可以直接对应 class_name

@export var character_name : String
# 导出一个字符串变量,用于存储角色名字,在 Inspector 中可视化编辑

@export_multiline var content : String
# 导出一个多行文本变量,适合较长的对话内容,Inspector 中会显示一个大文本框

@export var avatar : Texture
# 导出一个 Texture 类型变量,可以在 Inspector 中拖入角色头像图片资源

@export var show_on_left : bool
# 导出一个布尔型变量,用于在对话框显示时判断该角色头像是在左侧还是右侧
行号 原代码 说明
1 extends Resource 继承 Godot 的 Resource 类,使其可以作为资源保存和共享
2 class_name Dialogue 定义全局类名,方便在其他脚本 @export var dialogue: Dialogue 中使用
4 @export var character_name : String 导出接口供 Inspector 直接编辑角色名
6 @export_multiline var content : String 多行文本编辑器,适合输入对话内容
8 @export var avatar : Texture 导入头像贴图,资源编辑器可拖拽赋值
10 @export var show_on_left : bool 控制头像显示方向,左或右,布尔值直观控制界面布局

📋 为什么使用这些语法?

  • @export, @export_multiline 是 Godot 4.x 新的属性导出语法,可让变量出现在编辑器 Inspector,方便赋值及配置
  • extends Resource + class_name 用于定义一个可序列化且全项目可引用的资源类,适合对话、技能、剧情等数据的统一管理与复用。
  • @export_multiline 尤其适合长文本,自动命令 Inspector 显示大文本区域,提升易读性和编辑体验。

🎯 使用场景总结

  • 在 Inspector 中可视化编辑:无需写代码赋值,通过界面配置对话内容、头像、位置等。
  • 作为独立资源可复用 :可以创建多个 .tres.res 对话资源,多个 NPC 或对话事件使用同一个数据。
  • 序列化与版本控制:对话内容存为资源文件,可纳入版本控制,便于管理与协作。
  • 数据与逻辑解耦:该脚本只负责对话数据本身,逻辑交互部分可以另写脚本处理专属 UI 展示。
extends 复制代码
class_name DialogueGroup  # 将此脚本声明为一个全局资源类型,可以在 Inspector 创建或其他脚本引用

@export var dialogue_list : Array[Dialogue] = []
# 导出一个 Dialogue 类型的数组,Inspector 中可编辑
# 使用默认空数组 [],避免 dialogue_list 为 null,提高编辑体验
Control 复制代码
└── HBoxContainer
    ├── LeftAvatar (TextureRect)
    ├── Panel
    │   └── MarginContainer
    │       └── VBoxContainer
    │           ├── Name (Label)
    │           └── Content (Label, Text 等)
    └── RightAvatar (TextureRect)

📐 节点作用详解

HBoxContainer

  • 水平排列子节点(左右),自动分配空间
  • LeftAvatar 和 RightAvatar 分别居左和居右,Panel(对话内容)保持居中和伸缩。

LeftAvatar / RightAvatar (TextureRect)

  • 用于显示角色头像。根据对话方向(左侧或右侧)选择显示哪一个,另一个可以隐藏或设置可见性。

Panel

  • 通常是 PanelContainer,加上 MarginContainer 提供背景边框和阴影效果,同时截断输入

MarginContainer

  • 为 Panel 内部内容提供内边距(padding),避免文本或头像贴边

VBoxContainer

  • 垂直排列 Name 和 Content 标签,使角色名在上,内容在下

Label

  • 显示单行或自动换行的纯文本,不支持文字高亮、图片等复杂格式

  • 如果需要显示带有粗体、斜体、颜色、表情或图片的文本,应使用 RichTextLabel

🎯 属性解析

  • Texture:设置所显示的贴图(头像)。你可以直接从资源浏览器拖拽,也可点击小图标选择。

  • Expand Mode(扩展模式)

    控制节点最小尺寸的来源:

  • Stretch Mode(拉伸模式)

    决定纹理在控制节点区域如何绘制:

    • Keep Aspect: 等比缩放至充满节点边界,保持比例。
    • Keep Size: 保持原始尺寸,放在左上角。
    • Keep Aspect Centered: 等比缩放并居中显示。
    • Scale: 拉伸以完全填充节点矩形。

🧰 自动拉伸至填满父容器的全部空间,边距归零,尺寸与位置全由容器控制

✅ 总结

你看到的 Autowrap 四个选项分别控制不同的换行策略:

模式 描述
Off 不换行,整行显示
Arbitrary 任意位置断行
Word 单词边界换行
Word (Smart) 智能单词和标点符号换行,过长单词拆分
目的 为什么继承 Control
UI 布局 支持锚点、Container、自动调整大小
事件交互 能响应鼠标点击、焦点、输入
容易编辑与维护 编辑器可视化布局、属性设置统一靠 Control
场景结构清晰 UI 代码集中在 UI 根节点,逻辑清晰、扩展方便
extends 复制代码
# 继承 Control,用于管理对话 UI 布局、输入事件等

@export_group("UI")
@export var character_name_text : Label
@export var text_box : Label
@export var left_avatar : TextureRect
@export var right_avatar : TextureRect
# 导出 UI 控件引用,在 Inspector 中绑定对应节点,便于脚本访问和修改

@export_group("对话")
@export var main_dialogue : DialogueGroup
# 导出对话组资源,Inspector 可选择 `.tres` 文件,方便对话数据关联

var dialogue_index := 0
# 用于记录当前对话的索引位置

var typing_tween : Tween
# 存储当前用于"打字效果"的 Tween

func display_next_dialogue():
    # 展示下一条对话
    if dialogue_index >= len(main_dialogue.dialogue_list):
        visible = false
        return
        # 如果索引超出,隐藏整个对话 UI 并退出

    var dialogue := main_dialogue.dialogue_list[dialogue_index]
    # 获取当前 Dialogue 实例

    if typing_tween and typing_tween.is_running():
        # 如果打字动画还在运行,直接结束动画并显示完整文本
        typing_tween.kill()
        text_box.text = dialogue.content
        dialogue_index += 1

    else:
        # 正常开启打字动画
        character_name_text.text = dialogue.character_name
        typing_tween = get_tree().create_tween()
        text_box.text = ""
        # 字母逐个显示
        for character in dialogue.content:
            typing_tween.tween_callback(append_character.bind(character)).set_delay(0.05)
            # 每隔 0.05 秒执行一次 append_character,传入当前字符  
            # 使用 Callable.bind 参数传递方式,是 Godot 4 的推荐用法:contentReference[oaicite:1]{index=1}
        typing_tween.tween_callback(func(): dialogue_index += 1)
        # 在动画全部执行后,索引增加 1,准备下一句

        # 根据对话方向控制头像显示
        if dialogue.show_on_left:
            left_avatar.texture = dialogue.avatar
            right_avatar.texture = null
        else:
            left_avatar.texture = null
            right_avatar.texture = dialogue.avatar

func append_character(character : String):
    text_box.text += character
    # 将传入的字符追加到对话内容 Label 中

func _ready():
    display_next_dialogue()
    # 场景加载完成后立即开启第一句对话

func _on_click(event):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
        display_next_dialogue()
        # 捕获点击事件,如果是左键按下,就播放下一句或跳过动画

Godot 中的 Tween:

它是一个轻量级对象,用脚本创建,能在运行时对属性进行平滑动画控制,例如位置、颜色、透明度、文本逐字显示等

相关推荐
郭逍遥7 天前
[Godot] 通过AABB包围盒和射线法检测碰撞
算法·游戏引擎·godot
风痕天际7 天前
Godot扫雷游戏制作记录4——计算周围地雷数并显示
游戏·游戏引擎·godot
风痕天际7 天前
Godot扫雷游戏制作记录3——随机埋雷
游戏·游戏引擎·godot
风痕天际12 天前
Godot扫雷游戏制作记录2——鼠标交互
游戏·游戏引擎·godot
风痕天际15 天前
Godot扫雷游戏制作记录1——基础场景搭建
游戏·游戏引擎·godot·gdscript·教程
dlpay16 天前
使用blender搭建模型并导入godot游戏引擎
游戏引擎·godot·blender
会飞的一棵树1 个月前
Godot UI布局指南
godot
浪客川1 个月前
1972 GODOT 入门案例
android·java·godot
习惯就好zz1 个月前
从奶牛NPC到完整场景构建
godot·cow·house·npc·tilemaplayer·bed
郝学胜-神的一滴1 个月前
QtOpenGL多线程渲染方案深度解析
c++·qt·unity·游戏引擎·godot·图形渲染·unreal engine