Где хранить все мои сцены в одном месте - PullRequest
0 голосов
/ 27 марта 2019

Я создаю пробную версию в Unity и хотел бы иметь одну игру для доступа ко всем моим SceneNaming;

Прямо сейчас в пользовательском интерфейсе я должен установить имя сцены вручную.

enter image description here

Я хотел бы сохранить все мои имена сцен в объекте, чтобы я мог просто использовать перетаскивание для выбора всех имен своих сцен.

Я пытался поместить статический класс, и затем, например,

 public static string SCENE_MENU = "Menu";
 public static string SCENE_WORLD = "Demo";

или внутри перечисления

 public enum SCENE_NAME{
 Menu, Demo
 }

, а затем использовать GetName для перечисления, чтобы получить значение

Каков наилучший подход? 1 : /storage/temp/135402-screenshot-1.png

1 Ответ

3 голосов
/ 27 марта 2019

С помощью скрипта редактора клиента вы можете использовать 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, но только для простых строк.


Напечатано на моем смартфоне, так что никаких гарантий, но я надеюсь, что изложу свою точку зренияар

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...