在哪里存储我所有的场景名称在一个地方

Where to Store all my scene name in one place

我正在 Unity 中制作一个项目,并希望通过一次播放来访问我所有的 SceneNaming;

现在在UI,我必须手动设置场景名称。

我想将我所有的场景名称存储在一个对象中,这样我就可以使用拖放来选择我所有的场景名称。

我试着放一个静态的 class 然后像这样

 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

使用客户编辑器脚本,您可以使用 SceneAsset 来存储场景的路径。

我将在这里使用 CustomEditor,因为对于初学者来说,它更容易理解那里发生的事情。稍后您可能想将其切换为 CustomPropertyDrawer wot 适当的 class 或什至作为属性。

将其放在 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


注:
如前所述 here 仅存储场景路径可能不是 "save" 并且如果您稍后移动相应场景或重命名它会中断。因此,将相应的对象引用存储为一种后备方式可能是一个很好的扩展。


您也可以使用这种方法并将其扩展为中央管理器,而不是像

// 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 字段(比如枚举)以便 select 你想要的场景

[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();
    }
}

这应该会为您提供场景的 selection 下拉菜单。

注意 但是,如果没有对象引用,因为支持字段中断任何这些字符串或索引的更改速度更快...

但是您也可以与您的经理一起使用它,而无需整个 SceneAsset 方法,但仅适用于简单的字符串。


在我的智能手机上打字,所以没有保修,但我希望我能表达清楚