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

Ben*_*bin 3 unity-game-engine

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

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

der*_*ugo 8

是的你可以!

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


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

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

public static List<SceneAsset> Scenes = new List<SceneAsset>();
Run Code Online (Sandbox Code Playgroud)

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

List<EditorBuildSettingsScene> Scenes = EditorBuildSettings.scenes;
Run Code Online (Sandbox Code Playgroud)

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

List<string> scenePaths = Scenes.Select(scene => AssetDatabase.GetAssetPath(scene)).ToList();
Run Code Online (Sandbox Code Playgroud)

为了 EditorBuildSettingsSceneEditorBuildSettings.scenes您也可以简单地使用

List<string> scenePaths = Scenes.Select(scene => scene.path).ToList();
Run Code Online (Sandbox Code Playgroud)

现在您可以遍历它们并使用EditorSceneManager.OpenScene,EditorSceneManager.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();
Run Code Online (Sandbox Code Playgroud)

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

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

比为了最终启动该方法,最简单的方法是添加一个 [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
    }
}
Run Code Online (Sandbox Code Playgroud)

这将向Unity 编辑器的顶部菜单栏添加一个YourMenu带有一个条目的新菜单RunCalculation

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

#if UNITY_EDITOR
    // ... code here
#endif
Run Code Online (Sandbox Code Playgroud)

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


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