幸运的是,Unity中的多场景编辑允许以当前的分层状态启动(通过编辑器播放模式)当前场景。
但是,构建和运行项目无法在编辑器中识别当前场景设置,而是从“构建设置”中设置的内容开始。
是否可以通过某种方式使构建版本了解多场景编辑层次结构的当前编辑器状态,并构建并运行该设置?
答案 0 :(得分:5)
首先收集设置,您可以使用
使用编辑器脚本loaded
个场景,所以请列出isLoaded = true的仅场景列表我在菜单中将其设置为额外的按钮,因为您可能不希望总是自动拥有它。
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
public static class UpdateBuildSettigns
{
[MenuItem("Example/UpdateBuildSettings")]
public static void UpdateSettings()
{
// get current editor setup
SceneSetup[] editorScenes = EditorSceneManager.GetSceneManagerSetup();
// filter list e.g. get only scenes with isActive true
var activeEditorScenes = editorScenes.Where(scene => scene.isLoaded);
// set those scenes as the buildsettings
List<EditorBuildSettingsScene> editorBuildSettingsScenes = new List<EditorBuildSettingsScene>();
foreach (var sceneAsset in activeEditorScenes)
{
string scenePath = sceneAsset.path;
// ignore unsaved scenes
if (!string.IsNullOrEmpty(scenePath)) continue;
editorBuildSettingsScenes.Add(new EditorBuildSettingsScene(scenePath, true));
}
// Set the Build Settings window Scene list
EditorBuildSettings.scenes = editorBuildSettingsScenes.ToArray();
}
}
更新菜单按钮
如果您希望它自动发生,您还可以使用EditorSceneManager.sceneOpened和静态构造函数将调用作为回调添加到EditorSceneManager.sceneClosed和InitializeOnLoad中,以在重新编译或打开UnityEditor后获得添加的回调喜欢
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
[InitializeOnLoad]
public static class UpdateBuildSettigns
{
// ofcourse you still can also call it via menu item
[MenuItem("Example/UpdateBuildSettings")]
public static void UpdateSettings()
{
//...
}
static UpdateBuildSettigns()
{
// it is always save to remove callbacks even if they are not there
// makes sure they are allways only added once
//
// this is a static constructor so actually there should be no
// callbacks yet ... but .. you never know ;)
EditorSceneManager.sceneOpened -= OnSceneLoaded;
EditorSceneManager.sceneClosed -= OnSceneUnloaded;
EditorSceneManager.sceneOpened += OnSceneLoaded;
EditorSceneManager.sceneClosed += OnSceneUnloaded;
}
private static void OnSceneUnloaded(Scene current)
{
UpdateSettings();
}
private static void OnSceneLoaded(Scene current, OpenSceneMode mode)
{
UpdateSettings();
}
}
使用自动更新
如果您希望获得更多控制,还可以添加其他菜单项以启用和禁用自动更新,例如
// flag to check if auto-updates are currently enabled
private static bool isEnabled;
// disable the "EnableAutoUpdate" button if already enabled
[MenuItem("Example/EnableAutoUpdate", true)]
private static bool CanEnable()
{
return !isEnabled;
}
// disable the "DisableAutoUpdate" button if already disabled
[MenuItem("Example/DisableAutoUpdate", true)]
private static bool CanDisable()
{
return isEnabled;
}
// add callbacks
[MenuItem("Example/EnableAutoUpdate")]
private static void EnableAutoUpdate()
{
// it is always save to remove callbacks even if they are not there
// makes sure they are allways only added once
EditorSceneManager.sceneOpened -= OnSceneLoaded;
EditorSceneManager.sceneClosed -= OnSceneUnloaded;
EditorSceneManager.sceneOpened += OnSceneLoaded;
EditorSceneManager.sceneClosed += OnSceneUnloaded;
isEnabled = true;
}
// remove callbacks
[MenuItem("Example/DisableAutoUpdate")]
private static void DisableAutoUpdate()
{
EditorSceneManager.sceneOpened -= OnSceneLoaded;
EditorSceneManager.sceneClosed -= OnSceneUnloaded;
isEnabled = false;
}
请注意,由于此脚本使用UnityEditor
命名空间,因此您应将此脚本放置在Editor
文件夹中,或使用适当的预处理器,例如
#if UNITY_EDITOR
// above code here
#endif
稍后,在第一个场景中运行应用程序时,应该有一个脚本负责加载所有这些场景。像
// making it a component to make sure it is inside of one scene
public class SceneLoader : MonoBehaviour
{
private void Start()
{
var thisScene = SceneManager.GetActiveScene();
// load all scenes
for(int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
{
// skip if is current scene since we don't want it twice
if(thisScene.buildIndex == i) continue;
// Skip if scene is already loaded
if(SceneManager.GetSceneByBuildIndex(i).IsValid()) continue;
SceneManager.LoadScene(i, LoadSceneMode.Additive);
// or depending on your usecase
SceneManager.LoadSceneAsync(i, LoadSceneMode.Additive);
}
}
}
参考:
答案 1 :(得分:4)
我要做的是将某种脚本统一附加到启动场景,然后在游戏开始后触发其余所需场景的加载。这将需要一些摆弄才能正确启动(例如,在尝试加载场景之前检测到尚未加载场景的事实)。
如果需要的话,我可能会用代码片段扩展答案以达到结果。
现在您可以在这里查看文档: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.GetSceneByName.html https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadSceneAsync.html
基本思想是:
如果要在构建时保留当前层次结构(在编辑器中打开的一组场景),则可以通过BuildPipeline实现: https://docs.unity3d.com/Manual/BuildPlayerPipeline.html
有一种方法可以通过程序可访问的场景列表进行构建:
// Get filename.
string path = EditorUtility.SaveFolderPanel("Choose Location of Built Game", "", "");
string[] levels = new string[] {"Assets/Scene1.unity", "Assets/Scene2.unity"}; // You'd have to assemble this list yourself.
// Build player.
BuildPipeline.BuildPlayer(levels, path + "/BuiltGame.exe", BuildTarget.StandaloneWindows, BuildOptions.None);
(您可以在运行构建时根据当前加载的场景来确定)。虽然这不是标准的(Cmd + b)构建,但非常接近。