Je suis très nouveau dans le développement de jeux, mais pas dans la programmation.
Je joue (encore) avec un jeu de type Pong en utilisant l' canvas
élément JavaScript .
J'ai créé un Paddle
objet qui a les propriétés suivantes ...
width
height
x
y
colour
J'ai aussi un Pong
objet qui a des propriétés telles que ...
width
height
backgroundColour
draw()
.
La draw()
méthode consiste actuellement à réinitialiser le canvas
et c’est là qu’une question a été soulevée.
Si l' Paddle
objet a une draw()
méthode responsable de son dessin, ou si l' objet draw()
de l' Pong
objet est responsable de dessiner ses acteurs (je suppose que c'est le terme correct, corrigez-moi si je me trompe).
Je pensais qu'il serait avantageux pour le Paddle
de se dessiner lui-même, comme j'instancie deux objets, Player
et Enemy
. S'il n'y avait pas dans les Pong
« s draw()
, je dois écrire un code similaire deux fois.
Quelle est la meilleure pratique ici?
Merci.
la source
Réponses:
Faire dessiner des acteurs eux-mêmes n'est pas une bonne conception, pour deux raisons principales:
1) cela viole le principe de responsabilité unique , car ces acteurs avaient vraisemblablement un autre travail à faire avant d’y avoir inséré le code.
2) cela rend l'extension difficile; si tous les types acteur met en œuvre son propre dessin, et vous devez changer la façon dont vous dessinez en général , vous pouvez avoir à modifier beaucoup de code. Éviter le recours excessif à l'héritage peut atténuer ce problème dans une certaine mesure, mais pas complètement.
Il est préférable que votre moteur de rendu gère le dessin. Après tout, c’est ce que cela signifie d’être un moteur de rendu. La méthode draw du rendu doit prendre un objet "render description", qui contient tout ce dont vous avez besoin pour rendre une chose. Références à des données géométriques (probablement partagées), à des transformations spécifiques à une instance ou à des propriétés matérielles telles que la couleur, etc. Il dessine ensuite cela, et se moque de ce que la description de rendu est supposée "être".
Vos acteurs peuvent alors conserver une description de rendu qu'ils créent eux-mêmes. Étant donné que les acteurs sont généralement des types de traitement logique, ils peuvent appliquer des modifications d'état à la description de rendu, si nécessaire. Par exemple, lorsqu'un acteur subit des dommages, il peut définir la couleur de sa description de rendu en rouge pour l'indiquer.
Ensuite, vous pouvez simplement itérer chaque acteur visible, mettre en file d'attente leurs descriptions de rendu dans le rendu, et le laisser faire son travail (vous pouvez, en gros, généraliser davantage).
la source
actor.draw(renderer,x,y)
querenderer.draw(actor.getAttribs(),x,y)
.struct RenderDetail { glVAO* vao; int shader; int texture; Matrix4f* transform; }
plus ou moins pour mon rendu. De cette façon, le rendu ne se soucie pas de ce que les données représentent, il les traite simplement. Sur la base de ces informations, je peux alors également décider de trier l'ordre des appels de tirage afin de réduire le nombre total d'appels GPU.Le modèle de visiteur peut être utile ici.
Ce que vous pouvez faire est d'avoir une interface de rendu qui sache dessiner chaque objet et une méthode "dessine-toi" dans chaque acteur qui détermine quelle méthode de rendu (spécifique) à appeler, par exemple:
De cette façon, il est toujours facile de porter sur une autre bibliothèque graphique ou un autre framework (j’avais jadis porté un jeu de Swing / Java2D vers LWJGL et j’étais très heureux d’avoir utilisé ce modèle au lieu de passer à un autre
Graphics2D
.)Il y a un autre avantage: le moteur de rendu peut être testé séparément de tout code d'acteur.
la source
Dans votre exemple, vous voudriez que les objets Pong implémentent draw () et se rendent eux-mêmes.
Bien que vous ne remarquiez aucun gain significatif dans un projet de cette taille, la séparation de la logique de jeu et de leur représentation visuelle (rendu) est une activité utile.
J'entends par là que vos objets de jeu pourraient être update (), mais ils n'ont aucune idée de la façon dont ils sont rendus, ils ne sont concernés que par la simulation.
Ensuite, vous auriez une classe PongRenderer () avec une référence à un objet Pong, puis elle se chargerait du rendu de la classe Pong (). Cela pourrait impliquer le rendu des Paddles ou la création d’une classe PaddleRenderer.
La séparation des problèmes dans ce cas est assez naturelle, ce qui signifie que vos classes peuvent être moins lourdes et qu'il est plus facile de modifier le rendu des choses, il n'est plus nécessaire de suivre la hiérarchie de votre simulation.
la source
Si vous deviez le faire dans le
Pong
'draw (), vous n'auriez pas besoin de dupliquer le code - appelez simplement la fonctionPaddle
' draw () pour chaque pagaie. Donc dans tonPong
tirage () tu auraisla source
Chaque objet doit contenir sa propre fonction de dessin qui doit être appelée par le code de mise à jour du jeu ou le code de tirage. Comme
Ce n'est pas un code mais juste pour montrer comment dessiner des objets.
la source