Est-ce une mauvaise idée d'avoir statique Game1 dans XNA?

10

Est-ce vraiment une mauvaise idée que ma Game1classe soit statique? Comme en ce moment dans ma Game1classe, j'ai une classe appelée TileHandlerqui gère tout ce qui concerne mon jeu de tuiles actuel, et AnimalHandlerqui gère tous mes animaux (étonnamment).

Maintenant, si je suis dedans AnimalHandleret que je veux vérifier si une tuile est accessible à pied, TileHandlercela cause des problèmes ou je dois passer une liste de tuiles accessibles à pied AnimalHandler, ce que je préfère ne pas faire.

Ce qui serait plus facile serait de faire de la Game1statique puis de AnimalHandlerpartir Game1._tileHandler.WalkableTile(position).

Maintenant, je ne vois rien de mal immédiatement ou tout ce qui pourrait causer des problèmes, mais je viens juste de commencer à utiliser des classes statiques, donc quelqu'un de plus averti voit-il une raison géante pour laquelle c'est une mauvaise idée?

Harold
la source

Réponses:

9

Maintenant, je ne vois rien de mal immédiatement ou tout ce qui pourrait causer des problèmes, mais je viens juste de commencer à utiliser des classes statiques, donc quelqu'un de plus averti voit-il une raison géante pour laquelle c'est une mauvaise idée?

Lorsque vous avez un nouveau marteau brillant, chaque problème ressemble à un clou.

En général, il n'y a rien de mal avec les classes statiques et / ou les méthodes, si elles sont utilisées correctement (pour les choses qui n'ont pas ou dépendent de l'état par instance). Cependant, dans votre cas, vous les utilisez à mauvais escient pour masquer une dépendance par instance, confondant cela avec la suppression de la dépendance. Il apparaît également que vous exposez les détails d'implémentation de la Game1classe, ce qui est également généralement mauvais.

Voici le nœud de votre problème:

... si je suis dedans AnimalHandleret que je veux vérifier si une tuile est accessible à pied, TileHandlercela cause des problèmes ou je dois passer une liste de tuiles accessibles à pied AnimalHandler, ce que je préfère ne pas faire.

Ignorer la possibilité AnimalHandlerqu'avoir besoin de ces tuiles peut être en soi une mauvaise conception (avec les noms que vous avez choisis, il est difficile de dire les détails de ces classes) pour le moment ... si vous avez AnimalHandlerbesoin d'une liste de tuiles accessibles à pied, alors il a besoin d'une liste de tuiles marchables. Il est généralement préférable de rendre les dépendances plus explicites que moins , car cela rend le code plus auto-documenté. En passant directement la liste à AnimalHandler, vous expliquez explicitement qu'elle a besoin d'une telle liste. Si, à la place, vous rendez tout statique et public afin que vous puissiez simplement accéder à la liste statique contenue ailleurs dans le code, tout ce que vous faites est de masquer la dépendance sans réellement la résoudre ou la supprimer.

Pour un petit jeu qui n'a pas besoin d'être mis à l'échelle, ce ne sera pas un problème en soi, mais cela peut vous conduire sur le chemin d'une mauvaise habitude, vous pouvez donc envisager de ne pas le faire. À tout le moins, gardez cela à l'esprit pour le prochain projet sur lequel vous travaillez.


la source
Amen! Vous touchez un grand point dont je n'ai pas vraiment parlé dans ma réponse.
Nate
+1 cacher les dépendances et introduire un état global est vraiment le problème ici
ashes999
4

La raison pour laquelle appeler TileHandler dans un contexte statique n'est pas la meilleure conception possible, c'est qu'elle couple des composants de votre conception qui pourraient autrement être découplés.

Si vous choisissez d'avoir plus d'un TileHandler à l'avenir, vous devrez faire beaucoup de travail pour s'adapter à ce changement.

Si vous choisissez de supprimer TileHandler, vous devrez faire beaucoup de travail pour s'adapter à ce changement.

Supposons que vous construisez un niveau / zone différent à l'avenir, qui gérera les tuiles d'une manière différente de votre TileHandler actuel. Vous devez alors soit avoir un moyen de spécifier la méthode de traitement des tuiles à utiliser, soit appeler un autre gestionnaire.

Si le TileHandler a été transmis en tant que paramètre aux objets qui l'utilisent, vous pouvez simplement en passer un autre la prochaine fois, ou définir un autre gestionnaire de tuiles sur les objets qui l'utilisent plus tard.

Personnellement, j'accède à beaucoup de choses dans mes jeux XNA à partir d'un contexte statique, et je suppose que je n'en aurai jamais plus d'un.

Si vous voulez pouvoir réutiliser votre code moteur de jeu dans votre prochain jeu, vous devrez probablement réécrire une grande partie des éléments que vous avez actuellement écrits sous forme statique.

En bref:

Pour ne pas utiliser de contexte statique:

Le passage d'objets en paramètres autant que possible dissocie les éléments du jeu, et vous permet de les modifier / réutiliser plus facilement pour les projets en cours ou à venir. Il vous permet également de gérer un peu plus facilement la complexité de grandes quantités de code (pensez à avoir des centaines de gestionnaires statiques dans votre classe de jeu, dans un grand jeu).

En faveur du contexte statique:

La déclaration et l'accès aux objets à partir d'un contexte statique facilitent l'écriture de petits jeux qui ne nécessitent pas des centaines de gestionnaires statiques. Simplifie de nombreuses méthodes et constructeurs en ne nécessitant pas un ou plusieurs paramètres supplémentaires accessibles à la place de manière statique.

Olhovsky
la source
2

Je ne pense pas que ce soit une très mauvaise idée pour un jeu simple, mais vous pouvez aussi jeter un œil à http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services pour une meilleure idée sur la façon de construire des composants de jeu intercommunicants

smnbss
la source
Pourriez-vous penser à des problèmes si ce n'était pas seulement un jeu simple?
Harold
La lisibilité du code, la testabilité et les bonnes pratiques d'architecture suggèrent de l'éviter.
smnbss
2

Des choses comme TileHandler et AnimalHandler, je mettrais un niveau plus élevé dans un écran de jeu. Votre écran de titre doit-il avoir accès au TileHandler et est-il initialisé lors du premier chargement du jeu? Probablement pas.

Découvrez l'exemple XNA State Management . Il contient beaucoup de code, mais le jeu de base initialise simplement une pile d'états de jeu (ou écrans). Chaque écran est assez indépendant des autres et fonctionne comme une version simplifiée du jeu lui-même. Votre PlayScreen peut avoir des membres statiques afin qu'ils soient accessibles aux composants PlayScreen.

Dans le jeu de base, j'utilise quelques statiques, mais ce sont des choses de très bas niveau comme les lecteurs InputHelper, Log ou Config. Ils sont assez standard dans tous les jeux afin que le moteur de base puisse être rapidement et facilement porté. Les écrans sont l'endroit où la logique du jeu se produit. Donc, longue réponse courte - non, je ne pense pas que ce soit une mauvaise idée en théorie, faites juste attention à ce que vous faites en statique. Une fois que vous allez de l'avant et que vous faites quelque chose de statique, c'est un travail énorme si vous changez d'avis.

Clémence
la source
0

Les points soulevés ici sont tous bons. D'après mon expérience (qui est certes plus axée sur les applications professionnelles que sur les jeux), il existe de grandes utilisations pour les classes statiques et les membres et je les ai utilisées à plusieurs reprises. J'ai découvert qu'au fur et à mesure que les exigences et la complexité augmentent, je finis par recycler ces classes statiques et les convertir en classes d'instance et commencer à les transmettre.

Le point que je voudrais faire est que, si l'utilisation d'une classe statique vous aide à sortir ce jeu, allez-y, mais faites toujours les bonnes choses: implémentez une interface ou une classe de base afin qu'il soit plus facile de l'extraire et de la convertir plus tard à une classe d'instance.

Une once de prévention vaut une livre de guérison, alors assurez-vous que votre classe statique ne vous attache pas, ce qui rend difficile le changement. Il est assez facile de refactoriser une méthode à l'aide d'une classe statique qui implémente une interface afin qu'elle accepte un nouveau paramètre d'interface et utilise cette interface à la place de la référence de classe statique.

Nate
la source
0

Oui, c'est généralement toujours une mauvaise idée.

Transformer des objets contenant des données changeantes (c'est-à-dire tout sauf des constantes en lecture seule et des tables de recherche) en classes statiques est un bon point de départ.

  1. Il favorise les dépendances aléatoires qui tuent la modularité et entravent la réutilisation du code. Supposons que vous vouliez écrire un éditeur pour votre jeu - vous auriez soudain beaucoup de classes qui pleurent et Game1que vous ne pouvez pas facilement déplacer dans une bibliothèque partagée.

  2. Votre code devient impossible à tester. Les tests unitaires fonctionnent en isolant les classes individuelles des autres en se moquant ou en simulant leurs dépendances (qui doivent être aussi réduites que possible). Toute classe statique est un handicap car elle peut être consultée à tout moment, reporter l'état sur plusieurs tests ou nécessiter d'être initialisée avant que les tests puissent réussir.

  3. Il cache les dépendances. Tout comme l'anti-modèle de fournisseur de services (également utilisé par XNA, Game.Services), vos classes peuvent choisir des dépendances que vous ne voyez pas à l'extérieur.

Cette approche devient particulièrement toxique si l'on combine des classes statiques avec des appels de train de marchandises (choses semblables Game.Instance.ActorManager.Enemies.FindInRange(10)- ainsi appelées en raison des symboles enchaînés ressemblant à des wagons de train), où les composants nécessitent soudainement non seulement une Gameclasse, mais aussi une Instancepropriété statique qui renvoie quelque chose avec une ActorManagerpropriété qui a une Enemiespropriété qui renvoie un objet avec une FindInRange()méthode.

La seule excuse que j'accepterais pour écrire des classes statiques mutables serait celle qui est toujours en cours d'apprentissage et qui n'a pas encore la capacité d'appliquer systématiquement un bon design et un œil exercé pour repérer les mauvais choix.

Cygon
la source