Comment nous avons repensé le travail avec les scènes dans Unity

Unity, en tant que moteur, présente un certain nombre d'inconvénients qui, grâce à ses capacités de personnalisation et ses outils de génération de code, peuvent être résolus.

Maintenant, je vais vous expliquer comment nous avons écrit un plugin pour Unity basé sur le post-traitement des projets et le générateur de code CodeDom.

Problème

Dans Unity, le chargement des scènes se fait via un identifiant de chaîne. Il n'est pas stable, ce qui signifie qu'il est facilement modifiable sans conséquences évidentes. Par exemple, lorsque vous renommez une scène, tout volera, mais il ne sera révélé qu'à la toute fin au stade de l'exécution.

Le problème apparaît rapidement dans les scènes fréquemment utilisées, mais peut être difficile à détecter lorsqu'il s'agit de petites scènes additives ou de scènes rarement utilisées.

Décision

Lors de l'ajout d'une scène à un projet, une classe du même nom est générée avec la méthode Load.

Si nous ajoutons une scène Menu, la classe Menu sera générée dans le projet et à l'avenir, nous pourrons démarrer la scène comme suit:

Menu.Load();

Oui, la méthode statique n'est pas la meilleure mise en page. Mais cela m'a semblé un design laconique et pratique. La génération se produit automatiquement, le code source de cette classe:

//------------------------------------------------------------------------------
// <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);
        }
    }
}

A l'amiable, la classe doit être statique, puisqu'elle n'est pas supposée être instanciée à partir d'elle. C'est un bug que nous allons corriger. Comme vous pouvez le voir sur ce fragment, le code ne nous accroche pas au nom, mais au GUID de la scène, qui est plus fiable. La classe de base elle-même ressemble à ceci:

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. , .

Dépôt GitHub - https://github.com/HolyMonkey/unity-typed-scenes

Si vous êtes intéressé, je demanderai à Vladislav dans le prochain article de vous dire comment il a travaillé avec Code Dom dans Unity et comment travailler avec le post-traitement en utilisant l'exemple de ce dont nous avons discuté aujourd'hui.




All Articles