J'ai vu plusieurs vidéos et tutoriels pour la création d'objets singleton dans Unity, principalement pour un GameManager
, qui semblent utiliser différentes approches pour instancier et valider un singleton.
Existe-t-il une approche correcte, ou plutôt préférée, à cet égard?
Les deux principaux exemples que j'ai rencontrés sont:
Première
public class GameManager
{
private static GameManager _instance;
public static GameManager Instance
{
get
{
if(_instance == null)
{
_instance = GameObject.FindObjectOfType<GameManager>();
}
return _instance;
}
}
void Awake()
{
DontDestroyOnLoad(gameObject);
}
}
Seconde
public class GameManager
{
private static GameManager _instance;
public static GameManager Instance
{
get
{
if(_instance == null)
{
instance = new GameObject("Game Manager");
instance.AddComponent<GameManager>();
}
return _instance;
}
}
void Awake()
{
_instance = this;
}
}
La principale différence que je peux voir entre les deux est la suivante:
La première approche tentera de naviguer dans la pile d’objets du jeu pour trouver une instance de ce GameManager
qui, bien que cela ne se produise (ou ne devrait se produire), semble une fois que cela pourrait être très non optimisé à mesure que la taille des scènes augmente au cours du développement.
En outre, la première approche marque que l’objet ne doit pas être supprimé lorsque l’application change de scène, ce qui garantit la persistance de cet objet entre les scènes. La deuxième approche ne semble pas adhérer à cela.
La deuxième approche semble étrange car dans le cas où l'instance est nulle dans le getter, elle créera un nouveau GameObject et lui affectera un composant GameManger. Cependant, cela ne peut pas s'exécuter sans que ce composant GameManager soit déjà attaché à un objet de la scène, ce qui me confond.
Existe-t-il d'autres approches qui seraient recommandées, ou un hybride des deux ci-dessus? Il existe de nombreuses vidéos et tutoriels sur les singletons, mais ils diffèrent tous tellement qu'il est difficile d'établir des comparaisons entre les deux et donc de déterminer laquelle est la meilleure approche / la meilleure approche.
la source
GameManager
faire, mais plutôt de s’assurer qu’il n’existe qu’une seule instance de l’objet et le meilleur moyen de le faire respecter.Réponses:
Cela dépend, mais d'habitude j'utilise une troisième méthode. Le problème avec les méthodes que vous avez utilisées est que, dans le cas où l'objet est inclus pour commencer, il ne les supprimera pas de l'arborescence, et ils peuvent toujours être créés en instanciant trop d'appels, ce qui pourrait rendre les choses vraiment déroutantes.
Le problème avec vos deux implémentations est qu'elles ne détruisent pas un objet créé ultérieurement. Cela pourrait fonctionner, mais on pourrait jeter une clé à molette dans les travaux qui pourrait entraîner une erreur de débogage très difficile sur toute la ligne. Assurez-vous de vérifier dans Awake s'il existe déjà une instance et, le cas échéant, de détruire la nouvelle instance.
la source
OnDestroy() { if (this == _instance) { _instance = null; } }
, si vous voulez avoir une instance différente dans chaque scène.Instance
propriété static est effacée. Un exemple de ce qui ne fonctionne pas peut être trouvé non plus dans l'une des réponses ci-dessous , ou wiki.unity3d.com/index.php/Singleton (qui peut être obsolète, mais semble fonctionner à partir de mes expériences)Voici un résumé rapide:
Donc, si tout ce qui vous intéresse, c’est l’accès mondial, vous obtenez tous les trois ce dont vous avez besoin. L'utilisation du modèle Singleton peut être un peu ambiguë quant à savoir si nous voulons une instanciation paresseuse, une unicité imposée ou un accès global . Veillez donc à bien réfléchir à la raison pour laquelle vous recherchez le singleton et à choisir une implémentation qui optimise ces fonctionnalités, que d'utiliser un standard pour les trois quand vous n'en avez besoin que d'un.
(par exemple, si mon jeu aura toujours un GameManager, peut-être que je ne me soucie pas de l'instanciation paresseuse - c'est peut-être seulement un accès global avec une existence garantie et le caractère unique qui me tient à cœur - dans ce cas, une classe statique m'offre exactement ces fonctionnalités de manière très concise, sans considérations de chargement de scène)
... mais n'utilisez certainement pas la Méthode 1 telle qu'écrite. La recherche peut être ignorée plus facilement avec l’approche Awake () de Method2 / 3, et si nous gardons le responsable d’une scène à l’autre, nous voulons très probablement supprimer les doublons, au cas où nous chargerions entre deux scènes avec un responsable déjà présent.
la source
La meilleure implémentation d'un
Singleton
modèle générique pour Unity que je connaisse est (bien sûr) la mienne.Il peut tout faire , et il le fait proprement et efficacement :
Autres avantages:
OnApplicationQuit()
. (Et cela se fait avec un seul drapeau global, au lieu que chaque type de singleton ait son propre)Et parce que partager c'est aimer , le voici:
la source
MonoBehaviour
, et je crois toute classe utilisée directement par Unity en général.SampleSingletonClass : Singleton
,SampleSingletonClass.Instance
revient avecSampleSingletonClass does not contain a definition for Instance
.Singleton<>
classe générique . C'est pourquoi le générique est un enfant de laSingleton
classe de base .J'aimerais juste ajouter qu'il peut être utile d'appeler
DontDestroyOnLoad
si vous voulez que votre singleton persiste d'une scène à l'autre.la source
Une autre option pourrait être de scinder la classe en deux parties: une classe statique régulière pour le composant Singleton et un MonoBehaviour qui agit en tant que contrôleur pour l'instance singleton. De cette façon, vous avez un contrôle total sur la construction du singleton, et cela persistera à travers les scènes. Cela vous permet également d'ajouter des contrôleurs à tout objet pouvant nécessiter les données du singleton, sans avoir à fouiller dans la scène pour trouver un composant particulier.
la source
Voici mon implémentation d'une classe abstraite singleton ci-dessous. Voici comment cela se compare aux 4 critères
Il présente quelques autres avantages par rapport à certaines des autres méthodes présentées ici:
FindObjectsOfType
qui est un tueur de performanceC'est fil-safe
la source
OnApplicationQuitCallback
and enOnEnableCallback
tantabstract
quevirtual
méthodes vides ? Au moins dans mon cas, je n'ai pas de logique Quitter / Activer et avoir un remplacement vide me semble sale. Mais il se peut que je manque quelque chose.OnApplicationQuitCallback
etOnEnableCallback
: le fait de l' utiliser comme méthode virtuelle le rend moins évident. Peut-être un peu bizarre une pensée, mais pour autant que je m'en souvienne, c'était ma raison.Il existe en fait une manière pseudo officielle d'utiliser Singleton dans Unity. Voici l'explication: créez en gros une classe Singleton et faites en sorte que vos scripts héritent de cette classe.
la source
Je vais aussi ma mise en œuvre pour les générations futures.
Pour moi, cette ligne
Destroy(gameObject.GetComponent(instance.GetType()));
est très importante car jadis j’avais laissé un script singleton sur un autre gameObject d’une scène et que tout l’objet du jeu était en train d’être supprimé. Cela ne détruit le composant que s'il existe déjà.la source
J'ai écrit une classe singleton qui facilite la création d'objets singleton. C'est un script MonoBehaviour, vous pouvez donc utiliser les Coroutines. Son basé sur cet article de wiki de Unity , et j'ajouterai l'option pour le créer à partir de Prefab plus tard.
Donc, vous n'avez pas besoin d'écrire les codes Singleton. Il suffit de télécharger cette classe de base Singleton.cs , de l'ajouter à votre projet et de créer votre singleton en l'étendant:
Maintenant, votre classe MySingleton est un singleton, et vous pouvez l'appeler par instance:
Voici un tutoriel complet: http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/
la source