浏览代码

Scene Selector window (#285)

* changed input phase check to match best practices

* menu input

- handles keyboard + gamepad inputs
- handles mouse inputs
- created component to place on selectable UI elements to register them
  as a pointer enter/exit receiver
- updated inputreader to contain menu inputs as well
- updated input actions to contain new menu inputs

* updates

* debug

* docs

* removed ununsed var

* doc

* found fix for todo #2

* added to component menu

* was able to fix edge case #1

* doc

* updates

* undid prefab change

* merged in main, added menu prefab to asset database

* removed action asset reference in event system on prefab

* readme

* menu prefab into scene

* updated readme

* removed call to base.onenter in CC button to simplify selection logic

* Use more reliable SceneAsset instead of error-prone scene name

This also makes a custom editor unnecessary

* Set proper SceneAssets and serialize

* ...
/devlogs-3-input
GitHub 4 年前
当前提交
f5865370
共有 27 个文件被更改,包括 673 次插入272 次删除
  1. 4
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs
  2. 2
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.ColorSelectorWindow.cs.meta
  3. 2
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Data.cs.meta
  4. 2
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.PreferencesWindow.cs.meta
  5. 2
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Helper.cs.meta
  6. 18
      UOP1_Project/Assets/ScriptableObjects/SceneData/Initialization.asset
  7. 8
      UOP1_Project/Assets/ScriptableObjects/SceneData/Initialization.asset.meta
  8. 8
      UOP1_Project/Assets/Scripts/Editor/SceneSelector.meta
  9. 86
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.ColorSelectorWindow.cs
  10. 59
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Data.cs
  11. 125
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Helper.cs
  12. 170
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.PreferencesWindow.cs
  13. 180
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.cs
  14. 11
      UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.cs.meta
  15. 8
      UOP1_Project/Assets/Scenes/Examples/MultiSceneLoaderExample.meta
  16. 8
      UOP1_Project/Assets/ScriptableObjects/SceneData/Resources.meta
  17. 217
      UOP1_Project/Assets/Scripts/Editor/SceneAccessTool.cs
  18. 27
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs
  19. 8
      UOP1_Project/Assets/Scripts/Attributes.meta
  20. 0
      /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.ColorSelectorWindow.cs.meta
  21. 0
      /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Data.cs.meta
  22. 0
      /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.PreferencesWindow.cs.meta
  23. 0
      /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Helper.cs.meta

4
UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs


#if UNITY_EDITOR
using System;
using UnityEngine;
using UnityEditor;

{
public static Action<GameSceneSO> onEnabled;
private SceneAsset prevSceneAsset;
void ISerializationCallbackReceiver.OnBeforeSerialize()

// In case domain was not reloaded after entering play mode
prevSceneAsset = null;
PopulateScenePath();
onEnabled?.Invoke(this);
}
private void PopulateScenePath()

2
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.ColorSelectorWindow.cs.meta


fileFormatVersion: 2
guid: c8ba2b93ee72bce49aa87ecc1b52ea6f
guid: a4894a7d2b2ba4841b568d11b5a6e76f
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Data.cs.meta


fileFormatVersion: 2
guid: 041bdbf27ff47ea4586c6b730fc5114c
guid: 32f1f29a07c980749a706bad43083603
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.PreferencesWindow.cs.meta


fileFormatVersion: 2
guid: 8be0eb3c422b9db4193a660915ecdd09
guid: 9972e0eab10bb65419fd00ebd6347842
MonoImporter:
externalObjects: {}
serializedVersion: 2

2
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Helper.cs.meta


fileFormatVersion: 2
guid: 02575d91f97b73a4aa5801082ffca3a1
guid: 797a1d0919a54ff4dbadbc9529e559bc
MonoImporter:
externalObjects: {}
serializedVersion: 2

18
UOP1_Project/Assets/ScriptableObjects/SceneData/Initialization.asset


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7eabf0d1b44567046bb98dff8a1cd7ac, type: 3}
m_Name: Initialization
m_EditorClassIdentifier:
sceneName: Initialization
shortDescription:
music: {fileID: 0}
musicVolume: 0

8
UOP1_Project/Assets/ScriptableObjects/SceneData/Initialization.asset.meta


fileFormatVersion: 2
guid: abfc6b5ef9fe68048bae8ffe84afa7a0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

8
UOP1_Project/Assets/Scripts/Editor/SceneSelector.meta


fileFormatVersion: 2
guid: ea3c4d16eb54b4a40ac681e562989fe9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

86
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.ColorSelectorWindow.cs


using UnityEditor;
using UnityEngine;
using SceneSelectorInternal;
public partial class SceneSelector : EditorWindow
{
private class ColorSelectorWindow : EditorWindow
{
private static readonly float kCellSize = PreferencesWindow.kColorMarkerFieldSize * 2.0f;
private static readonly Color kCellBackColor = new Color(0.0f, 0.0f, 0.0f, 0.1f);
private static readonly Vector2 kCellOffset = new Vector2(1.0f, 1.0f);
private static readonly Vector2Int kCount = new Vector2Int(5, 5);
private PreferencesWindow _owner;
private Color[,] _colors;
private Item _item;
public static ColorSelectorWindow Open(Rect rect, PreferencesWindow owner, Item item)
{
var window = CreateInstance<ColorSelectorWindow>();
window.Init(rect, owner, item);
return window;
}
private void Init(Rect rect, PreferencesWindow owner, Item item)
{
var size = (Vector2)kCount * kCellSize;
ShowAsDropDown(rect, size);
_owner = owner;
_item = item;
}
private void OnEnable()
{
wantsMouseMove = true;
InitColors();
}
private void OnGUI()
{
Helper.RepaintOnMouseMove(this);
DrawMarkers();
}
private void DrawMarkers()
{
var size = new Vector2(kCellSize, kCellSize);
for (int x = 0; x < kCount.x; ++x)
{
for (int y = 0; y < kCount.y; ++y)
{
var color = _colors[x, y];
var position = size * new Vector2(x, y);
var rect = new Rect(position, size);
{
var cellBackRect = rect;
cellBackRect.position += kCellOffset;
cellBackRect.size -= kCellOffset * 2.0f;
EditorGUI.DrawRect(cellBackRect, kCellBackColor);
}
if (Helper.DrawColorMarker(rect, color, true, true))
{
_item.color = color;
_owner.RepaintAll();
Close();
}
}
}
}
private void InitColors()
{
var count = kCount.x * kCount.y;
_colors = new Color[kCount.x, kCount.y];
for (int x = 0; x < kCount.x; ++x)
{
var h = x * kCount.y;
for (int y = 0; y < kCount.y; ++y)
{
float hue = (float)(h + y) / count;
_colors[x, y] = Color.HSVToRGB(hue, 1.0f, 1.0f);
}
}
}
}
}

59
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Data.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
public partial class SceneSelector : EditorWindow
{
[Serializable]
private class Item
{
public string guid;
public int order = int.MaxValue;
public bool isVisible = true;
public Color color = Color.clear;
[NonSerialized]
public GameSceneSO gameScene;
}
private class Styles
{
public GUIStyle item;
}
private class Textures
{
public Texture2D visibilityOn;
public Texture2D visibilityOff;
}
[Serializable]
private class Storage : ISerializationCallbackReceiver
{
[SerializeField]
public List<Item> items = new List<Item>();
[NonSerialized]
public Dictionary<string, Item> itemsMap = new Dictionary<string, Item>();
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
for (int i = 0, count = items.Count; i < count; ++i)
{
var item = items[i];
item.order = i;
}
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
items.OrderBy(x => x.order);
foreach (var item in items)
{
itemsMap.Add(item.guid, item);
}
}
}
}

125
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Helper.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace SceneSelectorInternal
{
internal static class KeyValuePairExtension
{
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value)
{
key = tuple.Key;
value = tuple.Value;
}
}
internal static class Helper
{
public const float kColorMarkerNormalSize = 4.0f;
public const float kColorMarkerHoveredSize = 6.0f;
public static readonly Color kColorMarkerDarkTint = Color.gray;
public static readonly Color kColorMarkerLightTint = new Color(1.0f, 1.0f, 1.0f, 0.32f);
public struct ReplaceColor : IDisposable
{
public static ReplaceColor With(Color color) => new ReplaceColor(color);
private Color _oldColor;
private ReplaceColor(Color color)
{
_oldColor = GUI.color;
GUI.color = color;
}
void IDisposable.Dispose() => GUI.color = _oldColor;
}
private static readonly Dictionary<Type, Color> kDefaultMarkerColors = new Dictionary<Type, Color>()
{
{ typeof(PersistentManagersSO), Color.magenta },
{ typeof(LocationSO), Color.green },
{ typeof(MenuSO), Color.cyan },
};
public static void RepaintOnMouseMove(EditorWindow window)
{
if (Event.current.type == EventType.MouseMove)
window.Repaint();
}
public static bool DrawColorMarker(Rect rect, Color color, bool isClickable = false, bool isHoverable = false)
{
bool isClicked = false;
if (isClickable)
isClicked = GUI.Button(rect, GUIContent.none, GUIStyle.none);
var currentEvent = Event.current;
var isHovered = isHoverable && rect.Contains(currentEvent.mousePosition);
var targetSize = isHovered ? kColorMarkerHoveredSize : kColorMarkerNormalSize;
var size = rect.size;
rect.size = new Vector2(targetSize, targetSize);
rect.position += (size - rect.size) * 0.5f;
Rect shadowRect = rect;
shadowRect.position -= Vector2.one;
shadowRect.size += Vector2.one;
Rect lightRect = rect;
lightRect.size += Vector2.one;
GUIUtility.RotateAroundPivot(45.0f, rect.center);
EditorGUI.DrawRect(shadowRect, color * kColorMarkerDarkTint);
EditorGUI.DrawRect(lightRect, kColorMarkerLightTint);
EditorGUI.DrawRect(rect, color);
GUIUtility.RotateAroundPivot(-45.0f, rect.center);
return isClicked;
}
public static void OpenSceneSafe(string path)
{
if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
EditorSceneManager.OpenScene(path);
}
}
public static Color GetDefaultColor(GameSceneSO gameScene)
{
var type = gameScene.GetType();
if (kDefaultMarkerColors.TryGetValue(type, out var color))
return color;
return Color.red;
}
public static void RunOnNextUpdate(Action action)
{
void Run()
{
action?.Invoke();
EditorApplication.update -= Run;
}
EditorApplication.update += Run;
}
public static int FindAssetsByType<T>(List<T> assets) where T : UnityEngine.Object
{
int foundAssetsCount = 0;
var guids = AssetDatabase.FindAssets($"t:{typeof(T)}");
for (int i = 0, count = guids.Length; i < count; ++i)
{
var path = AssetDatabase.GUIDToAssetPath(guids[i]);
T asset = AssetDatabase.LoadAssetAtPath<T>(path);
if (asset != null)
{
assets.Add(asset);
foundAssetsCount += 1;
}
}
return foundAssetsCount;
}
}
}

170
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.PreferencesWindow.cs


using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using SceneSelectorInternal;
public partial class SceneSelector : EditorWindow
{
private class PreferencesWindow : EditorWindow
{
private class Styles
{
public GUIStyle itemBorder;
public GUIStyle buttonVisibilityOn;
public GUIStyle buttonVisibilityOff;
}
private const string kWindowCaption = "Scene Selector Preferences";
private const float kHeaderHeight = 0.0f;
private const float kItemHeight = 24.0f;
private const float kVisibilityButtonSize = 16.0f;
public static float kColorMarkerFieldSize = Mathf.Ceil(Helper.kColorMarkerNormalSize * 1.41f + 8.0f);
private static readonly Color kItemBorderColor = new Color(1.0f, 1.0f, 1.0f, 0.16f);
private SceneSelector _owner;
private ColorSelectorWindow _colorSelectorWindow;
private ReorderableList _itemsReorderableList;
private Styles _styles;
private Vector2 _windowScrollPosition;
private List<Item> items => _owner._storage.items;
public static PreferencesWindow Open(SceneSelector owner)
{
var window = GetWindow<PreferencesWindow>(true, kWindowCaption, true);
window.Init(owner);
return window;
}
private void OnEnable()
{
wantsMouseMove = true;
}
private void OnDisable()
{
_owner.SaveStorage();
if (_colorSelectorWindow != null)
_colorSelectorWindow.Close();
}
private void OnGUI()
{
EnsureStyles();
Helper.RepaintOnMouseMove(this);
DrawWindow();
}
public void RepaintAll()
{
RepaintOwner();
Repaint();
}
private void Init(SceneSelector owner)
{
_owner = owner;
CreateReorderableList();
}
private void CreateReorderableList()
{
_itemsReorderableList = new ReorderableList(items, typeof(Item), true, true, false, false);
_itemsReorderableList.drawElementCallback = DrawItem;
_itemsReorderableList.drawElementBackgroundCallback = DrawItemBackground;
_itemsReorderableList.onReorderCallback = OnReorder;
_itemsReorderableList.headerHeight = kHeaderHeight;
_itemsReorderableList.elementHeight = kItemHeight;
}
private void DrawWindow()
{
using (var scrollScope = new EditorGUILayout.ScrollViewScope(_windowScrollPosition))
{
GUILayout.Space(4.0f);
_itemsReorderableList.DoLayoutList();
_windowScrollPosition = scrollScope.scrollPosition;
}
}
private void DrawItem(Rect rect, int index, bool isActive, bool isFocused)
{
var item = items[index];
var gameScene = item.gameScene;
if (gameScene != null)
{
var colorMarkerRect = rect;
colorMarkerRect.width = colorMarkerRect.height;
if (Helper.DrawColorMarker(colorMarkerRect, item.color, true, true))
{
var colorSelectorRect = GUIUtility.GUIToScreenRect(colorMarkerRect);
_colorSelectorWindow = ColorSelectorWindow.Open(colorSelectorRect, this, item);
}
var itemLabelRect = rect;
itemLabelRect.x += colorMarkerRect.width;
itemLabelRect.width -= kVisibilityButtonSize + colorMarkerRect.width;
GUI.Label(itemLabelRect, gameScene.name);
var visibilityButtonRect = new Rect(rect);
visibilityButtonRect.width = kVisibilityButtonSize;
visibilityButtonRect.height = kVisibilityButtonSize;
visibilityButtonRect.x = itemLabelRect.x + itemLabelRect.width;
visibilityButtonRect.y += (rect.height - visibilityButtonRect.height) * 0.5f;
var visibilityStyle = item.isVisible
? _styles.buttonVisibilityOn
: _styles.buttonVisibilityOff;
if (GUI.Button(visibilityButtonRect, GUIContent.none, visibilityStyle))
{
item.isVisible = !item.isVisible;
RepaintOwner();
}
}
}
private void DrawItemBackground(Rect rect, int index, bool isActive, bool isFocused)
{
ReorderableList.defaultBehaviours.DrawElementBackground(rect, index, isActive, isFocused, true);
using (Helper.ReplaceColor.With(kItemBorderColor))
{
GUI.Box(rect, GUIContent.none, _styles.itemBorder);
}
}
private void OnReorder(ReorderableList _)
{
RepaintOwner();
}
private void RepaintOwner()
{
_owner.Repaint();
}
private void EnsureStyles()
{
if (_styles == null)
{
_styles = new Styles();
_styles.itemBorder = new GUIStyle(GUI.skin.GetStyle("HelpBox"));
_styles.buttonVisibilityOn = new GUIStyle(GUI.skin.label);
_styles.buttonVisibilityOn.padding = new RectOffset(0, 0, 0, 0);
_styles.buttonVisibilityOn.normal.background = EditorGUIUtility.FindTexture("d_scenevis_visible");
_styles.buttonVisibilityOn.hover.background = EditorGUIUtility.FindTexture("d_scenevis_visible_hover");
_styles.buttonVisibilityOff = new GUIStyle(GUI.skin.label);
_styles.buttonVisibilityOff.padding = new RectOffset(0, 0, 0, 0);
_styles.buttonVisibilityOff.normal.background = EditorGUIUtility.FindTexture("d_scenevis_hidden");
_styles.buttonVisibilityOff.hover.background = EditorGUIUtility.FindTexture("d_scenevis_hidden_hover");
}
}
}
}

180
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.cs


using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using SceneSelectorInternal;
public partial class SceneSelector : EditorWindow, IHasCustomMenu
{
private const string kPreferencesKey = "uop1.SceneSelector.Preferences";
private const int kItemContentLeftPadding = 32;
private static readonly GUIContent kOpenPreferencesItemContent = new GUIContent("Open Preferences");
private Styles _styles;
private Storage _storage;
private PreferencesWindow _preferencesWindow;
private Vector2 _windowScrollPosition;
private bool _hasEmptyItems;
private List<Item> items => _storage.items;
private Dictionary<string, Item> itemsMap => _storage.itemsMap;
[MenuItem("Window/Scene Selector", false, 100)]
private static void Open()
{
GetWindow<SceneSelector>();
}
private void OnEnable()
{
wantsMouseMove = true;
LoadStorage();
PopulateItems();
GameSceneSO.onEnabled += OnGameSceneSOCreated;
}
private void OnDisable()
{
if (_preferencesWindow != null)
_preferencesWindow.Close();
SaveStorage();
GameSceneSO.onEnabled -= OnGameSceneSOCreated;
}
private void OnGUI()
{
EnsureStyles();
Helper.RepaintOnMouseMove(this);
RemoveEmptyItemsIfRequired();
DrawWindow();
}
private void DrawWindow()
{
using (var scrollScope = new EditorGUILayout.ScrollViewScope(_windowScrollPosition))
{
GUILayout.Space(4.0f);
DrawItems();
_windowScrollPosition = scrollScope.scrollPosition;
}
}
private void DrawItems()
{
foreach (var item in items)
{
DrawItem(item);
}
}
private void DrawItem(Item item)
{
if (item.isVisible)
{
var gameScene = item.gameScene;
if (gameScene != null)
{
if (GUILayout.Button(gameScene.name, _styles.item))
{
Helper.OpenSceneSafe(gameScene.scenePath);
}
var colorMarkerRect = GUILayoutUtility.GetLastRect();
colorMarkerRect.width = colorMarkerRect.height;
colorMarkerRect.x += (_styles.item.padding.left - colorMarkerRect.width) * 0.5f;
Helper.DrawColorMarker(colorMarkerRect, item.color);
}
else
{
// In case GameSceneSO was removed (see RemoveEmptyItemsIfRequired)
_hasEmptyItems = true;
}
}
}
private void LoadStorage()
{
_storage = new Storage();
if (EditorPrefs.HasKey(kPreferencesKey))
{
var preferencesJSON = EditorPrefs.GetString(kPreferencesKey);
EditorJsonUtility.FromJsonOverwrite(preferencesJSON, _storage);
}
}
private void SaveStorage()
{
var preferencesJSON = EditorJsonUtility.ToJson(_storage);
EditorPrefs.SetString(kPreferencesKey, preferencesJSON);
}
private void PopulateItems()
{
var gameScenes = new List<GameSceneSO>();
Helper.FindAssetsByType(gameScenes);
foreach (var gameScene in gameScenes)
{
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(gameScene, out var guid, out long _))
{
if (itemsMap.TryGetValue(guid, out var item))
{
item.gameScene = gameScene;
}
else
{
item = new Item()
{
gameScene = gameScene,
guid = guid,
color = Helper.GetDefaultColor(gameScene)
};
items.Add(item);
itemsMap.Add(guid, item);
}
}
}
}
private void RemoveEmptyItemsIfRequired()
{
if (_hasEmptyItems)
{
for (int i = items.Count - 1; i >= 0; --i)
{
var sceneItem = items[i];
if (sceneItem == null || sceneItem.gameScene == null)
{
items.RemoveAt(i);
itemsMap.Remove(sceneItem.guid);
}
}
}
_hasEmptyItems = false;
}
private void OnGameSceneSOCreated(GameSceneSO _)
{
Helper.RunOnNextUpdate(PopulateItems);
}
private void EnsureStyles()
{
if (_styles == null)
{
_styles = new Styles();
_styles.item = "MenuItem";
_styles.item.padding.left = kItemContentLeftPadding;
}
}
private void OpenPreferences()
{
_preferencesWindow = PreferencesWindow.Open(this);
}
void IHasCustomMenu.AddItemsToMenu(GenericMenu menu)
{
menu.AddItem(kOpenPreferencesItemContent, false, OpenPreferences);
}
}

11
UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.cs.meta


fileFormatVersion: 2
guid: 78e26d6372ed406448b1b3bb3ea08b46
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
UOP1_Project/Assets/Scenes/Examples/MultiSceneLoaderExample.meta


fileFormatVersion: 2
guid: 3b1c2544e599a634ea09627dd05ef60e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
UOP1_Project/Assets/ScriptableObjects/SceneData/Resources.meta


fileFormatVersion: 2
guid: dd754fdc4b0731f4f9633351d8dcd5f3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

217
UOP1_Project/Assets/Scripts/Editor/SceneAccessTool.cs


using UnityEngine;
using UnityEditor;
using System.IO;
using UnityEditorInternal;
using UnityEditor.SceneManagement;
using System.Collections.Generic;
using System.Linq;
public class SceneAccessTool : EditorWindow, IHasCustomMenu
{
private SceneAccessHolderSO _inspected;
private SerializedObject _serializedObject;
private Editor _sceneAccessHolderSOEditor;
public enum Layout { List, Grid }
private Layout _layout;
private bool _showOptions = false;
private bool _editMode = false;
private ReorderableList list;
private void OnEnable()
{
_inspected = Resources.Load<SceneAccessHolderSO>("SceneAccessHolder");
SetUpList();
}
private void SetUpList()
{
_serializedObject = new SerializedObject(_inspected);
if (_editMode)
{
list = new ReorderableList(_serializedObject,
_serializedObject.FindProperty("sceneList"),
true, false, false, false);
list.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = list.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.PropertyField(
new Rect(rect.x, rect.y, rect.width - 30, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("name"), GUIContent.none);
EditorGUI.PropertyField(
new Rect(rect.x + rect.width - 25, rect.y, 25, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("visible"), GUIContent.none);
};
}
}
[MenuItem("Tools/SceneAccessTool")]
public static void ShowWindow()
{
GetWindow<SceneAccessTool>("SceneAccessTool");
}
private void OnGUI()
{
if (_inspected != null)
{
if (_showOptions)
ShowOptions();
ShowSceneList();
}
}
public void ShowOptions()
{
GUILayout.BeginHorizontal();
if (GUILayout.Button("Populate Scene List"))
{
PopulateSceneList();
}
if (GUILayout.Button("Clear List"))
{
ClearSceneList();
}
if (GUILayout.Button("Edit Mode"))
{
ToggleEditMode();
}
GUILayout.EndHorizontal();
}
public void ShowSceneList()
{
if (_editMode)
{
_serializedObject.Update();
list.DoLayoutList();
_serializedObject.ApplyModifiedProperties();
}
else
{
if (_layout == Layout.List)
{
for (int i = 0; i < _inspected.sceneList.Count; i++)
{
var sceneItem = _inspected.sceneList[i];
if (!sceneItem.visible)
{
continue;
}
if (GUILayout.Button(sceneItem.name))
{
EditorSceneManager.OpenScene(sceneItem.path);
}
}
}
else
{
int gridSize = 48;
int widthCount = gridSize;
GUILayout.BeginHorizontal();
for (int i = 0; i < _inspected.sceneList.Count; i++)
{
var sceneItem = _inspected.sceneList[i];
if (!sceneItem.visible)
{
continue;
}
GUIStyle customButton = new GUIStyle("button");
customButton.fontSize = 10;
customButton.alignment = TextAnchor.UpperLeft;
customButton.wordWrap = true;
GUIContent guiContent = new GUIContent(sceneItem.name);
if (GUILayout.Button(
guiContent,
customButton,
GUILayout.Width(gridSize),
GUILayout.Height(gridSize)))
{
EditorSceneManager.OpenScene(sceneItem.path);
}
widthCount += gridSize + 4;
if (widthCount > position.width)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
widthCount = gridSize;
}
}
GUILayout.EndHorizontal();
}
}
}
/// <summary>
/// Find all scenes in the project and put them in the list
/// </summary>
private void PopulateSceneList()
{
EditorBuildSettingsScene[] currentScenes = EditorBuildSettings.scenes;
EditorBuildSettingsScene[] filteredScenes = currentScenes.Where(ebss => File.Exists(ebss.path)).ToArray();
List<SceneAccessHolderSO.SceneInfo> allScene = new List<SceneAccessHolderSO.SceneInfo>();
for (int i = 0; i < filteredScenes.Length; i++)
{
allScene.Add(
new SceneAccessHolderSO.SceneInfo
{
name = Path.GetFileNameWithoutExtension(filteredScenes[i].path),
path = Path.GetFullPath(filteredScenes[i].path),
visible = true
});
}
//add the new scenes
foreach (SceneAccessHolderSO.SceneInfo sceneInfo in allScene)
{
if (!_inspected.sceneList.Contains(sceneInfo))
{
_inspected.sceneList.Add(sceneInfo);
}
}
//remove the deleted scenes
foreach (SceneAccessHolderSO.SceneInfo sceneInfo in _inspected.sceneList.ToList())
{
if (!allScene.Contains(sceneInfo))
{
_inspected.sceneList.Remove(sceneInfo);
}
}
}
private void ClearSceneList()
{
_inspected.sceneList.Clear();
}
public void AddItemsToMenu(GenericMenu menu)
{
menu.AddItem(new GUIContent("ToggleOptions"), false, ToggleOptions);
menu.AddItem(new GUIContent("ToggleLayout"), false, ToggleLayout);
}
private void ToggleOptions()
{
_showOptions = !_showOptions;
}
private void ToggleLayout()
{
if (_layout == Layout.List)
{
_layout = Layout.Grid;
}
else
{
_layout = Layout.List;
}
}
private void ToggleEditMode()
{
_editMode = !_editMode;
SetUpList();
}
}

27
UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs


using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// It holds a list of scenes that's shown in the scene quick access tool
/// </summary>
[CreateAssetMenu(fileName = "SceneAccessHolder", menuName = "Scene Data/SceneAccessHolder")]
public class SceneAccessHolderSO : ScriptableObject
{
[Serializable]
public struct SceneInfo : IEquatable<SceneInfo>
{
[ReadOnly] public string name;
[ReadOnly] public string path;
public bool visible;
public bool Equals(SceneInfo other)
{
// Would still want to check for null etc. first.
return this.path == other.path;
}
}
[Header("List of Scenes")]
public List<SceneInfo> sceneList;
}

8
UOP1_Project/Assets/Scripts/Attributes.meta


fileFormatVersion: 2
guid: b20537032508d384c9b7e9decf64c3ae
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

/UOP1_Project/Assets/Scripts/Editor/SceneAccessTool.cs.meta → /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.ColorSelectorWindow.cs.meta

/UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/SceneAccessHolderSO.cs.meta → /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Data.cs.meta

/UOP1_Project/Assets/Scripts/Attributes/Editor/ReadOnlyDrawer.cs.meta → /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.PreferencesWindow.cs.meta

/UOP1_Project/Assets/Scripts/Attributes/ReadOnlyAttribute.cs.meta → /UOP1_Project/Assets/Scripts/Editor/SceneSelector/SceneSelector.Helper.cs.meta

正在加载...
取消
保存