Skip to content

Instantly share code, notes, and snippets.

@nir1082
Last active October 7, 2020 09:49
Show Gist options
  • Save nir1082/583dd104199256a67593c7a01b17d180 to your computer and use it in GitHub Desktop.
Save nir1082/583dd104199256a67593c7a01b17d180 to your computer and use it in GitHub Desktop.
[Unity] シーンのロードとかActive化とかやりやすくするEditorWindow。マルチシーン対応 (Unity2018.2.14)
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