【问题标题】:Can I programatically load scenes in the Unity editor?我可以在 Unity 编辑器中以编程方式加载场景吗?
【发布时间】:2019-01-31 02:11:48
【问题描述】:

我正在为我的 2D 游戏使用 A* 寻路算法(据我了解,Unity Nav Meshes 在 2D 中不起作用)。我希望能够为我的所有场景预先计算导航网格,并将它们保存在资源文件中,当玩家进入新场景时可以加载这些文件。而不是必须记住为每个场景单击“计算”——如果我对导航网格进行更改,记得重新计算我的所有场景——我希望能够以编程方式让 Unity 编辑器迭代每个场景和计算网格。

有没有办法在 Unity 编辑器中创建一个命令,该命令将在编辑器中迭代地打开每个场景并在场景中的 MonoBehaviour 上运行一个方法?或者,还有其他方法可以完成我想要做的事情吗?

【问题讨论】:

  • 我很困惑,所以你不想加载场景。您只想以编程方式分析其属性吗?
  • @Mineo333 是的,我只想以编程方式分析场景。我提到迭代地加载每个场景是因为我认为这是我必须做的,但如果有一种方法可以访问每个场景及其组件而无需实际加载场景,那么它也可以工作。
  • 那么这会在您运行游戏后立即完成吗?还是会在整个游戏过程中完成?
  • @Mineo333 游戏运行时不会这样做。这将由我在发布游戏之前在 Unity 编辑器中完成。

标签: unity3d


【解决方案1】:

是的,你可以!

在编辑模式下,您不能使用SceneManager,但必须使用EditorSceneManager


首先,您需要要迭代的场景。

例如可以是public static 字段,在 Inspector 中包含 SceneAsset 列表,您只需在其中引用场景

public static List<SceneAsset> Scenes = new List<SceneAsset>();

或者您可以通过脚本获取它们,例如仅使用使用EditorBuildSettings.scenes添加到构建设置中的场景

List<EditorBuildSettingsScene> Scenes = EditorBuildSettings.scenes;

对于两者,您都可以获得场景路径列表,例如使用LinQ Select(这基本上是foreach循环的一种快捷方式)和AssetDatabase.GetAssetPath like

List<string> scenePaths = Scenes.Select(scene => AssetDatabase.GetAssetPath(scene)).ToList();

对于来自EditorBuildSettings.scenesEditorBuildSettingsScene,您也可以简单地使用

List<string> scenePaths = Scenes.Select(scene => scene.path).ToList();

现在您可以使用EditorSceneManager.OpenSceneEditorSceneManager.SaveSceneEditorSceneManager.CloseScene(如果您需要AssetDatabase.SaveAssets)来遍历它们并完成您的工作

foreach(string scenePath in scenePaths)
{
    // Open a scene e.g. in single mode
    var currentScene = EditorSceneManager.OpenScene(scenePath);

    /* Do your calculation for currentScene */

    // Don't know if it makes changes to your scenes .. if not you can probably skip this
    EditorSceneManager.SaveScene(currentScene);

    // Finally Close and remove the scene
    EditorSceneManager.CloseScene(currentScene, true);
}

// you might be doing changes to an asset you want to save when done
AssetDatabase.SaveAssets();

在开始之前,您可能应该要求使用 EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo 保存当前打开的场景

if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
    // Saved => the foreach loop here
}
else
{
    // aborted => do nothing
}

为了最终启动该方法,最简单的方法是添加[MenuItem]

public static class Calculation
{
    [MenuItem("YourMenu/RunCalculation")]
    public static void RunCalculation()
    {
        // all the before mentioned snippets here
        // depending how exactly you want to do it
    }
}

这将在 Unity 编辑器的顶部菜单栏中添加一个新菜单 YourMenu,其中包含一个条目 RunCalculation

注意:
由于这使用了许多仅存在于 UnityEditor 命名空间中的类型(EditorSceneManager 等),您应该将整个脚本放在 Editor 文件夹中(因此在最终构建中将被忽略)或使用预处理器喜欢

#if UNITY_EDITOR
    // ... code here
#endif

所以在构建中代码也被忽略了。


请注意,到目前为止,我假设您还在编辑模式下进行了计算。问题是,如果此计算依赖于任何 StartAwake 方法,则必须在运行计算之前从该编辑器脚本手动调用它。

【讨论】:

  • 优秀的答案!感谢您花时间写出所有这些内容。
  • 不客气!我在我的手机上破解了这个,所以我很高兴它对你有用;)
  • 有什么方法可以获取项目中的所有场景资源? (无论构建设置如何?)
  • @AdamKeenan Resources.FindObjectsOfTypeAll&lt;SceneAsset&gt;() 应该做到这一点。
猜你喜欢
  • 2017-10-23
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-26
  • 2015-05-16
  • 1970-01-01
相关资源
最近更新 更多