9
votes

Quel est le moyen le plus élégant et efficace de modéliser une hiérarchie d'objet de jeu? (Design Bonchers)

J'ai le code suivant, réfléchissez à un tireur simple en C ++: xxx

deux problèmes avec ceci:

1, objets de jeu connaissant d'autres Objets de jeu.

Il doit y avoir une installation qui connaît tous les objets. Cela pourrait ne pas avoir à exposer tous les objets, il doit exposer une partie de celui-ci, en fonction des paramètres de l'entraîneur (position, pour une). Cette installation est censée être mondiale.

Les objets doivent savoir sur le monde qu'ils sont dans, pour interroger les informations de collision et d'autres objets.

Ceci introduit une dépendance où les deux objets «Et la mise en œuvre du monde doit accéder à l'en-tête de l'objet, alors que le monde n'inclut pas son propre en-tête directement plutôt que par Object.HPP (qui inclut à son tour World.HPP). Cela me fait me sentir mal à l'aise - je ne pense pas que World.CPP devrait recompiler après avoir effectué une modification à Object.HPP. Le monde n'a pas envie de fonctionner avec un objet. Il se sent comme une mauvaise conception - comment peut-il être corrigé?

2, polymorphisme - peut et doit-il être utilisé pour tout au-delà de la réutilisation de code et le regroupement logique des entités de jeux (et comment)? < / Strong>

Les ennemis, les balles et le joueur mettront à jour et rendu différemment, sûrement, d'où la fonctionnalité de mise à jour virtuelle () et de rendu () - une interface identique. Ils sont toujours conservés dans des listes séparées et la raison en est que leur interaction dépend de laquelle les deux objets interagissants sont - deux ennemis se rebondissent, une balle et un ennemi se détruisent etc.

C'est une fonctionnalité qui dépasse la mise en œuvre de l'ennemi et de la balle; Ce n'est pas ma préoccupation ici. Je pense qu'au-delà de leurs interfaces identiques, il existe un facteur qui sépare les ennemis, les balles et les joueurs, et cela pourrait et devrait être exprimé d'une autre manière, me permettant de créer une liste unique pour toutes les personnes - comme leur interface est identique!

Le problème est de savoir comment raconter une catégorie d'objet d'une autre si contenue dans la même liste. Typeid ou une autre forme d'identification de type est hors de question - mais quelle autre façon de le faire? Ou peut-être qu'il n'y a rien de mal à l'approche?


0 commentaires

4 Réponses :


5
votes

Ceci est probablement le problème le plus important que je rencontre lors de la conception de programmes similaires. L'approche que j'ai installée est de réaliser qu'un objet ne se soucie vraiment pas de l'endroit où il est en termes absolus. Tout cela se soucie de ce qui est autour de cela. En conséquence, l'objet World (et je préfère l'approche d'objet dans un singleton pour de nombreuses bonnes raisons que vous pouvez rechercher sur Internet) maintient où tous les objets sont, et ils peuvent demander au monde Quels objets sont à proximité, où d'autres objets sont par rapport à celui-ci, etc. World ne devrait pas se soucier du contenu de objet ; Il tiendra à peu près n'importe quoi, et l'objet SI-S définira comment ils interagissent les uns avec les autres. Les événements sont également un excellent moyen de gérer des objets interagissant, car ils fournissent un moyen pour monde pour informer un objet de ce qui se passe sans attentionné quel objet est.

Cacher des informations à partir d'un objet sur tous les objets est une bonne idée et ne doit pas être confondu avec cacher des informations sur tout Objet . Pensez en ce qui concerne les personnes - il est raisonnable pour vous de connaître et de conserver des informations sur de nombreuses personnes différentes, bien que vous ne puissiez trouver que les informations en les rencontrant ou en leur disant quelqu'un d'autre.

Modifier à nouveau:

D'accord. Il est assez clair pour moi ce que vous voulez vraiment, et c'est une expédition multiple - la capacité de gérer une situation polymorphiquement sur des types de nombreux paramètres à l'appel de la fonction, plutôt que d'une seule. C ++ ne supporte malheureusement pas de multiples enregistrements de manière native.

Il y a deux options ici. Vous pouvez essayer de reproduire plusieurs envisages avec une double envoi ou du motif de visiteur, ou vous pouvez utiliser dynamic_cast . Que vous voulez utiliser dépend des circonstances. Si vous avez beaucoup de types différents pour l'utiliser, dynamic_cast est probablement la meilleure approche. Si vous n'avez que quelques-uns, une double envoi ou le motif de visiteur est probablement plus approprié.


3 commentaires

Merci pour les deux premiers paragraphes; Cela a beaucoup de sens et a contribué à effacer ma tête. J'ai réécrit ma question pour clarifier ce que je voulais faire du polymorphisme.


Le motif des visiteurs est génial, merci de le pointer. Je suppose que les méthodes Onhit () sont analogues à la méthode de la visite () du modèle et des objets constitueraient leurs propres visiteurs, non?


Il a été difficile de choisir une réponse à accepter comme le meilleur, comme tous sont venus avec de bons points, mais aucun d'entre eux n'était vraiment tout autour. J'ai senti que le contour de la conception sur l'interaction de l'objet-World était le plus utile d'information et le plus pertinent pour ma question. -



6
votes

Je pense que vous voudriez remettre une référence au monde à l'objet de jeu. Ceci est un très beau principe de base de Injection de dépendance . Pour les collisions, le monde peut utiliser le <-href="http://fr.wikipedia.org/wiki/strategy_pattern" Rel="nofollow NOREFERRER"> STRATÉGIE PORTRATION pour résoudre la manière dont des types spécifiques d'objets interagissent. < / p>

Cela empêche la connaissance de différents types d'objets hors des objets principaux et l'encapsule dans des objets spécifiques à l'interaction.


2 commentaires

Est-ce une solution dommage (oo conception et performance-sage) au lieu de transmettre la référence au monde à chaque fois, stockez simplement un pointeur de membre statique au monde, accessible à tous les objets? (Pas sur la forme publique brute, il a été présenté, peut-être - pourrait être un pointeur protégé et une méthode statique publique pour la définir.)


La façon dont vous stockez la référence à l'objet mondial est à vous. Étant donné que ces objets ne seront probablement pas instanciés dans plusieurs mondes simultanément, le stockage de la référence sur la classe est probablement bien. L'idée principale est que le monde est toujours fourni aux objets individuels à l'heure d'instantiation, de sorte que si vous souhaitez avoir deux objets du même type dans différents mondes, l'API d'instance ne change pas et que le seul refactoring qui doit se produire est dans la mise en œuvre de l'objet lui-même.



3
votes

Les objets doivent savoir sur le monde Ils sont dans, interroger pour la collision informations et autres objets.

En bref - non, ils ne le font pas. Les classes comme le monde peuvent gérer la majeure partie de cela et que tout l'objet doit faire est de se comporter de manière appropriée lorsque le monde lui dit qu'il y a eu une collision.

Parfois, vous aurez peut-être besoin de l'objet d'avoir une sorte de contexte afin de faire un autre type de décision. Vous pouvez transmettre l'objet mondial à ce point si nécessaire. Cependant, Iinsta dame de passer le monde, il vaut mieux passer d'un objet plus petit et plus pertinent en fonction du type de requête en cours d'exécution. Il est probable que votre objet mondial effectue plusieurs rôles différents et que les objets n'ont jamais besoin d'un accès transitoire à un ou deux de ces rôles. Dans ce cas, il est bon de partager l'objet mondial en sous-objets, ou si ce n'est pas pratique, demandez-lui de mettre en œuvre plusieurs interfaces distinctes.


0 commentaires

0
votes

Après avoir donné beaucoup de pensée, je me suis rendu compte que, bien que les objets doivent avoir accès à un monde, c'est pas la responsabilité du monde de servir des objets à proximité à des objets. < p> C'est ce que j'avais l'arène non-objet (jamais instancié + tous les membres statiques, contient des listes des catégories d'objet requises - balles, ennemis, visuels, etc.). Cependant, il a introduit une structure de dépendance similaire que la liste des listes de catégories Dans le cadre du monde (c'est pourquoi il ne ressentait pas une bonne solution): xxx

donc, la solution ou ce qu'il semble être à ce stade, est Pour avoir l'intégralité de l'objet (catégorique) S non un niveau de compilation au-dessus ou au-dessous de la déclaration des objets, mais au même niveau . xxx < p> Même s'il y a d'autres en-têtes pour spécialiser les ennemis, les balles, etc. Les listes de leurs catégories (et des autres ") sont entièrement disponibles pour eux en incluant objet.HPP qu'ils doivent évidemment être à toute évidence.

sur le polymorphisme bit a Pourquoi les différentes catégories sont conservées dans des listes séparées: les classes de base des catégories d'objet (balle, ennemi, lecteur) peuvent fournir des "manipulateurs d'événements" pour frapper des objets de certains types; Ils ne sont toutefois pas déclarés au niveau de l'objet plutôt que sur le niveau de la catégorie. (Par exemple, nous ne nous soucions pas des collisions BUNLET-VS-BUNLET, elles ne sont pas vérifiées et non manipulées.) xxx

éditer, pour l'exhaustivité "Sake: xxx


0 commentaires