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"
    ]
]

然后您将获得Arrays 中的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 对象并将其保存到表中

如何在 Node JS 中读取文本文件并将其作为 JSON 对象返回?

Linux tee命令作用是啥?