自动加载与常规节点
Godot提供了一个在项目根节点自动加载节点的功能, 允许你在全局范围内访问它们, 从而完成单例作用 单例(自动加载). 当您使用 SceneTree.change_scene 从代码中更改场景时, 这些自动加载的节点不会被释放.
在本指南中, 您将学习到何时使用自动加载功能, 以及避免使用该功能的方法.
切割音频问题
其他引擎可能鼓励使用创建管理类, 单例将很多功能组织到一个全局可访问的对象中. 由于节点树和信号,Godot提供了许多避免全局状态的方法.
例如, 假设我们正在构建一个平台游戏, 并希望收集能够播放声音效果的硬币, 那么就有一个节点 AudioStreamPlayer. 如果在 AudioStreamPlayer
已经在播放声音时调用它, 新的声音就会打断第一个声音.
有一个解决方案是写一个全局的, 自动加载的音效管理器类. 它会生成一个 AudioStreamPlayers
的节点池, 每个播放器随着每个新的音效请求的出现而依次循环播放. 我们不妨就起名该类为 Sound
, 你可以使用 Sound.play("coin_pickup.ogg")
从你的项目的任何位置使用它. 这在短期内解决了问题但是却造成了更多的麻烦:
全局状态 : 一个对象现在负责所有对象的数据. 如果音效有错误, 或没有一个可用的
AudioStreamPlayer
, 一切都会崩溃.全局访问 : 意味着任何对象都可以从任何地方调用
Sound.play(sound_path)
, 便不容易找到错误的来源了.全局资源分配 : 由于从一开始就存储了一个
AudioStreamPlayer
节点池, 如果数量太少会遇到bug, 而数量太多则会占用更多的内存.
备注
关于全局访问, 问题是任何地方的代码都可能将错误的数据传递给我们例子中的 Sound
自动加载. 因此, 为了修复这个bug, 需要检索的区域跨越整个项目.
当您将代码保存在场景中时, 音频可能仅涉及一个或两个脚本.
与之形成对比的是, 每个场景在其内部, 保留尽可能多的 AudioStreamPlayer
节点, 所有这些问题都会消失:
每个场景管理自己的状态信息. 如果数据有问题, 则只会在该场景中引起问题.
每个场景只访问自己的节点. 那么如果有一个bug, 很容易找到哪个节点有问题.
每个场景只分配所需数量的资源.
管理共享功能或数据
使用自动加载的另一个原因可能是您希望在许多场景中重复使用相同的方法或数据.
对于函数,可以使用 GDScript 中的 class_name 关键字创建一种新的 Node
类型,为单个场景提供该功能。
当涉及到数据时, 您可以:
创建一个新类型的 Resource 来共享数据.
将数据存储在每个节点可以访问的对象中, 例如使用
owner
属性来访问场景的根节点.
何时应使用自动加载
在某些情况下, 自动加载节点可以简化您的代码:
静态数据 : 如果你需要某个类专属的数据, 比如数据库, 那么自动加载将是一个很好的工具.Godot中并没有脚本API来创建和管理静态数据.
静态函数 : 创建一个只返回值的函数库.
范围广泛的系统 . 如果单例管理器自己的信息, 而不掺杂其他对象的数据, 那么它是创建处理宽泛任务系统的好办法. 例如, 任务或对话系统.
在Godot 3.1之前, 另一个用途只是为了方便: 自动加载将有一个全局变量, 用于在GDScript中生成它们的名称, 允许你从项目中的任何脚本文件中调用它们. 但现在, 你可以使用 class_name
关键字来代替, 以获得整个项目中一个类型的自动补全.
备注
自动加载不完全是一个单例. 没有什么可以阻止您实例化自动加载的节点的副本. 它只是一个使节点作为场景树的根的子节点自动加载的工具, 而与游戏的节点结构或运行哪个场景无关, 例如通过按 F6 键。
然后, 例如, 你可以通过调用 get_node("/root/Sound")
来获得一个名为 Sound
的自动加载节点.