С помощью скрипта редактора клиента вы можете использовать SceneAsset
для хранения пути к сцене.
Я буду использовать здесь CustomEditor, так как для начинающих легче понятьчто там происходитПозже вы можете захотеть переключить его на CustomPropertyDrawer
с правильным классом или, может быть, даже как Атрибут.
Поместите это в любое место Assets
public class SceneLoader : MonoBehaviour
{
public string ScenePath;
public void Load()
{
//e.g.
SceneManager.LoadSceneAsync(ScenePath);
}
}
это внутри папки Editor
(поэтому она не будет включена в сборку, где пространство имен UnityEditor
не существует)
[CustomEditor(typeof(SceneLoader), true)]
public class ScenePickerEditor : Editor
{
private SerializedProperty _scenePath;
private void OnEnable()
{
_scenePath = serializezObject.FindProperty("ScenePath");
}
public override void OnInspectorGUI()
{
// Draw the usual script field
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField(.FromMonoBehaviour((SceneLoader)target), typeof(SceneLoader), false);
EditorGUI.EndDisabledGroup();
// Loads current Values into the serialized "copy"
serializedObject.Update();
// Get the current scene asset for the current path
var currentScene = !string.IsNullOrWhiteSpace(_scenePath.stringValue) ? AssetDatabase.LoadAssetAtPath<SceneAsset>(_scenePath.stringValue) : null;
EditorGUI.BeginChangeCheck();
var newScene = (SceneAsset)EditorGUILayout.ObjectField("Scene", currentScene, typeof(SceneAsset), false);
if (EditorGUI.EndChangeCheck())
{
_scenePath.stringValue = newScene != Null ? AssetDatabase.GetAssetPath(newScene) : "";
}
// Write back changes to the actual component
serializedObject.ApplyModifiedProperties();
}
}
И, например, к вашей кнопке присоедините этот компонент SceneLoader.
Чем вы можете просто ссылаться на целевую сцену в Инспекторе с помощью перетаскивания.Внутри он вместо этого хранит соответствующий ScenePath.
Теперь в onClick
вместо этого используйте SceneLoader.Load
.
Примечание:
Как уже упоминалось здесь только сохранение пути сцены не может быть «сохранено» и прерывается, если вы позже переместите соответствующую сцену или переименуете ее.Поэтому, возможно, было бы хорошим расширением хранить также соответствующую ссылку на объект как своего рода запасной вариант.
Вы можете также использовать этот подход и расширить его до централизованного менеджера вместо этого, например
// It could as well be a ScriptableObject object
// this makes e.g. Awake run already in edit mode
[ExecuteInEditMode]
public class ScenePathManager : MonoBehaviour
{
// I would prefere references but for ease of this post
// use a Singleton for access
public static ScenePathManager Instance;
public List<string> AvailableScenePaths = new List<string>();
private void Awake ()
{
Instance = this;
}
}
и в скрипте редактора используйте список (опять же, есть более красивые способы, такие как ReorderableList
бит, это может привести к усложнению здесь
[CustomEditor(typeof(ScenePathManager))]
public class ScenePathManagerEditor : Editor
{
private SerializedProperty _availablePaths;
private void OnEnable ()
{
_availablePaths = serializedObject.FindProperty("AvailablScenePaths");
}
public override OnInpectorGUI ()
{
// Draw the usual script field
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField(.FromMonoBehaviour((SceneLoader)target), typeof(SceneLoader), false);
EditorGUI.EndDisabledGroup();
serializedObject.Update();
//Do the same thing as before but this time in a loop
for(var i=0; i<_availablePaths.arraySize; i++)
{
var _scenePath = _availablePaths.GetArrayElementAtIndex(i);
// Loads current Values into the serialized "copy"
serializedObject.Update();
// Get the current scene asset for the current path
var currentScene = !string.IsNullOrWhiteSpace(_scenePath.stringValue) ? AssetDatabase.LoadAssetAtPath<SceneAsset>(_scenePath.stringValue) : null;
EditorGUI.BeginChangeCheck();
var newScene = (SceneAsset)EditorGUILayout.ObjectField("Scene", currentScene, typeof(SceneAsset), false);
if (EditorGUI.EndChangeCheck())
{
_scenePath.stringValue = newScene != Null ? AssetDatabase.GetAssetPath(newScene) : "";
}
}
serializedObject.ApplyModifiedProperties();
}
}
Чем вы можете сослаться на все необходимые сцены в этом менеджереи вместо этого на вашем SceneLoader
вместо этого есть поле Popup
(как для перечислений), чтобы выбрать нужную сцену
[CustomEditor (typeof (SceneLoader))]
public class SceneLoaderEditor : Editor
{
private SerializedProperty _scenePath;
private void OnEnable ()
{
_scenePath = serializedObject.FindProperty("ScenePath");
}
public override void OnInpectorGUI ()
{
//Let me shorten it a bit this time ^^
serializedObject.Update();
var availablePaths = ScenePathManager.Instance ? ScenePathManager.Instance.AvailableScenePaths : new List<string>();
var currentIndex = availablePaths.FirstOrDefault(path => string.Equals(path, _scenePath.stringValue)));
var newIndex = EditorGUILayout.PopupField("Scene", currentIndex, availabePaths.ToArray());
_scenePath.stringValue = availablePaths[newIndex];
serializedObject.ApplyModifiedProperties();
}
}
Это должно дать вам выпадающий список для выбора сцены.
Примечание это может, однако, без ссылки на объект, поскольку разрыв базового поля происходит быстрее, чем любая из этих строк или индексов изменяется ...
Но Вы могли бы использовать это с вашим менеджером также без всего подхода SceneAsset
, но только для простых строк.
Напечатано на моем смартфоне, так что никаких гарантий, но я надеюсь, что изложу свою точку зренияар