Godot : 如何从可能的场景列表中实例化一个场景

如何解决Godot : 如何从可能的场景列表中实例化一个场景

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

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

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

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

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

解决方法

你的建议会奏效。

你可以通过这个模式来实例化场景:

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 文件)会很有用。然后,负责加载场景的自动加载代码会将该文件加载到数据结构(例如字典或数组)中,从那里它可以选择要加载的场景,并考虑其中指定的任何权重或约束。


我假设您的房间存在于网格中,并且可以为北、南、东、西设置门。我也会假设玩家可以回溯,所以布局必须是持久的。

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

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

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

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

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

您的房间组将是北、南、东、西的组合。生成列表的一种方法是给每个方向一个 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]

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-