浏览代码

Making GameSceneSO more reliable (#265)

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

This also makes a custom editor unnecessary

* Set proper SceneAssets and serialize

* Improve code readability by splitting runtime and editor parts

* Fix scene path not being retrieved when entering play mode in Editor

* Use scene path instead of name

* Reset to default value

For a case when domain was not reloaded after entering play mode
/main
GitHub 4 年前
当前提交
3b36c936
共有 12 个文件被更改,包括 76 次插入118 次删除
  1. 4
      UOP1_Project/Assets/ScriptableObjects/SceneData/Initialization.asset
  2. 3
      UOP1_Project/Assets/ScriptableObjects/SceneData/Locations/Beach.asset
  3. 3
      UOP1_Project/Assets/ScriptableObjects/SceneData/Locations/Forest.asset
  4. 3
      UOP1_Project/Assets/ScriptableObjects/SceneData/Locations/TestingGround.asset
  5. 6
      UOP1_Project/Assets/ScriptableObjects/SceneData/Menus/MainMenu.asset
  6. 4
      UOP1_Project/Assets/Scripts/SceneManagement/EditorInitialisationLoader.cs
  7. 23
      UOP1_Project/Assets/Scripts/SceneManagement/LocationLoader.cs
  8. 9
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSO.cs
  9. 2
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs.meta
  10. 44
      UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs
  11. 93
      UOP1_Project/Assets/Scripts/Editor/GameSceneSOEditor.cs
  12. 0
      /UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs.meta

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


m_Script: {fileID: 11500000, guid: 7eabf0d1b44567046bb98dff8a1cd7ac, type: 3}
m_Name: Initialization
m_EditorClassIdentifier:
sceneName: Initialization
sceneAsset: {fileID: 102900000, guid: e8df4c5a458acc5489b2865e6b789224, type: 3}
scenePath: Assets/Scenes/Initialization.unity
musicVolume: 0

3
UOP1_Project/Assets/ScriptableObjects/SceneData/Locations/Beach.asset


m_Script: {fileID: 11500000, guid: 8db63739a6674d74e8e232347422172f, type: 3}
m_Name: Beach
m_EditorClassIdentifier:
sceneName: Beach
sceneAsset: {fileID: 102900000, guid: dfaf60263d5c5dc4e80e2793f4328b32, type: 3}
scenePath: Assets/Scenes/Locations/Beach.unity
shortDescription: The level to find X
music: {fileID: 0}
locationName:

3
UOP1_Project/Assets/ScriptableObjects/SceneData/Locations/Forest.asset


m_Script: {fileID: 11500000, guid: 8db63739a6674d74e8e232347422172f, type: 3}
m_Name: Forest
m_EditorClassIdentifier:
sceneName: Forest
sceneAsset: {fileID: 102900000, guid: 3a816f06c17361b4398583570bcbf8eb, type: 3}
scenePath: Assets/Scenes/Locations/Forest.unity
shortDescription: Find Y
music: {fileID: 0}
locationName:

3
UOP1_Project/Assets/ScriptableObjects/SceneData/Locations/TestingGround.asset


m_Script: {fileID: 11500000, guid: 8db63739a6674d74e8e232347422172f, type: 3}
m_Name: TestingGround
m_EditorClassIdentifier:
sceneName: TestingGround
sceneAsset: {fileID: 102900000, guid: 1e57caa7d7ed5e24a88cb3b5c309cc65, type: 3}
scenePath: Assets/Scenes/TestingGround.unity
shortDescription:
music: {fileID: 0}
locationName:

6
UOP1_Project/Assets/ScriptableObjects/SceneData/Menus/MainMenu.asset


m_Script: {fileID: 11500000, guid: 3546e1f9ebb6f054fb677b86f543542b, type: 3}
m_Name: MainMenu
m_EditorClassIdentifier:
sceneName: MainMenu
sceneAsset: {fileID: 102900000, guid: df490f8a21305b549b67b8301af79724, type: 3}
scenePath: Assets/Scenes/Menus/MainMenu.unity
musicVolume: 0
type: 0
menuType: 0

4
UOP1_Project/Assets/Scripts/SceneManagement/EditorInitialisationLoader.cs


for (int i = 0; i < SceneManager.sceneCount; ++i)
{
Scene scene = SceneManager.GetSceneAt(i);
if (scene.name == initializationScene.sceneName)
if (scene.path == initializationScene.scenePath)
SceneManager.LoadSceneAsync(initializationScene.sceneName, LoadSceneMode.Additive);
SceneManager.LoadSceneAsync(initializationScene.scenePath, LoadSceneMode.Additive);
}
#endif
}

23
UOP1_Project/Assets/Scripts/SceneManagement/LocationLoader.cs


private void Start()
{
if (SceneManager.GetActiveScene().name == _initializationScene.sceneName)
if (SceneManager.GetActiveScene().path == _initializationScene.scenePath)
{
LoadMainMenu();
}

{
for (int i = 0; i < locationsToLoad.Length; i++)
{
string currentSceneName = locationsToLoad[i].sceneName;
if (IsSceneLoaded(currentSceneName) == false)
string currentScenePath = locationsToLoad[i].scenePath;
if (IsSceneLoaded(currentScenePath) == false)
_scenesToLoadAsyncOperations.Add(SceneManager.LoadSceneAsync(currentSceneName, LoadSceneMode.Additive));
_scenesToLoadAsyncOperations.Add(SceneManager.LoadSceneAsync(currentScenePath, LoadSceneMode.Additive));
_scenesToLoadAsyncOperations[i].completed += SetActiveScene;
// TODO: Run a coroutine for each scene loading that updates a combined value
// for the progress bar. This way, as each scene completes loading, we will

private void SetActiveScene(AsyncOperation asyncOp)
{
// TODO: As each event completes, decide if it needs to activate right away.
SceneManager.SetActiveScene(SceneManager.GetSceneByName(_activeScene.sceneName));
SceneManager.SetActiveScene(SceneManager.GetSceneByPath(_activeScene.scenePath));
}
private void AddScenesToUnload()

Scene scene = SceneManager.GetSceneAt(i);
if (scene.name != _initializationScene.sceneName && scene.name != _activeScene.name)
var scene = SceneManager.GetSceneAt(i);
var scenePath = scene.path;
if (scenePath != _initializationScene.scenePath && scenePath != _activeScene.scenePath)
Debug.Log("Added scene to unload = " + scene.name);
Debug.Log("Added scene to unload = " + scenePath);
_scenesToUnload.Add(scene);
}
}

/// <summary>
/// This function checks if a scene is already loaded
/// </summary>
/// <param name="sceneName"></param>
/// <param name="scenePath"></param>
private bool IsSceneLoaded(string sceneName)
private bool IsSceneLoaded(string scenePath)
if (scene.name == sceneName)
if (scene.path == scenePath)
{
return true;
}

9
UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSO.cs


/// This class is a base class which contains what is common to all game scenes (Locations or Menus)
/// </summary>
public class GameSceneSO : ScriptableObject
public abstract partial class GameSceneSO : ScriptableObject
public string sceneName;
#if UNITY_EDITOR // See GameSceneSOEditor.cs
public UnityEditor.SceneAsset sceneAsset;
#endif
[HideInInspector]
public string scenePath;
}

2
UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs.meta


fileFormatVersion: 2
guid: a9133d1c8803ac04e8b40219b69b76b0
guid: 1c16d46359a2ac443892febbf5d270cb
MonoImporter:
externalObjects: {}
serializedVersion: 2

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


#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
// This is second part of implementation of GameSceneSO
// This part is reponsible for the editor-related functionality
public abstract partial class GameSceneSO : ScriptableObject, ISerializationCallbackReceiver
{
private SceneAsset prevSceneAsset;
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
PopulateScenePath();
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{ }
private void OnEnable()
{
// In case domain was not reloaded after entering play mode
prevSceneAsset = null;
PopulateScenePath();
}
private void PopulateScenePath()
{
if (sceneAsset != null)
{
// To prevent constant invocation of AssetDatabase API
// when this SO is opened in the Inspector.
if (prevSceneAsset != sceneAsset)
{
prevSceneAsset = sceneAsset;
scenePath = AssetDatabase.GetAssetPath(sceneAsset);
}
}
else
{
scenePath = string.Empty;
}
}
}
#endif

93
UOP1_Project/Assets/Scripts/Editor/GameSceneSOEditor.cs


using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
[CustomEditor(typeof(GameSceneSO), true)]
public class GameSceneSOEditor : Editor
{
private const string NO_SCENES_WARNING = "There is no Scene associated to this location yet. Add a new scene with the dropdown below";
private GUIStyle _headerLabelStyle;
private static readonly string[] _excludedProperties = { "m_Script", "sceneName" }; //m_script is a reference to the script being edited but it'll result an editable object field.
private string[] _sceneList;
private GameSceneSO _gameSceneInspected;
private void OnEnable()
{
_gameSceneInspected = target as GameSceneSO;
PopulateScenePicker();
InitializeGuiStyles();
}
public override void OnInspectorGUI()
{
//Make GUI not editable.
GUI.enabled = false;
//Draw reference information about script being edited.
EditorGUILayout.ObjectField("Script", MonoScript.FromScriptableObject((GameSceneSO)target), typeof(GameSceneSO), false);
//Make GUI editable.
GUI.enabled = true;
serializedObject.Update();
EditorGUILayout.LabelField("Scene information", _headerLabelStyle);
EditorGUILayout.Space();
DrawScenePicker();
DrawPropertiesExcluding(serializedObject, _excludedProperties);
serializedObject.ApplyModifiedProperties();
}
private void DrawScenePicker()
{
var sceneName = _gameSceneInspected.sceneName;
EditorGUI.BeginChangeCheck();
var selectedScene = _sceneList.ToList().IndexOf(sceneName);
if (selectedScene < 0)
{
EditorGUILayout.HelpBox(NO_SCENES_WARNING, MessageType.Warning);
}
selectedScene = EditorGUILayout.Popup("Scene", selectedScene, _sceneList);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Changed selected scene");
_gameSceneInspected.sceneName = _sceneList[selectedScene];
MarkAllDirty();
}
}
private void InitializeGuiStyles()
{
_headerLabelStyle = new GUIStyle(EditorStyles.largeLabel)
{
fontStyle = FontStyle.Bold,
fontSize = 18,
fixedHeight = 70.0f
};
}
/// <summary>
/// Populates the Scene picker with Scenes included in the game's build index
/// </summary>
private void PopulateScenePicker()
{
var sceneCount = SceneManager.sceneCountInBuildSettings;
_sceneList = new string[sceneCount];
for (int i = 0; i < sceneCount; i++)
{
_sceneList[i] = Path.GetFileNameWithoutExtension(SceneUtility.GetScenePathByBuildIndex(i));
}
}
/// <summary>
/// Marks scenes as dirty so data can be saved
/// </summary>
private void MarkAllDirty()
{
EditorUtility.SetDirty(target);
EditorSceneManager.MarkAllScenesDirty();
}
}

/UOP1_Project/Assets/Scripts/Editor/GameSceneSOEditor.cs.meta → /UOP1_Project/Assets/Scripts/SceneManagement/ScriptableObjects/GameSceneSOEditor.cs.meta

正在加载...
取消
保存