Avoir un outil pour bien communiquer entre les scènes avec Unity est essentiel. Je vais parler ici des Gmanager (pour GlobalManager ou si vous aimez mieux GameManager) que j’ai développer pour faire fonctionner mon architecture logiciel que j’utilise dans Unity.
L’instanciation
Commencer par créer une classe enfant de MonoBehaviour dans laquelle nous allons mettre des éléments pour instancier l’objet tout en ayant un message d’erreur si jamais l’objet était instancié une deuxième fois par erreur.
//scripts/ProjectName/Behaviours/Gmanagers/BaseGmanagers.cs using UnityEngine; using Akerue.ProjectName.Data; namespace Akerue.ProjectName.Behaviours.Gmanagers { public class BaseGmanager : MonoBehaviour { #region ### init ### static BaseGmanager _instance; static BaseGmanager instance{ get{ setInstance(); return _instance; } } static void setInstance(){ if(_instance != null)return; GameObject go = new GameObject("BaseGmanager"); go.AddComponent‹BaseGmanager>(); GameObject.DontDestroyOnLoad(go);//keep the object active all along the game _instance = go.GetComponent‹BaseGmanager>(); } void Awake(){ if(_instance != null){ throw new System.Exception(this.GetType().Name+" can not be instanciate twice!"); } } #endregion } }
Dans le code vous avez un field _instance et une property instance. Il est très important ici de ne jamais utiliser directement le field _instance en dehors de la property instance ou de la methode setInstance.
Comme vous l’avez peut-être déjà remarqué, à chaque fois qu’instance est appelé la méthode setInstance vérifie si l’objet est déjà instancié. Si ce n’est pas le cas, la méthode créera un GameObject avec le component BaseGmanager et le mettra en DontDestroyOnLoad, ce qui signifie que l’objet restera présent durant les changement de scène. Et puis, finalement nous enregistrons l’instance de notre objet dans _instance pour se souvenir que l’objet est déjà instancié.
Objet Data
Ensuite créons une classe enfant de ScriptableObject pour pouvoir enregistrer nos données dans un prefab. Ceci est seulement un exemple. Il est fort possible qu’un vrai projet demande plus d’un objet Data.
//scripts/ProjectName/Data/ExempleData.cs using UnityEngine; namespace Akerue.ProjectName.Data { [CreateAssetMenu(fileName="ExempleData",menuName="Akerue/ExempleData")] public class ExempleData : ScriptableObject { #region ### Fields ### #region ** SerializeFields ** [SerializeField, Tooltip("Exemple int")] int _exempleInt; [SerializeField, Tooltip("Exemple string")] string _exempleStr; #endregion #endregion #region ### properties ### public int exempleInt{get{return _exempleInt;} set{_exempleInt=value;}} public string exempleStr{get{return _exempleStr;} set{_exempleStr=value;}} #endregion } }
Ici, notez bien l’attribut CreateAssetMenu. Cette attribut permet d’ajouter plus facilement un prefab avec la classe avec lequel il est associé en passant par le Create du menu.
Créer un prefab
Après ces étapes, en faisant un clique droit dans un dossier Resources, ajouter un prefab où nous pourrons enregistrer les données par défaut. Personnellement, je mets dans le dossier Resources une hiérarchie de dossier suivante NomCompagnie/NomProjet pour éviter les conflits.
Loader le Data
Ensuite, j’ajoute un field dans BaseGmanager pour garder en mémoire le data et une property public static pour partage le data avec d’autres objets si besoin est. De plus, pour ne pas surcharger l’a mémoire, la property vérifiera si le field est null et si c’est le cas le data sera loadé du dossier Resources avec une nouvelle instance du dit data.
//scripts/ProjectName/Behaviours/Gmanagers/BaseGmanagers.cs using UnityEngine; using Akerue.ProjectName.Data; namespace Akerue.ProjectName.Behaviours.Gmanagers { public class BaseGmanager : MonoBehaviour { #region ### init ### [...] #region ### fields ### ExempleData _exempleData; #endregion #region ### properties ### public static ExempleData exempleData{get{ if(instance._exempleData == null) instance._exempleData = Instantiate‹ExempleData>( Resources.Load‹ExempleData>("Akerue/ProjectName/ExempleData") ); return instance._exempleData; }} #endregion } }
Hiérarchie partiel et Code complet
scripts
>ProjectName
> > Behaviours
> > > Gmanagers
> > > – BaseGmanagers.cs
> > Data
> > – ExempleData.cs
Resources
> Akerue
> > ProjectName
> > – ExempleData.asset
//scripts/ProjectName/Behaviours/Gmanagers/BaseGmanagers.cs using UnityEngine; using Akerue.ProjectName.Data; namespace Akerue.ProjectName.Behaviours.Gmanagers { public class BaseGmanager : MonoBehaviour { #region ### init ### static BaseGmanager _instance; static BaseGmanager instance{ get{ setInstance(); return _instance; } } static void setInstance(){ if(_instance != null)return; GameObject go = new GameObject("BaseGmanager"); go.AddComponent‹BaseGmanager>(); GameObject.DontDestroyOnLoad(go);//keep the object active all along the game _instance = go.GetComponent‹BaseGmanager>(); } void Awake(){ if(_instance != null){ throw new System.Exception(this.GetType().Name+" can not be instanciate twice!"); } } #endregion #region ### fields ### ExempleData _exempleData; #endregion #region ### properties ### public static ExempleData exempleData{get{ if(instance._exempleData == null) instance._exempleData = Instantiate‹ExempleData>( Resources.Load‹ExempleData>("Akerue/ProjectName/ExempleData") ); return instance._exempleData; }} #endregion } }
//scripts/ProjectName/Data/ExempleData.cs using UnityEngine; namespace Akerue.ProjectName.Data { [CreateAssetMenu(fileName="ExempleData",menuName="Akerue/ExempleData")] public class ExempleData : ScriptableObject { #region ### Fields ### #region ** SerializeFields ** [SerializeField, Tooltip("Exemple int")] int _exempleInt; [SerializeField, Tooltip("Exemple string")] string _exempleStr; #endregion #endregion #region ### properties ### public int exempleInt{get{return _exempleInt;} set{_exempleInt=value;}} public string exempleStr{get{return _exempleStr;} set{_exempleStr=value;}} #endregion } }