Un objet dans un jeu 2D doit-il se rendre?


16

Je fais un jeu de combat de rue en 2D qui n'est pas basé sur des tuiles. Habituellement, les gens recommandent que les entités soient données à un moteur de rendu qui les rend, pas elles-mêmes, mais il semble que l'inverse soit meilleur,

Pourquoi est-on meilleur que l'autre?

Merci


Pourquoi pensez-vous que l'inverse est meilleur?

1
@Martin car l'objet indiquera quel bitmap utiliser de toute façon, alors pourquoi ne pas simplement faire object-> render ();
jmasterx

Réponses:


11

Quelques considérations:

  • comme vous l'avez mentionné, chaque sprite devrait "faire allusion" au bitmap à utiliser, mais si l'entité doit se rendre. Quel serait ce «indice»? S'il s'agit d'une référence à un bitmap différent, une feuille de sprite, etc ... pour chaque sprite, alors vous pourriez finir par utiliser plus de mémoire que nécessaire, ou avoir des problèmes pour gérer cette mémoire. Un avantage d'un rendu distinct est que vous n'avez qu'une seule classe responsable de la gestion des actifs. Cela dit, dans un jeu de combat de type SF2, vous pourriez n'avoir que deux sprites;)

  • comme mentionné ailleurs, chaque fois que vous voulez changer votre API graphique, vous devez changer le code de tous vos sprites.

  • le rendu est rarement effectué sans référence à un contexte graphique. Donc soit il y a une variable globale qui représente ce concept, soit chaque sprite a une interface avec render (GraphicalContext ctx). Cela mélange l'API graphique et la logique de votre jeu (que certaines personnes trouveront non élégant) et pourrait entraîner des problèmes de compilation.

  • Personnellement, je trouve que séparer le rendu des entités individuelles est une première étape intéressante dans le sens de voir votre jeu comme un système qui n'a pas nécessairement besoin de graphiques du tout. Ce que je veux dire, c'est que lorsque vous mettez le rendu à l'écart, vous réalisez qu'une grande partie du gameplay se produit dans un "monde non graphique" où les coordonnées des entités, leurs états internes, etc. sont ce qui compte. Cela ouvre la porte à des tests automatisés, à un système plus découplé, etc.

Dans l'ensemble, j'ai tendance à préférer les systèmes où le rendu est effectué par une classe séparée. Cela ne signifie pas que vos sprites ne peuvent pas avoir certains attributs qui sont "graphiquement liés" (nom de l'animation, cadre d'animation, hauteur x largeur, id de sprite etc ...), si cela rend le rendu plus facile à écrire ou plus efficace.

Et je ne sais pas si cela s'appliquerait à la 3D (où la notion de maillage et la variable de coordonnées que vous utiliseriez seraient peut-être liées à votre API 3D; tandis que x, y, h, w sont à peu près indépendants de tout 2D API).

En espérant que cela aide.


11

Vous voulez que le système de rendu contrôle ce qui est dessiné quand. Si au contraire les sprites contrôlent le rendu, vous perdez beaucoup de gains d'efficacité et de flexibilité. Je suis d'avis que le contrôle du système de rendu entraîne un code plus propre.

Quelques avantages du rendu centralisé:

  • z-ordering:
    Si les objets du jeu eux-mêmes sont responsables du rendu, vous devrez vous assurer de les appeler dans le bon ordre. Sinon, les objets d'arrière-plan peuvent être dessinés sur les objets de premier plan.
    Avec le système de rendu sous contrôle, il peut choisir de trier tous les objets de rendu, détecter les superpositions au moment du rendu et simplement les rendre, ou tout simplement renoncer à tout ordonner ensemble. Le fait est que la décision peut être prise facilement maintenant.
  • batching:
    L'autre avantage évident de permettre au système de rendu d'être sous contrôle est le batching. Ici encore, le système de rendu a la possibilité de rendre par lots un sprite qui rend le partage une texture. Il peut utiliser le découpage en triangle pour tout rendre en un seul appel. Il peut être capable de mettre en cache certains calculs de rendu. Ou il pourrait simplement rendre chaque sprite tour à tour sans rien de tout cela. (Remarque: il est possible de batch lorsque chaque objet se rend, mais le problème est moins efficace et plus complexe).

La façon dont j'implémente cela dans mes jeux pour que les objets de jeu enregistrent les sprites qu'ils veulent dessiner avec le système de rendu. Lorsque l'objet ne veut plus que l'objet soit dessiné, il annule l'enregistrement du sprite ou le marque comme inactif.

Cela dit. S'il est plus facile que vos objets de jeu se rendent par tous les moyens, faites-le de cette façon. Il est beaucoup plus important de progresser et d'obtenir quelque chose / quelque chose de dessiné que d'avoir une architecture parfaite.


À propos de l'ordre z si les objets se dessinent eux-mêmes, un système ne peut pas décider de l'ordre d'appeler leur méthode de dessin? Je veux dire centralisé vs non centralisé ne semble pas faire de différence sur l'ordre z.
GorillaApe

3

Avertissement: votre question ne donne pas beaucoup de détails, je réponds donc par un principe général. Veuillez m'excuser si j'ai mal compris votre utilisation ou «rendu».

J'utilise généralement un objet externe pour rendre différents acteurs dans une scène comme un moyen d'encapsuler des propriétés et des méthodes au niveau de la scène en dehors des `` objets acteur '' individuels. Les objets de la scène ne doivent contenir que des méthodes et propriétés internes; ils ne devraient savoir que ce qu'ils sont eux-mêmes et ce qu'ils font. Vraisemblablement, ils seront influencés par d'autres objets dans le jeu ainsi que par l'entrée de l'utilisateur. Cela affectera comment / s'ils sont rendus à l'écran. Un «objet directeur» peut, par exemple, traduire la touche «w» pour sauter, puis dire à l'objet acteur .jump (). Une telle logique au niveau du réalisateur peut également dire aux acteurs d'entrer ou de sortir entièrement de la scène.

À la vôtre, David


Mais en ce sens, le réalisateur ne pouvait-il pas simplement dire acton-> setVisible (false); ?
jmasterx

Même dans le cas setVisible (false), c'est une entité externe qui fait le rendu en vérifiant la variable visible de l'acteur et en la rendant uniquement si elle est vraie.
Nav

Le simple fait de rendre un acteur invisible ne le supprime pas de la scène. Il doit également cesser de participer aux collisions, etc.
finnw

3

Que se passe-t-il si un jour vous souhaitez porter votre jeu vers une résolution différente (par exemple iPhone et amis). Ainsi, une propriété globale sur les modifications de rendu, comment mettre à jour facilement votre code?


3

Ce que j'ai utilisé était une conception basée sur l'observateur. Lorsque j'ai créé une instance d'une classe que je voulais rendre, un pointeur vers celle-ci a été stocké dans la classe centrale Renderer. Lorsque vous appelez RenderFrame(), le rendu dispose déjà de tous les objets existants dont il a besoin pour le rendu et a accédé à leurs propriétés pour le faire. Les classes elles-mêmes n'avaient aucune idée qu'elles allaient être rendues du tout. Cette API était agréable et propre et facile à utiliser.


1
+1 Intéressant. J'ai utilisé cette approche pour le son tout en utilisant le modèle de visiteur pour les graphiques. Je pensais que cela avait plus de sens pour le son car, bien que les graphiques et l'IA fonctionnent sur la même horloge, le mélangeur audio fonctionne sur un autre, donc un modèle d'événement est plus facile. De plus, ce n'est pas critique si un événement de mouvement (qui provoque le changement de panoramique / réverbération d'un canal audio) arrive quelques millisecondes en retard, mais il est critique si un sprite est dessiné dans le mauvais état.
finnw

2

En général, il s'agit toujours de la facilité de maintenance et de développement de votre code. Demain, vous comprendrez que vous n'aimez pas l'API graphique que vous utilisez actuellement et que vous souhaitez changer. Aurez-vous maintenant à parcourir toutes vos classes d'objets et à tout changer, ou avez-vous toujours besoin de changer votre code en un point central du projet?

Cela dépend de ce que font réellement vos objets lorsque vous appelez render (). Tant qu'ils enveloppent simplement les appels de méthode autour de votre moteur graphique, c'est très bien, car la distinction graphique <-> logique sera toujours donnée.

Par exemple, si vos méthodes render () sont essentiellement des méthodes de commodité et ressemblent à ceci:

void MyClass::render(const Graphics &g)
{
    g.draw(this);
}

ou

void MyClass::render()
{
   mySprite->render();
}

ou

void MyClass::render()
{
    mySprite->UseShader(thatshader);
    mySprite->render();
}

ou près de cela, je ne pense pas que ce soit un problème que ce soit.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.