【问题标题】:Godot : How to instantiate a scene from a list of possible scenesGodot:如何从可能的场景列表中实例化一个场景
【发布时间】:2021-07-19 09:03:00
【问题描述】:

我正在尝试创建一个游戏,其中程序生成将类似于以撒的结合:从列表中选择连续的房间。我想我可以将它们链接在一起,但是我有一个问题:如何从列表中选择一个房间? 我的第一个想法是创建包含场景的文件夹,例如

  • zone_1
    • basic_rooms
      • room_1.tscn
      • room_2.tscn
    • special_rooms
      • ...
  • zone_2
    • ...

并从我需要的文件夹中选择一个随机场景,例如,第一个区域中的随机基本房间将是 zone_1/basic_rooms 中的随机场景。

问题是我不知道这是否是一个好的解决方案,因为它会创建很多场景,而且我不知道如何正确地做到这一点。我只是使用包含文件夹路径的字符串,还是有更好的方法?然后我想我得到文件夹中的所有文件,随机选择一个,加载它并实例化它,但同样,我不确定。

我想我的解释有点迷茫,但总而言之,我正在寻找一种从列表中选择房间布局的方法,但不知道该怎么做。

【问题讨论】:

    标签: scene godot gdscript


    【解决方案1】:

    你的建议可行。

    您可以通过这种模式来实例化场景:

    var room_scene = load("res://zone/room_type/room_1.tscn")
    var room_instance = room_scene.instance()
    parent.add_child(room_instance)
    

    我还会提醒你给room_instance一个职位。

    因此,正如您所说,您可以构建传递给 load 的字符串。

    我建议将帽子逻辑放在自动加载中并在需要的地方调用它。


    但是,上面的代码会在加载场景时停止游戏。而是使用ResourceLoader 进行后台加载。

    首先你需要调用load_interactive,它会给你一个ResourceInteractiveLoader对象:

    loader = ResourceLoader.load_interactive(path)
    

    然后你需要在加载器上调用poll。直到它返回ERR_FILE_EOF。在这种情况下,您可以使用get_resource 获取场景:

    if loader.poll() == ERR_FILE_EOF:
        scene = loader.get_resource()
    

    否则,这意味着对poll 的调用不足以完成加载。

    这个想法是将对poll 的调用分散到多个帧中(例如,通过从_process 调用它)。

    您可以拨打get_stage_count 来获取您需要拨打poll 的次数,get_stage 会告诉您到目前为止您已经拨打了多少次。

    因此,您可以使用它们来计算进度:

    var progress = float(loader.get_stage()) / loader.get_stage_count()
    

    这为您提供了从 01 的值。其中0 根本没有加载,而1 已完成。 乘以 100 得到要显示的百分比。您也可以将它用作进度条。


    问题是我不知道这是否是一个好的解决方案,因为它会创建很多场景

    这不是问题。

    我是否只是使用包含文件夹路径的字符串

    是的。

    那我假设我把文件夹里的所有文件都拿到了,随机选择一个

    不一定。

    你可以确保文件夹中的所有场景都具有相同的名称,除了一个数字,那么你只需要知道文件夹中有多少个场景,然后选择一个数字。

    但是,您可能不希望完全随机。根据您生成房间的方法,您可能希望:

    • 根据房间的连接选择房间。以确保它连接到相邻的房间。
    • 衡量一个房间应该有多普通或少见。

    因此,拥有包含该信息的文件(例如 json 或 csv 文件)会很有用。然后,负责加载场景的自动加载代码将该文件加载到数据结构(例如字典或数组)中,从中可以选择要加载的场景,考虑到此处指定的任何权重或约束。


    我会假设您的房间存在于网格上,并且可以有通往 NORTH、SOUTH、EAST、WEST 的门。我还会假设玩家可以回溯,所以布局必须是持久的。

    我不知道你会领先多远。您可以选择一次生成所有地图,或者在玩家尝试进入时生成房间,或者在前面生成几个房间。

    如果您要在玩家尝试进入时生成,您将需要一个房间过渡动画,您可以在其中隐藏场景加载(使用背景加载方法)。

    但是,您不应该生成已经生成的房间。因此,如果已经生成了房间,请保留一个文本网格(一个数组),您可以在其中存储。您将首先检查网格(数组),如果已生成,则无需执行任何操作。但如果没有,那么你需要随机选择一个房间。

    但是等等!例如,如果您从南面进入,您选择的房间必须有南门才能返回。如果您按房间的门来组织房间,那么您可以从有南门的房间中挑选 - 在本例中。

    事实上,您需要考虑您已经生成的任何相邻房间的门。因此,将生成的房间有哪些门存储在网格(数组)中。因此,您可以稍后从阵列中读取新房间需要哪些门。如果没有房间,随意决定是否要在那儿有一扇门。然后从有这些门的系列中随机选择一个房间。

    您的房间组将是 NORTH、SOUTH、EAST、WEST 的组合。生成列表的一种方法是为每个方向赋予 2 的幂。例如:

    • 北 = 1
    • 南 = 2
    • 东 = 4
    • 西 = 8

    然后找出集合,你可以数数,二进制表示给出门。例如 10 = 8 + 2 -> 西和南。

    这些是您的房间组合。重申一下,查看进入您要生成的房间的门已经生成的邻居。如果没有房间,随意决定是否要在那儿有一扇门。这应该会告诉您需要从哪组房间中选择生成。

    这类似于使用自动平铺解决方案的方法。您可能想了解它是如何工作的。


    现在假设集合中的房间有权重(所以有些房间比较常见,有些比较少见),你需要随机挑选。

    这是一般算法:

    1. 对权重求和。
    2. 将权重归一化(将权重除以总和,因此它们加起来为 1)。
    3. 累积归一化权重。
    4. 生成一个从 0 到 1 的随机数,最后累积的大于我们得到的随机数的归一化权重是多少。

    由于您可能会多次从同一个集合中挑选房间,因此您可以计算并存储累积的归一化权重(我们称它们为最终权重),因此您不必每次都计算它们。

    你可以这样计算它们:

        var total_weight:float = 0.0
        for option in options:
            total_weight = total_weight + option.weight
    
        var final_weight:float = 0.0
        var final_weights:Array = []
        for option in options:
            var normalized_weight = option.weight / total_weight
            final_weight = final_weight + normalized_weight
            final_weights.append(final_weight)
    

    然后你可以这样选择:

        var randomic:float = randf()
        for index in final_weights.size():
            if final_weights[index] > randomic:
                return options[index]
    

    一旦您选择了要生成的房间,您就可以加载它(例如使用背景加载方法)、实例化它并将其添加到场景树中。记得在世界上给出一个位置。

    还要记得更新网格(数组)信息。你从一组有特定门的房间中选择了一个房间。您想存储它以考虑生成相邻房间。

    顺便说一句,如果您需要大规模寻路(从一个房间到另一个房间),您也可以使用该网格。

    【讨论】:

      猜你喜欢
      • 2020-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多