Instantly share code, notes, and snippets.
Last active
May 3, 2017 07:05
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save dron247/f44da7e51158cd45b3f3d8a025df5919 to your computer and use it in GitHub Desktop.
Circular scene switch utility for Unity 3D
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.Generic; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Text.RegularExpressions; | |
| using UnityEditor; | |
| using UnityEditor.SceneManagement; | |
| using UnityEngine; | |
| using UnityEngine.SceneManagement; | |
| public class SceneNavigator : EditorWindow { | |
| private string mCurrentScene = string.Empty; | |
| private bool mIsDirty; | |
| private IList<string> mScenesList; | |
| [MenuItem("Window/Scene switcher")] | |
| public static void ShowLevelNavigator() { | |
| var window = GetWindow<SceneNavigator>(); | |
| var minSize = window.minSize; | |
| minSize.y = 35; | |
| window.minSize = minSize; | |
| } | |
| private void OnDisable() { | |
| if (mScenesList != null) mScenesList.Clear(); | |
| mScenesList = null; | |
| } | |
| private void OnEnable() { | |
| titleContent.text = "Scene switcher"; | |
| var allAssets = AssetDatabase.GetAllAssetPaths(); | |
| mScenesList = allAssets.Where(a => a.EndsWith(".unity")).OrderBy(x => x, new SceneNameComparer()).ToList(); | |
| mCurrentScene = CleanupSceneName(SceneManager.GetActiveScene().name); | |
| } | |
| Vector2 mScrollPos; | |
| private void OnGUI() { | |
| if (mIsDirty) { | |
| mCurrentScene = CleanupSceneName(SceneManager.GetActiveScene().name); | |
| mIsDirty = false; | |
| } | |
| EGUI.Vertical(() => { | |
| EGUI.SimpleScroll(ref mScrollPos, scroll => { | |
| GUILayout.Label("Active: " + mCurrentScene + Environment.NewLine); | |
| foreach (var scene in mScenesList) { | |
| EGUI.Button(scene, DirectOpenScene); | |
| } | |
| }); | |
| EGUI.Horizontal(() => { | |
| EGUI.Button("<-", caption => ChangeScene(Direction.Back)); | |
| EGUI.Button("->", caption => ChangeScene(Direction.Forward)); | |
| }); | |
| }); | |
| } | |
| /// <summary> | |
| /// Scene change method | |
| /// </summary> | |
| /// <param name="direction">Forward or backwards</param> | |
| private void ChangeScene(Direction direction) { | |
| if (mCurrentScene == string.Empty) return; | |
| var currentScene = mCurrentScene; | |
| if (currentScene.IndexOf("/", StringComparison.Ordinal) != -1 || currentScene.Contains(".unity")) | |
| currentScene = CleanupSceneName(currentScene); | |
| var index = FindIndex(mScenesList, currentScene); | |
| switch (direction) { | |
| case Direction.Back: | |
| if (index <= 0) index = mScenesList.Count; | |
| index--; | |
| break; | |
| case Direction.Forward: | |
| if (index >= mScenesList.Count - 1) index = -1; | |
| index++; | |
| break; | |
| default: | |
| index = 0; | |
| break; | |
| } | |
| EditorSceneManager.OpenScene(mScenesList[index]); | |
| mIsDirty = true; | |
| } | |
| private void DirectOpenScene(string sceneName) { | |
| var index = FindIndex(mScenesList, sceneName); | |
| EditorSceneManager.OpenScene(mScenesList[index]); | |
| mIsDirty = true; | |
| } | |
| /// <summary> | |
| /// Cleans scene name from file system artifacts | |
| /// </summary> | |
| /// <param name="sceneName">Name of scene in assets</param> | |
| /// <returns>Name of scene which can be used for loading scene in editor</returns> | |
| private static string CleanupSceneName(string sceneName) { | |
| return Path.GetFileNameWithoutExtension(sceneName); | |
| } | |
| /// <summary> | |
| /// Finds index of scene in scene collection by its name | |
| /// </summary> | |
| /// <param name="collection">collection of scenes</param> | |
| /// <param name="query">part of scene name</param> | |
| /// <returns>more or less accurate scene index in collection</returns> | |
| public static int FindIndex(IList<string> collection, string query) { | |
| for (var i = 0; i < collection.Count(); i++) if (collection.ElementAt(i).Contains(query)) return i; | |
| return -1; | |
| } | |
| /// <summary> | |
| /// Represents a direction of scene switching | |
| /// </summary> | |
| private enum Direction { | |
| Back = -1, | |
| Forward = 1 | |
| } | |
| /// <summary> | |
| /// Simple dsl wrapper for easier editor layout building | |
| /// </summary> | |
| private static class EGUI { | |
| /// <summary> | |
| /// Creates horizontal editor gui layout | |
| /// </summary> | |
| /// <param name="content">here you can place all content</param> | |
| public static void Horizontal(Action content) { | |
| using (var h = new EditorGUILayout.HorizontalScope()) { | |
| if (content != null) content.Invoke(); | |
| } | |
| } | |
| /// <summary> | |
| /// Creates vertical editor gui layout | |
| /// </summary> | |
| /// <param name="content">here you can place your content</param> | |
| public static void Vertical(Action content) { | |
| using (var v = new EditorGUILayout.VerticalScope()) { | |
| if (content != null) content.Invoke(); | |
| } | |
| } | |
| /// <summary> | |
| /// Do not use it outside, should be tested | |
| /// </summary> | |
| /// <param name="content"></param> | |
| public static void SimpleScroll(ref Vector2 position, Action<EditorGUILayout.ScrollViewScope> content) { | |
| using (var scrollView = new EditorGUILayout.ScrollViewScope(position, false, false, null)) { | |
| position = scrollView.scrollPosition; | |
| if (content != null) content.Invoke(scrollView); | |
| } | |
| } | |
| /// <summary> | |
| /// Creates a button | |
| /// </summary> | |
| /// <param name="caption">Button text</param> | |
| /// <param name="handler">Button click handler</param> | |
| public static void Button(string caption, Action<string> handler) { | |
| if (GUILayout.Button(caption)) if (handler != null) handler.Invoke(caption); | |
| } | |
| } | |
| /// <summary> | |
| /// Numbered scenes names comparer | |
| /// </summary> | |
| private class SceneNameComparer : IComparer<string> { | |
| private readonly Regex mRegex = new Regex(@"\d+"); | |
| public int Compare(string x, string y) { | |
| var cnx = ContainedNumber(x); | |
| var cny = ContainedNumber(y); | |
| if (cnx > cny) return 1; | |
| if (cnx < cny) return -1; | |
| return 0; | |
| } | |
| private int ContainedNumber(string source) { | |
| var match = mRegex.Match(source); | |
| int val; | |
| return int.TryParse(match.Value, out val) ? val : -1; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment