Last active
October 7, 2020 09:49
-
-
Save nir1082/583dd104199256a67593c7a01b17d180 to your computer and use it in GitHub Desktop.
[Unity] シーンのロードとかActive化とかやりやすくするEditorWindow。マルチシーン対応 (Unity2018.2.14)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.IO; | |
using UnityEditor; | |
using UnityEditor.SceneManagement; | |
using UnityEditorInternal; | |
using UnityEngine; | |
using Scene = UnityEngine.SceneManagement.Scene; | |
namespace NIR1082 | |
{ | |
public class MultiSceneWindow : EditorWindow | |
{ | |
private enum ViewType | |
{ | |
Control, | |
Manage, | |
} | |
[MenuItem ("Tools/MultiScene")] | |
public static void ShowWindow() | |
{ | |
MultiSceneWindow window = GetWindow<MultiSceneWindow> (false); | |
window.minSize = new Vector2 (200.0f, 120.0f); | |
window.Show(); | |
} | |
private Vector2 controlScrollPosition1, controlScrollPosition2; | |
private Vector2 manageScrollPosition; | |
private ViewType viewType = ViewType.Control; | |
private SerializedObject serializedObject; | |
private SerializedProperty propManagedSceneAssets; | |
private SerializedProperty propIsFixOpenedScenes; | |
private SerializedProperty propIsSingleMode; | |
private ReorderableList reorderableManagedSceneAssets; | |
[SerializeField] private bool isFixOpenedScenes; | |
[SerializeField] private bool isSingleMode; | |
[SerializeField] SceneAsset[] managedSceneAssets = new SceneAsset[0]; | |
#region OnGUI | |
private void OnGUI() | |
{ | |
ShowViewTypeTabOnGUI(); | |
switch (viewType) | |
{ | |
case ViewType.Control: | |
ShowControlViewOnGUI(); | |
break; | |
case ViewType.Manage: | |
ShowManageViewOnGUI(); | |
break; | |
} | |
} | |
/// <summary> | |
/// 表示タイプを切り替えるタブの表示 | |
/// </summary> | |
private void ShowViewTypeTabOnGUI() | |
{ | |
using (new EditorGUILayout.HorizontalScope()) | |
{ | |
string[] names = Enum.GetNames (typeof (ViewType)); | |
viewType = (ViewType) GUILayout.Toolbar ( (int) viewType, names); | |
} | |
} | |
/// <summary> | |
/// タブ:Control | |
/// 各シーンのコントロールを一覧表示 | |
/// </summary> | |
private void ShowControlViewOnGUI() | |
{ | |
using (var scrollViewScope = new EditorGUILayout.ScrollViewScope (controlScrollPosition1)) | |
{ | |
controlScrollPosition1 = scrollViewScope.scrollPosition; | |
using (new EditorGUI.DisabledGroupScope (EditorApplication.isPlayingOrWillChangePlaymode)) | |
{ | |
ShowManagedScenes(); | |
} | |
} | |
if (isFixOpenedScenes) | |
{ | |
GUILayout.Box (string.Empty, GUILayout.ExpandWidth (true), GUILayout.Height (1)); | |
using (var scrollViewScope = new EditorGUILayout.ScrollViewScope (controlScrollPosition2)) | |
{ | |
controlScrollPosition2 = scrollViewScope.scrollPosition; | |
using (new EditorGUI.DisabledGroupScope (EditorApplication.isPlayingOrWillChangePlaymode)) | |
{ | |
ShowOpenedScenes(); | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// 管理内のシーンの表示 | |
/// </summary> | |
private void ShowManagedScenes() | |
{ | |
for (var i = 0; i < managedSceneAssets.Length; i++) | |
{ | |
SceneAsset sceneAsset = managedSceneAssets[i]; | |
if (sceneAsset == null) | |
{ | |
continue; | |
} | |
Scene scene = EditorSceneManager.GetSceneByPath (AssetDatabase.GetAssetPath (sceneAsset)); | |
ShowSceneControl (sceneAsset, scene, sceneAsset.name); | |
} | |
} | |
/// <summary> | |
/// 開かれているシーンを固定位置に表示する | |
/// </summary> | |
private void ShowOpenedScenes() | |
{ | |
for (var i = 0; i < EditorSceneManager.sceneCount; i++) | |
{ | |
Scene scene = EditorSceneManager.GetSceneAt (i); | |
if (IsManagedScene (scene)) | |
{ | |
ShowSceneControl (null, scene, scene.name); | |
} | |
else | |
{ | |
Color color = GUI.contentColor; | |
GUI.contentColor = Color.red; | |
ShowSceneControl (null, scene, scene.name); | |
GUI.contentColor = color; | |
} | |
} | |
} | |
/// <summary> | |
/// シーンの Open/Close、Loaded/NotLoaded、Active/非Active の各トグルの表示 | |
/// </summary> | |
private void ShowSceneControl (SceneAsset sceneAsset, Scene scene, string label) | |
{ | |
bool isActiveSceneAsset = IsActiveScene (scene); | |
bool isLoadedSceneAsset = scene.isLoaded; | |
bool isOpenedSceneAsset = sceneAsset == null || IsOpenedSceneAsset (sceneAsset); | |
using (new EditorGUILayout.HorizontalScope (GUILayout.Width (position.width - 24))) | |
{ | |
string sceneName = !string.IsNullOrEmpty (label) ? label : "Untitled"; | |
string scenePath = sceneAsset != null ? AssetDatabase.GetAssetPath (sceneAsset) : scene.path; | |
EditorGUILayout.LabelField (sceneName, GetSceneNameLabelStyle (sceneAsset, scene), GUILayout.Width (150.0f)); | |
using (new EditorGUI.DisabledGroupScope (isSingleMode)) | |
{ | |
isOpenedSceneAsset = ShowOpenedToggle (scenePath, isOpenedSceneAsset); | |
using (new EditorGUI.DisabledScope (string.IsNullOrEmpty (scenePath))) // 保存されていないシーンの Loaded/NotLoaded トグルは操作できない (操作したらバグる) | |
{ | |
isLoadedSceneAsset = ShowLoadedToggle (scenePath, isLoadedSceneAsset); | |
} | |
} | |
ShowIsActiveToggle (scenePath, isOpenedSceneAsset, isLoadedSceneAsset, isActiveSceneAsset); | |
} | |
} | |
/// <summary> | |
/// シーンのOpen/Close切り替えトグルの表示 | |
/// 切り替わったらシーンのOpen/Close処理を呼ぶ | |
/// </summary> | |
/// <returns> | |
/// return:処理後のシーンのOpen/Close状態 | |
/// </returns> | |
private bool ShowOpenedToggle (string scenePath, bool isOpenedSceneAsset) | |
{ | |
if (isOpenedSceneAsset != EditorGUILayout.Toggle (isOpenedSceneAsset)) | |
{ | |
isOpenedSceneAsset = !isOpenedSceneAsset; | |
if (isOpenedSceneAsset) | |
{ | |
OpenScene (scenePath, true); | |
} | |
else | |
{ | |
CloseScene (EditorSceneManager.GetSceneByPath (scenePath), true); | |
} | |
} | |
return isOpenedSceneAsset; | |
} | |
/// <summary> | |
/// シーンのLoaded/NotLoaded切り替えトグルの表示 | |
/// 切り替わったらシーンのロード/アンロード処理を呼ぶ | |
/// </summary> | |
/// <returns> | |
/// return:処理後のシーンのロード/未ロード状態 | |
/// </returns> | |
private bool ShowLoadedToggle (string scenePath, bool isLoadedSceneAsset) | |
{ | |
if (isLoadedSceneAsset != EditorGUILayout.Toggle (isLoadedSceneAsset)) | |
{ | |
isLoadedSceneAsset = !isLoadedSceneAsset; | |
if (isLoadedSceneAsset) | |
{ | |
OpenScene (scenePath, true); | |
} | |
else | |
{ | |
CloseScene (EditorSceneManager.GetSceneByPath (scenePath), false); | |
} | |
} | |
return isLoadedSceneAsset; | |
} | |
/// <summary> | |
/// シーンのアクティブ化トグルの表示 | |
/// 切り替わったらシーンのアクティブ化処理を呼ぶ | |
/// もしアクティブ化しようとしたシーンが開かれていない場合、開いてからアクティブ化処理 | |
/// もしアクティブ化しようとしたシーンがロードされていない場合、ロードしてからアクティブ化処理 | |
/// </summary> | |
private void ShowIsActiveToggle (string scenePath, bool isOpenedSceneAsset, bool isLoadedSceneAsset, bool isActiveSceneAsset) | |
{ | |
using (new EditorGUI.DisabledGroupScope (isActiveSceneAsset)) // すでにアクティブなら操作できないようにする | |
{ | |
if (isActiveSceneAsset != EditorGUILayout.Toggle (isActiveSceneAsset)) | |
{ | |
if (!isOpenedSceneAsset || !isLoadedSceneAsset) | |
{ | |
OpenScene (scenePath, true); | |
} | |
SetActiveScene (EditorSceneManager.GetSceneByPath (scenePath)); | |
} | |
} | |
} | |
/// <summary> | |
/// タブ:Manage | |
/// Controlで表示するシーンの管理 | |
/// </summary> | |
private void ShowManageViewOnGUI() | |
{ | |
using (var scrollViewScope = new EditorGUILayout.ScrollViewScope (manageScrollPosition)) | |
{ | |
manageScrollPosition = scrollViewScope.scrollPosition; | |
using (new EditorGUI.DisabledGroupScope (EditorApplication.isPlayingOrWillChangePlaymode)) | |
{ | |
reorderableManagedSceneAssets.DoLayoutList(); | |
serializedObject.ApplyModifiedProperties(); | |
ShowFixOpenedScenesToggle (); | |
ShowSingleModeToggle (); | |
} | |
} | |
} | |
/// <summary> | |
/// 開かれているシーンを固定位置に表示するかどうかのトグルの表示 | |
/// </summary> | |
private void ShowFixOpenedScenesToggle () | |
{ | |
if (isFixOpenedScenes != (isFixOpenedScenes = EditorGUILayout.ToggleLeft ("Show Opened Scenes", isFixOpenedScenes))) | |
{ | |
propIsFixOpenedScenes.boolValue = isFixOpenedScenes; | |
serializedObject.ApplyModifiedProperties (); | |
} | |
} | |
/// <summary> | |
/// 単シーンのみのモードにするかどうかのトグル表示 | |
/// </summary> | |
private void ShowSingleModeToggle () | |
{ | |
if (isSingleMode != (isSingleMode = EditorGUILayout.ToggleLeft ("Single Mode", isSingleMode))) | |
{ | |
propIsSingleMode.boolValue = isSingleMode; | |
serializedObject.ApplyModifiedProperties (); | |
} | |
} | |
#endregion | |
/// <summary> | |
/// シーンを開く | |
/// </summary> | |
/// <param name="withLoad"> | |
/// falseなら、シーンを未ロード状態で開く | |
/// </param> | |
private void OpenScene (string scenePath, bool withLoad) | |
{ | |
if (!isSingleMode || EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) | |
{ | |
OpenSceneMode openSceneMode = isSingleMode ? OpenSceneMode.Single | |
: withLoad ? OpenSceneMode.Additive : OpenSceneMode.AdditiveWithoutLoading; | |
EditorSceneManager.OpenScene (scenePath, openSceneMode); | |
} | |
} | |
/// <summary> | |
/// シーンを閉じる | |
/// </summary> | |
/// <param name="withRemove"> | |
/// falseなら、シーンを閉じた後も未ロード状態で残す | |
/// </param> | |
private void CloseScene (Scene scene, bool withRemove) | |
{ | |
if (!scene.isDirty || EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) | |
{ | |
EditorSceneManager.CloseScene (scene, withRemove); | |
} | |
} | |
/// <summary> | |
/// シーンのアクティブ化 | |
/// </summary> | |
private void SetActiveScene (Scene scene) | |
{ | |
EditorSceneManager.SetActiveScene (scene); | |
} | |
/// <summary> | |
/// シーンが開いているかどうか | |
/// </summary> | |
private bool IsOpenedSceneAsset (SceneAsset sceneAsset) | |
{ | |
string sceneAssetPath = AssetDatabase.GetAssetPath (sceneAsset); | |
for (int i = 0; i < EditorSceneManager.sceneCount; i++) | |
{ | |
Scene tmpScene = EditorSceneManager.GetSceneAt (i); | |
if (sceneAssetPath.Equals (tmpScene.path)) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
/// <summary> | |
/// シーンがアクティブかどうか | |
/// </summary> | |
private bool IsActiveScene (Scene scene) | |
{ | |
return EditorSceneManager.GetActiveScene() == scene; | |
} | |
/// <summary> | |
/// 管理内のシーンかどうか | |
/// </summary> | |
private bool IsManagedScene (Scene scene) | |
{ | |
if (string.IsNullOrEmpty (scene.path)) | |
{ | |
return false; | |
} | |
for (var i = 0; i < managedSceneAssets.Length; i++) | |
{ | |
if (AssetDatabase.GetAssetPath (managedSceneAssets[i]) == scene.path) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
private GUIStyle GetSceneNameLabelStyle (SceneAsset sceneAsset, Scene scene) | |
{ | |
return (sceneAsset != null || IsManagedScene (scene)) ? EditorStyles.label : EditorStyles.boldLabel; | |
} | |
#region Save Data | |
private readonly string SaveJsonFilePath = "Library/MultiSceneWindow.json"; | |
private void SaveToJson() | |
{ | |
File.WriteAllText (SaveJsonFilePath, EditorJsonUtility.ToJson (this)); | |
} | |
private void LoadFromJson() | |
{ | |
if (File.Exists (SaveJsonFilePath)) | |
{ | |
EditorJsonUtility.FromJsonOverwrite (File.ReadAllText (SaveJsonFilePath), this); | |
} | |
} | |
#endregion | |
private void OnEnable() | |
{ | |
LoadFromJson(); | |
serializedObject = new SerializedObject (this); | |
propManagedSceneAssets = serializedObject.FindProperty ("managedSceneAssets"); | |
reorderableManagedSceneAssets = new ReorderableList (serializedObject, propManagedSceneAssets); | |
reorderableManagedSceneAssets.drawHeaderCallback += rect => EditorGUI.LabelField (rect, "Managed Scenes"); | |
reorderableManagedSceneAssets.drawElementCallback = (rect, index, _, __) => | |
{ | |
var element = propManagedSceneAssets.GetArrayElementAtIndex (index); | |
rect.height -= 4; | |
rect.y += 2; | |
EditorGUI.PropertyField (rect, element); | |
}; | |
propIsFixOpenedScenes = serializedObject.FindProperty ("isFixOpenedScenes"); | |
propIsSingleMode = serializedObject.FindProperty ("isSingleMode"); | |
} | |
private void OnDisable() | |
{ | |
SaveToJson(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment