Godot:根据输入读取JSON文件并将其输出为Textbook
Posted
技术标签:
【中文标题】Godot:根据输入读取JSON文件并将其输出为Textbook【英文标题】:Godot: read and output JSON file as Textbook according to the input 【发布时间】:2022-01-21 12:13:45 【问题描述】:我希望能够通过在这个 JSON 文件中分配的数字来调用特定的短语,所以例如当我调用 go(1) 时,它只显示将“Num”设置为 1 的文本。
我的 JSON 文件:
[
"Num":0, "Name":"Afely", "Emotion":"Neutral", "Text":"TEST1",
"Num":0, "Name":"Afely", "Emotion":"Neutral", "Text":"TEST2",
"Num":0, "Name":"Afely", "Emotion":"Neutral", "Text":"TEST3",
"Num":1, "Name":"Afely", "Emotion":"Neutral", "Text":"2TEST1"
]
文本框代码:
extends ColorRect
export var dialogPath = ""
export(float) var textSpeed = 0.005
var dialog
var phraseNum = 0
var finished = false
func go(phraseNum):
$Timer.wait_time = textSpeed
dialog = getDialog()
assert(dialog, "Dialog not found")
nextPhrase()
var f = File.new()
var img = dialog[phraseNum]["Emotion"] + ".png"
$Portrait.texture = load(img)
func _unhandled_input(event):
if event is InputEventKey:
if event.pressed and event.scancode == KEY_Q:
if finished:
$NEXT.play()
nextPhrase()
else:
$Text.visible_characters = len($Text.text)
func getDialog() -> Array:
var f = File.new()
assert(f.file_exists(dialogPath), "File path does not exist")
f.open(dialogPath, File.READ)
var json = f.get_as_text()
var output = parse_json(json)
if typeof(output) == TYPE_ARRAY:
return output
else:
return []
func nextPhrase() -> void:
if phraseNum >= len(dialog):
queue_free()
return
finished = false
$Name.bbcode_text = dialog[phraseNum]["Name"]
$Text.bbcode_text = dialog[phraseNum]["Text"]
$Text.visible_characters = 0
while $Text.visible_characters < len($Text.text):
$Text.visible_characters += 1
$TEXT_AUDIO.play()
$Timer.start()
yield($Timer, "timeout")
finished = true
phraseNum += 1
return
我怎么称呼它:
$TextBox.show()
$TextBox.go(1)
最后,我遵循的教程: https://www.youtube.com/watch?v=GzPvN5wsp7Y
我将如何做到这一点?
【问题讨论】:
【参考方案1】:你问了什么
您的要求需要相当多的额外工作。让我们从 JSON 文件开始:
[
"Num":0, "Name":"Afely", "Emotion":"Neutral", "Text":"TEST1",
"Num":0, "Name":"Afely", "Emotion":"Neutral", "Text":"TEST2",
"Num":0, "Name":"Afely", "Emotion":"Neutral", "Text":"TEST3",
"Num":1, "Name":"Afely", "Emotion":"Neutral", "Text":"2TEST1"
]
这将解析为Array
([
和]
之间的所有元素),其中每个元素都是Dictionary
( 和
之间的元素)。这意味着您将需要遍历
Array
,检查每个Num
。
在我们这样做之前,我们需要确认我们将使用名称 phraseNum
来表示两件事:
dialog
中的索引Array
Num
的期望值
由于您使用的源材料,我们处于这种情况。他们将 phraseNum
作为参数(此处:func go(phraseNum)
)隐藏了 phraseNum
字段(此处为 var phraseNum = 0
)。
这会阻碍沟通。如果我告诉你用phraseNum
做这个,它是哪一个?这势必给我们带来麻烦。
我将重写go
,所以它需要一个Num
而不是dialog
中的索引Array
,所以我将保留phraseNum
作为dialog
中的索引Array
, 并为 go
的参数使用不同的名称。
让我们开始重写go
:
func go(num):
pass
现在,让我们得到所有的对话:
func go(num):
dialog = getDialog()
我们将迭代它们。因为我想要phraseNum
的索引,所以我将使用索引进行迭代:
func go(num):
dialog = getDialog()
for index in dialog.size():
pass
我们需要检查Num
是否匹配。如果是这样,我们得到了我们的索引:
func go(num):
dialog = getDialog()
for index in dialog.size():
if num == dialog[index]["Num"]:
phraseNum = index
break
我们需要处理我们没有找到它的情况。现在,嗯……源材料只有一个assert
,我会保持这种方法。所以我们需要一种方法来知道代码没有找到它……
func go(num):
var found := false
dialog = getDialog()
for index in dialog.size():
if num == dialog[index]["Num"]:
phraseNum = index
found = true
break
assert(found, "Dialog not found")
接下来你打电话给nextPhrase()
,当然:
func go(num):
var found := false
dialog = getDialog()
for index in dialog.size():
if num == dialog[index]["Num"]:
phraseNum = index
found = true
break
assert(found, "Dialog not found")
nextPhrase()
还有一个没用过的var f = File.new()
,我就不加了。
然后你设置了肖像纹理。当然:
func go(num):
var found := false
dialog = getDialog()
for index in dialog.size():
if num == dialog[index]["Num"]:
phraseNum = index
found = true
break
assert(found, "Dialog not found")
nextPhrase()
var img = dialog[phraseNum]["Emotion"] + ".png"
$Portrait.texture = load(img)
我已经跳过了计时器的事情,我现在将其插入:
func go(num):
var found := false
dialog = getDialog()
for index in dialog.size():
if num == dialog[index]["Num"]:
phraseNum = index
found = true
break
assert(found, "Dialog not found")
$Timer.wait_time = textSpeed
nextPhrase()
var img = dialog[phraseNum]["Emotion"] + ".png"
$Portrait.texture = load(img)
别的东西
现在,您说您想要只具有给定Num
的短语。这可以解释。
为了清楚起见,上面的代码将使对话框从您要求的Num
的第一个实例开始。但它不会结束 - 也不会跳过 - 当它找到不同的 Num
时。不知道你愿不愿意。
我们有几种方法可以做到这一点。我们可以记住num
是什么,并在nextPhrase
中检查它。我真的不想那样做。所以,我会给你一个替代方法:让我们创建一个对话框数组,只包含我们想要的元素。
看起来像这样:
func go(num):
var every_dialog = getDialog()
dialog = []
for candidate in every_dialog:
if num == candidate["Num"]:
dialog.append(candidate)
assert(dialog, "Dialog not found")
phraseNum = 0
$Timer.wait_time = textSpeed
nextPhrase()
var img = dialog[phraseNum]["Emotion"] + ".png"
$Portrait.texture = load(img)
请注意,在此示例中,我们不是将getDialog()
读取为dialog
。相反,我们正在构建一个仅包含我们想要的条目的 dialog
数组。我们通过迭代getDialog()
的结果来做到这一点(我们用append
添加到数组中)。
这是dialog
含义的细微变化,因为它不再代表 JSON 文件中的每个条目。相反,它仅代表将要显示的条目。之前这两个东西是一样的,但是这次改变它们已经不一样了。
你没有问什么
函数 getDialog
从 JSON 文件中读取。每次拨打go
时,您都会这样做。您可以改为在_ready
中执行一次。
了解每个变量所代表的含义以及读取和写入它们的位置非常重要。 上面我提到dialog
对替代更改有一个微妙的含义。您需要考虑到这一点才能进行此更改。
我坚信nextPhrase
应该处理计时器和肖像。应该不需要从go
设置那些。
我希望您考虑这种替代 JSON 文件结构:
[
[
"Name":"Afely", "Emotion":"Neutral", "Text":"TEST1",
"Name":"Afely", "Emotion":"Neutral", "Text":"TEST2",
"Name":"Afely", "Emotion":"Neutral", "Text":"TEST3",
],
[
"Name":"Afely", "Emotion":"Neutral", "Text":"2TEST1"
]
]
然后您将获得Array
s 中的Array
,其中嵌套Array
的每个元素都是Dictionary
。然后,您可以“简单”地通过索引获取嵌套数组,而不必遍历每个元素。
您获得的结构类似于 JSON 文件的结构。这也意味着你将不得不改变你使用它的方式。例如,可以用dialog[num][phraseNum]["Text"]
代替dialog[phraseNum]["Text"]
。
现在考虑源材料。在这种情况下,我们有一个节点,它既负责解析 JSON,又负责显示角色对话。如果这些代码彼此分开,则修改此代码会更容易。想必作者的意图是不同的对话会有不同的 JSON 文件,所以在必要的时候切换 JSON 文件(这也解释了他们为什么每次都读取 JSON 文件)。
但这不是你问的。
【讨论】:
事实证明这非常有帮助并解决了我想做的事情。我也很欣赏深入的解释!它帮助我更好地了解我正在使用什么。谢谢!以上是关于Godot:根据输入读取JSON文件并将其输出为Textbook的主要内容,如果未能解决你的问题,请参考以下文章
Nodejs Parse Json 文件将输入转换为 JSON 数组写入文件
从 Linux shell 读取输出并将其存储到 JSON 对象
sh 将stdin转换为其他语言并将其保存为输出路径为.json文件
如何从单个文件中读取不同的模式 json 对象并将其保存到表中