Reputation: 7341
I'm using the A* pathfinding algorithm for my 2D game (from my understanding, Unity Nav Meshes don't work in 2D). I would like to be able to pre-calculate navigation grids for all of my scenes, and save them in resource files that can be loaded whenever the player enters a new scene. Rather than having to remember to click "calculate" for every scene -- and remember to recalculate all of my scenes if I make a change to my navigation grids -- I want to be able to programatically have the Unity Editor iterate though each scene and calculate the grids.
Is there a way to create a command in the Unity editor that will iteratively open each scene in the editor and run a method on a MonoBehaviour
that's in the scene? Alternatively, is there another way to accomplish what I'm trying to do?
Upvotes: 4
Views: 6665
Reputation: 90779
Yes you can!
In editmode you can't use SceneManager
but have to use the EditorSceneManager
.
First of all you need the scenes you want to iterate.
Could be e.g. a public static
field with a list of SceneAsset
in the Inspector where you simply reference the scenes
public static List<SceneAsset> Scenes = new List<SceneAsset>();
or you could get them by script e.g. for only use the scenes added to the build settings using EditorBuildSettings.scenes
List<EditorBuildSettingsScene> Scenes = EditorBuildSettings.scenes;
For both you can get a list of the scene paths e.g. using LinQ Select
(this is basically a kind of shortcut for a foreach
loop) and AssetDatabase.GetAssetPath
like
List<string> scenePaths = Scenes.Select(scene => AssetDatabase.GetAssetPath(scene)).ToList();
for the EditorBuildSettingsScene from EditorBuildSettings.scenes
you can also simply use
List<string> scenePaths = Scenes.Select(scene => scene.path).ToList();
Now you can iterate over them all and do your stuff by using EditorSceneManager.OpenScene
, EditorSceneManager.SaveScene
and EditorSceneManager.CloseScene
(and if you need it 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();
Before starting you should probably ask to save the current open scene(s) using EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
// Saved => the foreach loop here
}
else
{
// aborted => do nothing
}
Than in order to finally start that method the simplest would be to add a [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
}
}
This will add a new menu YourMenu
with one entry RunCalculation
to the top menubar of the Unity Editor.
Note:
Since this uses a lot of types (EditorSceneManager
etc) that only exist in the UnityEditor
namespace you should either place the whole script in an Editor
folder (so it is ignored in the final build) or use pre-processors like
#if UNITY_EDITOR
// ... code here
#endif
so in the build the code is also ignored.
Note that I'm assuming so far you also did your calculation in editmode. The thing is if this calculation relies somewhere aon any Start
or Awake
method you have to call it manually from that editorscript before running the calculation.
Upvotes: 11