我能否在Unity编辑器中以编程方式加载场景?

4
我正在使用A*寻路算法制作我的2D游戏(据我所知,Unity Nav Meshes不适用于2D)。 我想能够预先计算所有场景的导航网格,并将它们保存在资源文件中,以便在玩家进入新场景时加载。而不是必须记住为每个场景单独点击“计算”按钮 - 如果我更改了我的导航网格,则必须记住重新计算所有场景 - 我希望能够编程方式让Unity编辑器迭代遍历每个场景并计算网格。
是否有一种方法可以在Unity编辑器中创建一个命令,以便迭代地打开编辑器中的每个场景并在场景中运行MonoBehaviour上的方法?或者,是否有其他方法可以实现我正在尝试完成的任务?

我有点困惑,所以你不想加载场景,而是想通过编程分析其属性? - Sharad Khanna
@Mineo333 是的,我只是想以编程方式分析场景。我提到逐个加载每个场景是因为我认为那是我必须做的,但如果有一种方法可以在不实际加载场景的情况下访问每个场景及其组件,那也行。 - Ben Rubin
这个会在你运行游戏的时候立即完成吗?还是会在整个游戏过程中完成? - Sharad Khanna
@Mineo333 游戏运行时不会完成此操作。在发布游戏之前,我将在Unity编辑器中完成它。 - Ben Rubin
1个回答

11

当然可以!

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


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

例如,可以在检查器中使用包含SceneAsset列表的 public static 字段,其中您只需引用场景即可。

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

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

List<EditorBuildSettingsScene> Scenes = EditorBuildSettings.scenes;

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

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

对于 EditorBuildSettingsScene,你也可以直接使用EditorBuildSettings.scenes

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

现在您可以通过使用 EditorSceneManager.OpenSceneEditorSceneManager.SaveSceneEditorSceneManager.CloseScene(如果需要,还有AssetDatabase.SaveAssets)遍历它们并执行所需操作。请保留HTML标签。
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方法,则必须在运行计算之前从该编辑脚本手动调用它。


1
优秀的回答!感谢您抽出时间将所有内容写下来。 - Ben Rubin
1
不用谢!我在手机上破解了这个,很高兴它对你有用 ;) - derHugo
1
有没有办法只获取项目中的所有场景资源?(不考虑构建设置?) - Adam Keenan
1
@AdamKeenan Resources.FindObjectsOfTypeAll<SceneAsset>() 应该可以解决这个问题。 - derHugo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接