Mises à jour des objets, internes vs externes?

8

Le titre est un peu déroutant, mais je n'ai pas pensé à expliquer ma question en une courte phrase. Voici donc:

Chaque fois que j'écris des moteurs de jeu, qu'ils soient basés sur la physique / les tuiles, etc., j'arrive toujours au point où je ne sais pas comment je dois gérer les choses. Les entités dans le monde devraient-elles se débrouiller seules, ou un système mondial devrait-il les gérer?

Voici un exemple simple: déplacer des objets. Si chaque objet voit le monde autour de lui (vérifiez les collisions) et se déplace en fonction de cela.

[Remarque, il s'agit d'un jeu basé sur des tuiles où l'objet se déplace par tuile, donc je n'utilise pas la physique pour passer d'une tuile à une autre]

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            if (world.getTile(location) != solid && world.objAtTile(location) == null)
            {
                Tweener.addTween(this, location);
            }
          }
        }

Ou le mouvement de chaque objet doit-il être manipulé dans le monde, où le monde vérifie tout?

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            world.moveTo(location);
          }
        }

public class World
{

    public void moveObject(GameObject obj, Vector2 location)
    {
      //called from object

      if (getTile(location) != solid && objAtTile(location) == null)
         {
                Tweener.addTween(obj, location);
         }
    }
}

Cela n'a pas vraiment d'importance pour cet exemple, je suppose, mais je peux me voir avoir des ennuis plus tard. Merci d'avance.

omgnoseat
la source
1
Plus à la question, devrait Actorsavoir worlddu tout?
deceleratedcaviar
1
Je pense que vous confondez les objets avec les composants et cela confond la question de savoir qui fait quoi. Il peut s'agir d'un problème sémantique car Component est un terme fortement surchargé. Je pense que si vous clarifiez ce qu'est un objet, ce que vous entendez par composant et comment vous organisez les petits moteurs qui font réellement le travail, vous pouvez répondre à votre propre question.
Patrick Hughes
1
Je dois convenir avec les autres que vous demandez si l'objet de jeu se déplace lui-même ou si le monde déplace l'objet de jeu. Le code ci-dessus ne m'amène pas à croire que vous voulez vraiment dire un système de type de composant et peut donc être trompeur d'avoir dans le titre de votre question.
James
J'ai utilisé des termes trompeurs maintenant que vous en parlez. Va l'ajuster maintenant! Edit: Voir qu'il a déjà été changé, merci!
omgnoseat
@daniel Les acteurs doivent clairement connaître le monde qui les entoure afin de se déplacer efficacement, bien que je conçoive généralement autour d'un conteneur qui encapsule les deux, mais ni l'un ni l'autre ne sait. par exemple. Le monde contient à la fois acteur et niveau; L'acteur connaît Level (ou plutôt on lui parle de Level si nécessaire, mais pas une référence permanente) mais pas de World.
jhocking le

Réponses:

2

Je vois que vos exemples sont en Java, mais vos balises ne spécifient aucune langue. En C ++, la réponse n'est ni l'un ni l'autre - vous ne devriez pas utiliser de fonction membre pour cela!

void move_to(actor *a, world *w, vec2 location);

la source
4
Je dois dire un grand fan des livres que l'auteur de l'article a écrits. Cependant, le raisonnement de l'article est, pour autant que je sache, une bonne théorie mais pas un code pratique. En déplaçant des méthodes comme celles-ci hors des objets auxquels elles appartiennent, vous ajoutez plus d'emplacements pour rechercher les fonctionnalités qui les concernent, ce qui ne cause que de la confusion et des niveaux plus élevés de maintenance requise. Juste ma vue, donc pas de + ni de -. Seulement deux cents.
James
1
Aussi, je dois dire que cela ressemble à C # avec l'héritage en utilisant: ClassName au lieu d'étend ClassName.
James
C'est un pseudo code basé sur C #, mais cela ne devrait pas être pertinent pour ma question :)
omgnoseat
1
@omgnoseat: C'est pertinent parce que le conseil est impossible dans un langage sans fonctions nues, et son utilité est réduite dans n'importe quel langage sans ADL. Une bonne architecture n'est pas indépendante du choix de la langue.
2
@James: Il n'y a rien de non-OO dans les fonctions nues, si les fonctions elles-mêmes invoquent des méthodes qui suivent les principes de conception OO. C'est le point de l'article. (OO n'est pas non plus synonyme de bon design. Si un design clair ou simple nécessite que vous n'utilisiez pas OO, abandonnez OO, pas le design.)
1

Il n'y a pas de réponse simple.

Comme avec la plupart des choses dans la programmation, c'est un compromis. Donner plus de puissance aux objets individuels les rend plus grands - et donc plus lents - mais rend le moteur plus facile à comprendre et à étendre. Avoir une méga-classe qui peut tout gérer ensemble pourrait être plus rapide, mais au prix d'avoir une méga-classe; c'est-à-dire qu'il est généralement considéré comme une mauvaise forme de créer des classes supermassives.

J'ai lu quelques articles sur la conception pilotée par les composants et les données, où vous avez une seule classe qui représente tous les objets d'un certain type, stockant leurs données dans des listes et ne faisant circuler que les index pour obtenir les propriétés d'un objet individuel. Bien que je puisse voir cela comme un type d'architecture viable, je le sens plutôt vis à vis du point entier d'orientation de l'objet, qui a également obtenu sa juste part de critiques.

Je recommande personnellement de donner plus de puissance aux objets. Cela a plus de sens dans un langage orienté objet et (j'imagine) plus facile à comprendre et à maintenir au fil du temps.

Quasiperfect
la source
Vous sous-estimez quelque peu les choses en disant que le style de conception basée sur les composants et les données que vous avez décrit "vis avec tout le point d'OO" - ce n'est pas du tout OO . Au moins comme décrit dans «Les systèmes d'entité sont l'avenir du développement de MMOG» (lié dans la réponse de Pek), les systèmes d'entité sont un paradigme de programmation complètement différent et si vous vous trouvez à essayer de rendre vos composants ou entités OO au-delà de la simple commodité de l'emballage, vous ' re Doing It Wrong.
Dave Sherohman
6
Ils sont parfaitement orientés objet. Ce n'est tout simplement pas l'OO auquel la plupart des gens sont habitués, mais ça va. L'orientation objet consiste à coupler l'état avec les méthodes qui opèrent sur cet état, c'est tout. Cela n'exige pas que chaque objet soit un objet de la vie réelle ou quelque chose comme ça.
Kylotan
@Kylotan: Encore une fois, je parle spécifiquement de modèles tels que ceux décrits dans "Entity Systems sont l'avenir du développement MMOG", où les composants sont des données stupides exploitées par des "systèmes" externes. Ce ne sont pas des objets car ils n'ont aucun comportement / méthode; ce sont des relations (pensez aux lignes de base de données ou aux structures C). Une équivalence erronée entre la POO et l'utilisation quotidienne de "l'objet" n'a rien à voir avec cela. Extrait de la partie 3: «Je suis vigoureusement contre l'utilisation de la POO n'importe où dans une implémentation ES; il est trop facile de se faufiler dans la PO où elle est inappropriée et de se faire illusion en pensant que c'est une bonne idée.
Dave Sherohman le
Je connais l'article, mais ce n'est qu'une opinion d'une personne sur la façon dont ces choses devraient être faites - ce n'est pas la manière standard, ou nécessairement la meilleure, donc il n'est pas correct de dire que la conception axée sur les composants est complètement différente paradigme de programmation. Il est parfaitement possible - et beaucoup plus courant - d'implémenter une architecture basée sur des composants avec du code OO, et l'utilisation du code OO n'en endommage pas plus la "composante" que d'utiliser des procédures stockées endommage l'aspect relationnel d'une base de données .
Kylotan
@Dave, cette question ne concerne en aucun cas les systèmes à composants d'entité. ES ou la conception basée sur les données ne sont pas non plus OO, c'est une erreur courante, mais grave, à supposer. si vous cherchez sur Google, vous trouverez de bons articles qui découvrent ce mythe. Cependant, cette question concerne les principes OO généraux de la conception de vos objets, les modèles de conception de niveau supérieur ne répondent pas du tout à cette question.
Maik Semder
0

Je mets à jour ma réponse parce que beaucoup de choses n'étaient pas claires avant les commentaires. Veuillez me dévoiler pendant que j'explique mes pensées.

En général, deux aspects clés à considérer dans toute conception sont la cohésion et le couplage . Nous savons tous que nous avons besoin d'une forte cohésion et d'un faible couplage pour pouvoir réaliser une conception plus réutilisable et extensible.

Donc, si le monde doit tout gérer, cela signifie qu'il a une faible cohésion et un couplage étroit (car il doit tout savoir et tout faire). Cependant, c'est également le cas lorsqu'une entité de jeu doit tout faire. Mettre à jour son emplacement, rendre sa texture, etc. etc.

Ce qui vous intéresse vraiment, c'est de créer des systèmes qui se concentrent sur un aspect de l'entité. Par exemple, une entité de jeu pourrait avoir une texture, mais un rendu serait responsable de rendre cette texture à l'écran. Le Renderer ne se soucie pas des autres propriétés de l'entité.

En allant un peu plus loin, une entité de jeu est simplement un sac de propriétés. Ces propriétés sont manipulées par des systèmes qui se concentrent sur des propriétés spécifiques. Et c'est là qu'interviennent les systèmes d'entités basés sur les composants (CBES), où propriétés = composants.

Plus précisément, CBES avec des systèmes (ou sous- systèmes ). Cette conception a tendance à avoir quelques systèmes qui se concentrent sur des composants spécifiques d'une entité sans se soucier des autres composants de l'entité. De plus, les systèmes sont couplés uniquement avec les informations dont ils ont besoin pour traiter ces composants.

Prenons votre exemple. Étant donné que l'entrée de l'endroit où déplacer l'entité est basée sur le contrôleur du joueur, vous auriez probablement un PlayerControllerSystem. Ce système contrôlerait, à part bien d'autres choses, le composant de position de l'entité. Dans ce cas, le PlayerControllerSystem aurait besoin de connaître le Level et le PositionComponent. Si plus tard vous décidez d'ajouter la détection de collision, vous créeriez un CollisionSystem qui utiliserait à nouveau la position des entités, mais cette fois pour calculer les boîtes englobantes (ou vous pourriez avoir un BoundingBoxComponent, votre appel). Le fait est que vous pouvez facilement activer ou désactiver le comportement (même à la volée) en ajoutant / supprimant simplement des composants. Ainsi, plus de comportement signifie que plus de systèmes manipulent les composants d'une entité, mais ils sont tous dans une classe bien définie avec un faible couplage. Vous voulez des scripts? Ajoutez un composant ScriptComponent. BAM! Vous venez d'ajouter des capacités de script avec 2 classes. La physique? Du son? Encore le même.

Donc, la raison pour laquelle je préconise CBES avec les sous-systèmes est qu'il est parfaitement OO et un système global facilement maintenable / extensible. L'ajout d'un comportement à une entité est aussi simple que de décider quelles données ce comportement a besoin et quelles entités en ont besoin.

Pour plus d'informations sur les systèmes d'entités basés sur des composants avec des sous-systèmes, il existe une excellente série de billets de blog par T = Machine chez Entity Systems qui sont l'avenir du développement MMOG . L'auteur est même allé jusqu'à créer un wiki pour collecter diverses implémentations nommé Entity Systems Project

Un poste général (et bien connu) sur les systèmes d'entités basés sur les composants en général est Evolve your hierarchy qui a créé le système pour Tony Hawk Pro.

Enfin, si vous cherchez une bibliothèque avec un exemple de code, n'allez pas plus loin que la bibliothèque Artemis . Artemis est principalement en Java mais voici un port en C # (que j'utilise actuellement dans mon projet XNA).

pek
la source
2
-1, car cela ne résout pas le problème, le déplace simplement. Il n'aura toujours pas de réponse claire quant à l'objet qui prend la décision, qu'il soit composé de composants ou non.
Kylotan
1
Le deuxième lien fournit un didacticiel détaillé expliquant pourquoi le comportement des entités de jeu doit être externalisé vers Entity Systems. Artemis suit exactement la même architecture.
pek
Le deuxième lien est un article d'opinion. Les composants sont préférés par beaucoup, mais ils ne sont pas une solution à tous les problèmes, et ils n'ont certainement pas de solution intrinsèque à celui-ci.
Kylotan
La réponse la plus votée dans cette question commence "Il n'y a pas de réponse simple. Comme avec la plupart des choses dans la programmation, c'est un compromis." Le deuxième lien fournit l'une des nombreuses solutions. En fait, il préconise l'exact opposé de cette réponse. Je devrais peut-être modifier ma réponse pour la rendre plus claire. Mais là encore, peut-être que cela ne changera pas les votes négatifs: P
pek
@pek: Mon downvote est parce que "utiliser des composants" n'est pas une réponse à cette question. J'utilise des composants et je recommande le modèle de composant, mais "utiliser un système d'entités basé sur les composants" n'est pas une réponse à tous les problèmes de développement de jeux, ni même d'architecture logicielle de jeu - cette question se pose tout de même pour les composants ou l'héritage hiérarchies ou types d'entités statiques totalement indépendants!
0

Je vais généralement avec un design où les objets se gèrent eux-mêmes (c'est à cela que servent les méthodes, après tout) mais le monde de base a des listes de tous les objets et il utilise ces listes pour les coordonner. Donc quelque chose comme:

class World {
  var walls = [];
  var actors = [];
  function update() {
    for each (actor in actors) {
      actor.update(walls);
    }
  }
}

class Actor {
  function update(walls) {
    this.move();
    for each (wall in walls) {
      this.collide(wall);
    }
  }
}
jhocking
la source
0

Gardez-le au sec, timide et dites à l'autre gars.

Il vaut mieux demander au monde de déplacer votre acteur que de demander au monde si vous pouvez vous déplacer où vous voulez aller. De cette façon, vous pouvez changer facilement l'algorithme de recherche de chemin dans la classe mondiale et autres. Bien sûr, vous pouvez simplement laisser cela à une classe de base pour l'acteur, mais c'est la direction que je prendrais et la raison.

Daniel Carlsson
la source
-1

EDIT: Réécrit en raison de commentaires indiquant que je n'avais pas tracé la ligne assez clairement pour cette réponse à la question d'origine.

J'aimerais clarifier un peu plus la question si possible. La logique qui agit sur un objet doit-elle être interne ou externe à cet objet? La dernière partie de l'article mentionne spécifiquement la longévité du design comme base pour poser la question, afin d'éviter des problèmes plus tard.

Ma réponse simple de haut niveau est de garder toute la logique qui agit sur un objet dans cet objet.

Vous n'avez pas besoin du monde pour déplacer un objet, tout ce dont vous avez besoin est de l'objet à déplacer et du vecteur représentant l'emplacement pour y accéder. Le monde peut entrer en jeu lorsqu'une destination est choisie ou lorsqu'une réaction à l'environnement est requise en raison d'une collision, mais celles-ci sont en dehors de l'exemple donné pour travailler.

Pour répondre à la partie sous-jacente de la question et atteindre la longévité de la conception, je suggère une architecture orientée composants. Les architectures de composants décomposent un objet en ensembles discrets de données et de fonctionnalités (en supposant que vous allez avec ma réponse ci-dessus qui indique de garder la logique avec les données). Si votre structure ressemble à CEntity-> CHuman-> CSoldier-> CPlayerCharacter, vous rencontrerez invariablement des problèmes où vous devrez modifier une logique et en fonction de son emplacement dans cet arbre (combien d'autres types d'humains y a-t-il par exemple?) il peut avoir des effets de balayage sur plusieurs types d'objets.

Un système de composants aurait à la place un ensemble d'interfaces qui définissent ce que l'objet CEntity est composé comme ICompRenderable, ICompMoveable, ICompHealth, ICompInventory et ainsi de suite. Où vous auriez CCompMoveableHuman et éventuellement un CCompMoveableSoldier et CCompMoveablePlayer pour garder leurs modèles de mouvement individuels séparés. Disons que le soldat est modifié pour fonctionner en formations. Cette modification n'affectera que les entités créées à l'aide de ce composant.

Donc, pour résumer, je vous suggère de contenir la logique avec les données auxquelles la logique s'applique. Je recommande également de diviser les objets en composants discrets pour réduire le "Où dois-je mettre cela?" questions et assurer la stabilité dans l'avenir avec la facilité de maintenance et son extensible.

J'espère que cela t'aides.

James
la source
J'ai examiné le modèle de composant au cours des dernières heures. (les liens de pek sont très sympas) .Mais on ne sait toujours pas où le "comportement" devrait avoir lieu. Il est clair qu'une entité a différents composants pour l'entrée, le rendu, la physique, mais si j'ai bien compris, les composants ne contiennent que les données nécessaires pour pouvoir fonctionner, mais ne contiennent pas réellement l'implémentation. Revenons au déplacement; comment dois-je faire pour déplacer une entité à l'aide des composants? Dois-je étendre le composant d'entrée et coder l'implémentation là-bas? Ou autre chose gérer l'implémentation?
omgnoseat
Pour moi, je garde la logique dans les objets, mais je fais en fait un système de composants au-dessus de la conception orientée données, ce qui signifie que la plupart de mes objets ne sont en fait que la logique qui est mappée à des emplacements à l'intérieur des données pour un traitement rapide contigu ... Et à la fin de la journée, apprenez un modèle de conception à la fois: D Quant au -1, j'apprécierais de savoir pourquoi cela a été étiqueté comme ça, même si c'est juste 'j'aime mieux ma réponse' que j'aimerais quand même savoir pourquoi.
James
1
@James, assez bien. J'ai rétrogradé parce que les systèmes à composants d'entité ne répondent pas à la question d'origine. Un composant de position peut encore se déplacer lui - même ou le monde pourrait itérer sur toutes les composantes de position et de les déplacer. La même raison pour laquelle Kylotan a rejeté la réponse de Pek, alors j'ai pensé que la raison -1 était évidente. Et même s'il serait obligatoire pour un système de composants de se déplacer lui-même (ce qui n'est pas le cas), ce ne serait toujours pas une réponse, juste un cas d'utilisation pour 1 des options. Mais la question portait sur les raisons d'utiliser l'un ou l'autre, leurs avantages et inconvénients. La réponse ne couvre pas cela.
Maik Semder
@Maik Semder. Merci pour les commentaires. J'ai réécrit la réponse pour essayer de tracer les lignes plus clairement à la question initiale et la motivation globale pour elle en premier lieu comme indiqué à la fin de la question.
James
@James, merci d'avoir pris le temps de modifier la réponse en réponse à mon commentaire, très apprécié. La réponse proposée pour "garder toute la logique qui agit sur un objet à l'intérieur de cet objet" défait une caractéristique essentielle de l'OO, à savoir l'encapsulation. Comme le montre le lien de Joe, l'utilisation de fonctions non membres non amis augmente le niveau d'encapsulation d'un objet. De plus, il introduit une méthode claire pour mesurer réellement l'encapsulation. Mettre la fonction de déplacement dans le monde ou l'acteur diminue l'encapsulation de la conception, ce qui rend le code moins flexible et plus difficile à maintenir.
Maik Semder
-1

Je vous recommande d'essayer de lire sur les architectures basées sur les composants. Il y a pas mal de billets de blog, de présentations et d'écrits à leur sujet qui peuvent faire un meilleur travail que jamais.

AltDevBlogADay a pas mal de messages à ce sujet, un très bon étant cette série sur les entités de jeu: http://altdevblogaday.com/2011/07/10/the-game-entity-–-part-ia-retrospect/ Il y a plusieurs parties qui se concentrent sur le problème que vous essayez de résoudre.

Kyle
la source