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:

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

相关推荐
libo_202516 天前
AI素材生成:Godot+HarmonyOS 5 MindSpore实现游戏贴图的实时风格迁移
godot
程序员小刘22 天前
如何开始HarmonyOS 5与Godot引擎融合开发?
华为·游戏引擎·godot·harmonyos
三巧1 个月前
Godot 敌人生成半径和围墙不匹配,导致敌人错误的生成在围墙外的解决代码
游戏引擎·godot
技术小甜甜1 个月前
【Godot引擎】如何使用内置的全局搜索功能提升开发效率
游戏引擎·godot
技术小甜甜1 个月前
【Godot】如何导出 Release 版本的安卓项目
android·游戏引擎·godot
CApp1 个月前
GODOT引擎学习日志
学习·游戏引擎·godot
技术小甜甜1 个月前
[Godot][游戏开发] 如何在 Godot 中配置 Android 环境(适配新版 Android Studio)
android·android studio·godot
三巧1 个月前
Godot的RichTextLabel富文本标签,鼠标拖拽滚动,方向键滚动,底部吸附,自动滚动
游戏引擎·godot
夏有凉风,冬有雪1 个月前
AI 制作游戏美术素材流程分享(程序员方向粗糙版)
人工智能·godot·游戏美术