Questions concernant l'architecture des jeux avec XNA

12

J'ai donc enfin pu jouer avec XNA et jouer avec la création d'un jeu 2D (j'ai un tas d'actifs artistiques d'un ami qui l'a développé sur iOS)

Beaucoup de choses semblent faciles à faire et sortent de la boîte, mais je suis perplexe pour un tas de choses car la plupart de la littérature (les livres que j'ai achetés par exemple) ne font pas trop attention à la 2D.

J'apprécierais vraiment toute clarification ou être pointé vers plus d'informations sur les quêtes suivantes:

  1. Quel est l'intérêt d'un Game Service? Je comprends tout l'idiome de l'enregistrement d'un objet en tant que service afin que tout autre GameComponent puisse le saisir, mais comment cela se fait-il simplement en le rendant public ou statique? Par exemple, mon livre recommandait d'enregistrer l'objet SpriteBatch dans la classe Game.cs. Je ne sais pas comment cela est préférable à simplement le rendre public / statique car il ne devrait y avoir qu'une seule instance de Game de toute façon (singleton)?

  2. Je ne sais pas quand je dois hériter de GameComponent ou RenderableGameComponent. J'essaie de suivre une conception de gestionnaire / contrôleur, de sorte que toutes les entités sont créées / détenues par un seul gestionnaire et les mêmes pour d'autres choses. J'ai actuellement chaque gestionnaire / contrôleur hérité de GameComponent, mais comment cela se fait-il que l'objet Game possède tous les gestionnaires et appelle manuellement la mise à jour sur eux et dessine?

  3. J'ai remarqué que Initialize est appelé avant ContentLoad (), j'ai trouvé cela ennuyeux car dans mon Initialize, c'est là que j'aimerais créer certaines de mes entités (c'est-à-dire Sprite, Player, etc.), mais je ne peux pas leur donner leurs données chargées SpriteSheets ou Textures depuis l'appel à les charger n'a pas encore eu lieu. Suis-je peut-être en train d'initialiser incorrectement ou est-ce que les gens attribuent simplement la texture plus bas dans ContentLoad?

Celles-ci semblent être mon plus grand " WTF " de ne pas vraiment comprendre

Setheron
la source

Réponses:

11

La réponse à votre question est simplement: faites tout ce qui fonctionne. Idéalement, faites ce qui est simple et fonctionne. Souvent, l'utilisation de l'architecture intégrée n'est pas simple car, comme vous le constatez, vous devez sauter à travers des cerceaux pour structurer votre jeu comme vous le souhaitez.

Pour répondre à la première question, je vous renvoie à ma réponse à la question "Pourquoi utiliser les services?" . La réponse courte est que les services sont un bon moyen d'éviter les problèmes de couplage (versioning, dépendance, extensibilité) que vous ne rencontrerez jamais dans un jeu autonome . La plupart du temps, il est plus simple de simplement devenir membre public(et peut-être même staticsi vous êtes pressé) et de vous inquiéter de problèmes plus intéressants.

Pour répondre à votre deuxième question, je vous renvoie à ma réponse à la question "Quels sont les inconvénients de l'utilisation de DrawableGameComponent pour chaque instance d'un objet de jeu?" ainsi que mes réflexions sur l'architecture du jeu . La réponse courte est: il n'y a aucun avantage à utiliser le GameComponentover simplement en créant vos propres classes et en appelant des méthodes comme Drawet Updatevous - même. Si GameComponentcorrespond exactement à votre architecture souhaitée, utilisez-la certainement - mais presque toujours non.

L'utilisation de services et de composants ne devient vraiment intéressante que si vous créez une bibliothèque pour une consommation tierce. XNA lui-même fait cela - il l'a fait IGraphicsDeviceServiceet GamerServicesComponent, par exemple. Ceux-ci répondent à des exigences de découplage spécifiques que vous ne rencontrez généralement pas lors du développement d'un jeu.

Enfin, la réponse à votre troisième question est assez simple: créez simplement vos entités de jeu dans LoadContent. Il n'y a rien de particulièrement spécial Initialize.

Il convient de souligner que l'ensemble de l' Microsoft.Xna.Framework.Gameassemblage est facultatif . Il fournit un point de départ extrêmement utile - mais il ne doit en aucun cas être considéré comme «la seule bonne façon» de faire les choses.

Andrew Russell
la source
Une façon très intéressante de le voir. Beaucoup plus réaliste et terre à terre que ma réponse. Bien mérité +1, monsieur.
Jesse Emond
J'ai une autre question! Qu'en est-il de l'origine lorsque vous dessinez pour un Texture2D. Est-il courant de placer l'origine au milieu en bas de la texture? J'essaie de faire des animations, et je trouve que l'origine à (0,0) provoque un léger décalage de la texture si la largeur et la hauteur ne sont pas les mêmes
Setheron
@Setheron: Vous devez vraiment créer une nouvelle question - car cela n'a aucun rapport avec la question d'origine. Je vais revenir sur la modification que vous avez apportée à cette question. L'origine de SpriteBatch.Drawest spécifiée en coordonnées de pixels de texture par rapport au coin supérieur gauche de la texture (ou du rectangle source, si vous en utilisez un).
Andrew Russell
1
@Andrew: J'ai récemment refactorisé mon jeu afin qu'il soit entièrement basé sur les services au lieu de public/ staticproperties. Pourquoi? Testabilité. Il est presque impossible de changer les choses avec l'approche de la propriété, alors que c'est trivial si tout est initialisé avec un IServiceProviderqui peut être rempli de tout ce dont la classe a besoin par votre méthode de test. Cela évite également la nécessité d'instancier l' Gameobjet lui-même dans votre test, ce qui devient très rapidement désordonné.
Matthew Scharley
En passant, j'ai encore beaucoup de propriétés publiques sur l' Gameobjet. Il se trouve qu'ils sont simplement accessibles via des interfaces qui sont poussées dans Game.Serviceslesquelles sont ensuite transmises à tout pour obtenir à nouveau ce dont elles ont besoin.
Matthew Scharley
3

Pour votre première question, je dois admettre que je ne connais pas vraiment la réponse réelle. Je suppose que ce serait pour la même raison que le singleton est généralement un mauvais modèle de conception. Je vous renvoie à une citation de ce lien :

La première à laquelle nous avons pensé (et l'une des raisons de l'introduction des services) était de rendre une référence GraphicsDevice disponible dans un jeu. Au départ, nous avions le jeu propriétaire du GraphicsDevice et l'exposions via une propriété comme Game.GraphicsDevice. Le problème était que cela liait étroitement le GraphicsDevice au jeu, ne permettant pas à quelqu'un d'autre de «posséder» le périphérique (comme un moteur de rendu) et empêchant quelqu'un d'utiliser un futur GraphicsDevice mis à jour sans expédier une nouvelle version du jeu qui ne t être rétrocompatible.

Pour votre deuxième question, je suppose que l'utilisation de composants comme celui-ci serait plus utile si vous suiviez une approche basée sur les composants à la place, comme si vous aviez une liste de Spritecomposants qui sauraient comment se dessiner et se mettre à jour au lieu d'un gestionnaire qui sait mettre à jour et dessiner chaque sprite. Je suis d'accord, ça sonne pareil mais je préfère une conception basée sur les composants parce que j'aime vraiment l'approche orientée objet qu'elle a.

Pour votre troisième question, oui, vous devez charger n'importe quelle forme de contenu (ressources, polices, etc.) dans la méthode LoadContent. En ce qui concerne l'initialisation, vous créez généralement l'objet Player dans la fonction Initialize, puis chargez son contenu dans LoadContent .. Ou vous pouvez simplement tout faire dans LoadContent si vous le souhaitez.

Jesse Emond
la source