Godot学习-对话系统

实现一个简单的对话系统

一、准备

关于剧情游戏,我要实现的功能有1.可交互按钮 2.可切换文本及图片3.打字机效果等
知识点运用:1.字典的运用 2.代码增加信号 3.富文本及TWEEN节点 4.代码创建节点等

二、场景准备

还是先原型图自己简单搭一个,根据这个建场景

三、实现按钮更新文本

首先我们来显示所有的内容,先随便搞个字典来放置对话文本

和之前的一样,先想下,1.需要增加新按钮节点 2.我们需要两个函数来获取按钮及对话框的文本 3.需要调用函数来展示

1.增加新节点

这里需要用到new()函数来创建新的节点* var buttons = Button.new()* 这样我们再将buttons利用add_child()放置到我们的VBoxContainer下就可以了。

2.获取文本函数

文本框的很简单,直接通过@onready来获取文本框节点,再.text = 参数即可,需要注意下按钮文本,因为我们按钮文本也是需要分别出现的,所以也是以字典的形式,因此参数类型为字典,需要使用for循环来遍历,for text in button_group,再将参数赋值给buttons.text即可。

3.展示函数

新建show_line函数,参数为id,id就相当于检索字典内顺序,再通过检索key,就可以获取我们想得到的,例如dialogue[id][“text”]就是对应id的文本,我们再调用函数,进行传参,展示文本

最后利用_ready()函数 输出show_line(0)就可以展示第一个内容了

4.更新文本

展示做好了,就可以继续如何按钮更新文本了,先随便搞点剧情,注意要在按钮字典key后加入想要跳转的文本

我们需要通过代码获取这个你想要跳转的id,通过key可以获取,我们之前的text就是按钮字典中的key,通过button_group[text]就可以获取button_id,随后通过信号连接,当按钮点击时,调用show_line函数,参数为button_id,即可通过索引玩家点击的key到对应的id,由此实现按钮更新文本功能。但是点击会发现原先的按钮还存在,因此我们还需要删除多余的按钮,我们需要遍历button_column的子节点,来删除按钮

5.打字机效果

我们想要文字呈现打字机动画该怎么办?那我们需要使用tween来实现轻量化动画,首先先在节点下创建个tween,*var tween = get_tree().create_tween(),之后我们就可以使用tween下的函数,使用tween_property(object: Object, property: NodePath, final_val: Variant, duration: float)*,这个方法会将 object 对象的 property 属性在初始值和最终值 final_val 之间进行补间,持续时间为 duration 秒,而tabel中的vusible_ratio可以控制显示文字占比来达成打字机效果,我们可以默认设为0,速度我们可以通过文本的长度/固定数值来实现,需要注意的一点是当vusible_ratio值通过tween_property变为1后,之后更新文本也还是1,所以需要再将值变为0,这样就实现了打字机效果。


6.更新texture

通过上面的gif,可以看到我更新了texture,实现的方法其实大同小异,就是通过索引我们字典中的KEY:expression,获得后面的字符串,再通过简单的if函数判断实现更换texture操作,当然不要忘记在show_line中调用。

7.增加退出按钮

我们想实现判断按钮字典中无内容时,出现退出按钮。首先是创建退出按钮,通过Button.new()创建按钮,利用信号,当其被点击时,退出。

之后在show_line中增加判断,当button字典中没有值时,调用增加退出按钮函数

一个简单的对话系统就完成了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
extends PanelContainer
@onready var text_label = $VBoxContainer/HBoxContainer/RichTextLabel
@onready var texture_rect = $VBoxContainer/HBoxContainer/TextureRect
@onready var button_column = $VBoxContainer/VBoxContainer

var dialogue = {
0: {
"text": "昨天的功课复习的怎么样",
"expression": "idle",
"buttons":
{
"压根就没看": 2,
"当然都看了": 1,
}
},
1: {
"text": "很好,那你预习内容了吗",
"expression": "happy",
"buttons":
{
"当然预习了": 3,
"什么预习?": 2,
}
},
2: {
"text": "你忘记了",
"expression": "sad",
"buttons":
{
"不,你再问我遍": 0,
"其实我学习了": 3,
}
},
3: {
"text": "很好!",
"expression": "happy",
"buttons": {}
}
}

func _ready() -> void:
show_line(0)

func show_line(id):
var line_data = dialogue[id]
set_text(line_data["text"])
set_texture(line_data["expression"])
for button in button_column.get_children():
button.queue_free()
if line_data["buttons"]:
add_button(line_data["buttons"])
else:
add_quit_button()

func add_button(button_group):
for text in button_group:
var buttons = Button.new()
button_column.add_child(buttons)
buttons.text = text
var button_id = button_group[text]
buttons.pressed.connect(show_line.bind(button_id))

func add_quit_button():
var quit_button = Button.new()
quit_button.text = "Quit"
button_column.add_child(quit_button)
quit_button.connect("pressed", Callable(get_tree(), "quit"))

func set_text(new_text):
text_label.bbcode_text = new_text
var tween = get_tree().create_tween()
var duration = text_label.text.length() / 60.0
tween.tween_property(text_label,"visible_ratio",1.0,duration)
text_label.visible_ratio = 0.0


func set_texture(new_texture):
if new_texture == "idle":
texture_rect.texture = preload("res://picture/zhangyu_idle.png")
elif new_texture == "happy":
texture_rect.texture = preload("res://picture/zhangyu_happy.png")
elif new_texture == "sad":
texture_rect.texture = preload("res://picture/zhangyu_sad.png")