我们如何重新想象在Unity中使用场景

作为引擎,Unity有许多缺点,由于其定制功能和代码生成工具,这些缺点可以得到解决。

现在,我将向您介绍我们如何基于后处理项目和CodeDom代码生成器为Unity编写插件。

问题

在Unity中,场景的加载是通过字符串标识符完成的。它不是稳定的,这意味着它很容易更改,而没有明显的后果。例如,当您重命名场景时,所有内容都会飞行,但是仅在执行阶段的最后显示。

在频繁使用的场景中,该问题很快出现,但是当涉及到小的附加场景或很少使用的场景时,可能很难检测到。

决断

将场景添加到项目时,将使用Load方法生成同名的类。

如果添加一个Menu场景,那么将在项目中生成Menu类,将来我们可以如下所示启动场景:

Menu.Load();

是的,静态方法不是最佳布局。但是在我看来,这是一种简洁而方便的设计。生成自动发生,此类的源代码:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace IJunior.TypedScenes
{   
    public class Menu : TypedScene
    {
        private const string GUID = "a3ac3ba38209c7744b9e05301cbfa453";
        
        public static void Load()
        {
            LoadScene(GUID);
        }
    }
}

以友好的方式,该类应该是静态的,因为不应从该类实例化该类。这是一个我们将修复的错误。从该片段中您可以看到,我们的代码不保留名称,而是保留场景GUID,这更可靠。基类本身看起来像这样:

namespace IJunior.TypedScenes
{
    public abstract class TypedScene
    {
        protected static void LoadScene(string guid)
        {
            var path = AssetDatabase.GUIDToAssetPath(guid);
            SceneManager.LoadScene(path);
        }

        protected static void LoadScene<T>(string guid, T argument)
        {
            var path = AssetDatabase.GUIDToAssetPath(guid);

            UnityAction<Scene, Scene> handler = null;
            handler = (from, to) =>
            {
                if (to.name == Path.GetFileNameWithoutExtension(path))
                {
                    SceneManager.activeSceneChanged -= handler;
                    HandleSceneLoaders(argument);
                }
            };

            SceneManager.activeSceneChanged += handler;
            SceneManager.LoadScene(path);
        }

        private static void HandleSceneLoaders<T>(T loadingModel)
        {
            foreach (var rootObjects in SceneManager.GetActiveScene().GetRootGameObjects())
            {
                foreach (var handler in rootObjects.GetComponentsInChildren<ISceneLoadHandler<T>>())
                {
                    handler.OnSceneLoaded(loadingModel);
                }
            }
        }
    }
}

- .

- ( , ), .

, .

, Game , .

.

using IJunior.TypedScenes;
using System.Collections.Generic;
using UnityEngine;

public class GameLoadHandler : MonoBehaviour, ISceneLoadHandler<IEnumerable<Player>>
{
    public void OnSceneLoaded(IEnumerable<Player> players)
    {
        foreach (var player in players)
        {
            //make avatars
        }
    }
}

, .

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace IJunior.TypedScenes
{
    public class Game : TypedScene
    {
        private const string GUID = "976661b7057d74e41abb6eb799024ada";
        
        public static void Load(System.Collections.Generic.IEnumerable<Player> argument)
        {
            LoadScene(GUID, argument);
        }
    }
}

. .. N , N . - .

, , , .

N?

YouTube .

. , , , .

, ?

. :

public class GameArguments
{
    public IEnumerable<Player> Players { get; set; }
}

, , , .

, : , . , .

ID .

PlayerPerfs

. , PlayerPrefs . , , .

ASPNet

- View ASPNet Core. ViewData ViewModel. Unity - .

Unity , - , View ASPNet. Additive ( , , ), .

, , , , .

Proof-of-concept. , .

GitHub存储库-https: //github.com/HolyMonkey/unity-typed-scenes

如果您有兴趣,我将在下一篇文章中请Vladislav告诉您他如何在Unity中使用Code Dom,以及如何使用我们今天讨论的示例进行后期处理。




All Articles