Disclamer: Je sais ce qu'est un modèle de système d'entité et je ne l' utilise pas.
J'ai beaucoup lu sur la séparation des objets et le rendu. À propos du fait que la logique du jeu doit être indépendante du moteur de rendu sous-jacent. C'est très bien et dandy et c'est parfaitement logique, mais cela provoque aussi beaucoup d'autres douleurs:
- besoin de synchronisation entre l'objet logique et l'objet de rendu (celui qui garde l'état de l'animation, les sprites etc)
- besoin d'ouvrir l'objet logique au public afin que l'objet de rendu lise l'état réel de l'objet logique (ce qui conduit souvent l'objet logique à se transformer facilement en un objet getter et setter muet)
Cela ne me semble pas être une bonne solution. D'un autre côté, il est très intuitif d'imaginer un objet comme sa représentation 3D (ou 2D) et également très facile à entretenir (et peut-être aussi beaucoup plus encapsulé).
Existe-t-il un moyen de maintenir la représentation graphique et la logique de jeu couplées (en évitant les problèmes de synchronisation) mais en éloignant le moteur de rendu? Ou existe-t-il un moyen de séparer la logique de jeu et le rendu qui ne cause pas les inconvénients ci-dessus?
(peut-être avec des exemples, je ne suis pas très bon pour comprendre les discussions abstraites)
la source
Réponses:
Supposons que vous ayez une scène composée d'un monde , d'un joueur et d'un boss. Oh, et c'est un jeu à la troisième personne, vous avez donc aussi un appareil photo .
Votre scène ressemble donc à ceci:
(Au moins, ce sont les données de base . La façon dont vous contenez les données dépend de vous.)
Vous ne voulez mettre à jour et rendre la scène que lorsque vous jouez au jeu, pas en pause ou dans le menu principal ... donc vous l'attachez à l'état du jeu!
Maintenant, votre état de jeu a une scène. Ensuite, vous voulez exécuter la logique sur la scène et rendre la scène. Pour la logique, vous exécutez simplement une fonction de mise à jour.
De cette façon, vous pouvez conserver toute la logique du jeu dans la
Scene
classe. Et juste à titre de référence, un système de composants d'entité pourrait le faire comme ceci à la place:Quoi qu'il en soit, vous avez maintenant réussi à mettre à jour votre scène. Maintenant, vous voulez l'afficher! Pour lequel nous faisons quelque chose de similaire à ce qui précède:
Voilà. Le renderSystem lit les informations de la scène et affiche l'image appropriée. Simplifiée, la méthode de rendu de la scène pourrait ressembler à ceci:
Vraiment simplifié, vous auriez encore besoin, par exemple, d'appliquer une rotation et une traduction en fonction de l'endroit où se trouve votre joueur et où il regarde. (Mon exemple est un jeu en 3D, si vous optez pour la 2D, ce sera une promenade dans le parc).
J'espère que c'est ce que vous cherchiez? Comme vous pouvez vous en souvenir avec ce qui précède, le système de rendu ne se soucie pas de la logique du jeu . Il utilise uniquement l'état actuel de la scène pour le rendu, c'est-à-dire qu'il en extrait les informations nécessaires pour le rendu. Et la logique du jeu? Peu importe ce que fait le moteur de rendu. Heck, il ne se soucie pas du tout s'il est affiché!
Et vous n'avez pas non plus besoin d'attacher d'informations de rendu à la scène. Il devrait suffire que le moteur de rendu sache qu'il doit rendre un orc. Vous aurez déjà chargé un modèle orc, que le moteur de rendu sait alors afficher.
Cela devrait répondre à vos besoins. La représentation graphique et la logique sont couplées , car elles utilisent toutes deux les mêmes données. Pourtant, ils sont séparés , car aucun ne dépend de l'autre!
EDIT: Et juste pour répondre pourquoi on le ferait comme ça? Parce que c'est plus facile est la raison la plus simple. Vous n'avez pas besoin de penser à "tel ou tel est arrivé, je devrais maintenant mettre à jour les graphiques". Au lieu de cela, vous faites bouger les choses et chaque image du jeu examine ce qui se passe actuellement et l'interprète d'une manière ou d'une autre, vous donnant un résultat à l'écran.
la source
Votre titre pose une question différente de celle de votre contenu corporel. Dans le titre, vous demandez pourquoi la logique et le rendu doivent être séparés, mais dans le corps, vous demandez les implémentations des systèmes de logique / graphiques / rendu.
La deuxième question a été traitée précédemment , je vais donc me concentrer sur la première question.
Raisons de séparer la logique et le rendu:
Dans un cadre de POO, l'instanciation de nouveaux objets a un coût, mais d'après mon expérience, le coût des ressources système est un petit prix à payer pour la capacité de penser et de mettre en œuvre les choses spécifiques que je dois faire.
la source
Cette réponse est seulement de construire une intuition de la raison pour laquelle la séparation du rendu et de la logique est importante, plutôt que de suggérer directement des exemples pratiques.
Supposons que nous ayons un gros éléphant , personne dans la pièce ne peut voir l'éléphant entier. peut-être que tout le monde est même en désaccord sur ce que c'est réellement. Parce que tout le monde voit une partie différente de l'éléphant et ne peut traiter que cette partie. Mais en fin de compte, cela ne change pas le fait qu'il s'agit d'un gros éléphant.
L'éléphant représente l'objet du jeu avec tous ses détails. Mais personne n'a réellement besoin de tout savoir sur l'éléphant (objet de jeu) pour pouvoir faire sa fonctionnalité.
Coupler la logique du jeu et le rendu, c'est en fait faire voir tout le monde à l'éléphant. Si quelque chose a changé, tout le monde doit le savoir. Alors que dans la plupart des cas, ils ont seulement besoin de voir la partie qui les intéresse uniquement. Si quelque chose a changé la personne qui en a connaissance, n'a qu'à informer l'autre personne du résultat de ce changement, c'est ce qui est le plus important pour lui. (pensez à cela comme une communication via des messages ou des interfaces).
Les points que vous avez mentionnés ne sont pas des inconvénients, ils ne sont des inconvénients que s'il y avait plus de dépendances qu'il ne devrait y en avoir dans le moteur, en d'autres termes, les systèmes voient les parties de l'éléphant plus qu'ils ne devraient avoir. Et cela signifie que le moteur n'a pas été "correctement" conçu.
Vous n'avez besoin de synchronisation avec sa définition formelle que si vous utilisez un moteur multithread où il place la logique et le rendu dans deux threads différents, et même un moteur qui nécessite beaucoup de synchronisation entre les systèmes n'est pas particulièrement bien conçu.
Sinon, la façon naturelle de traiter un tel cas est de concevoir le système comme entrée / sortie. La mise à jour fait la logique et génère le résultat. Le rendu est uniquement alimenté avec les résultats de la mise à jour. Vous n'avez pas vraiment besoin de tout exposer. Vous exposez uniquement une interface qui communique entre les deux étapes. La communication entre les différentes parties du moteur doit se faire via des abstractions (interfaces) et / ou des messages. Aucune logique ou état interne ne doit être exposé.
Prenons un exemple de graphique de scène simple pour expliquer l'idée.
La mise à jour se fait généralement via une seule boucle appelée boucle de jeu (ou éventuellement via plusieurs boucles de jeu, chacune s'exécutant dans un thread séparé). Une fois la boucle mise à jour, jamais l'objet de jeu. Il suffit de dire via la messagerie ou les interfaces que les objets 1 et 2 ont été mis à jour et de l'alimenter avec la transformation finale.
Le système de rendu ne prend que la transformation finale et ne sait pas ce qui a réellement changé sur l'objet (par exemple, une collision spécifique s'est produite, etc.). Maintenant, pour rendre cet objet, il n'a besoin que de l'ID de cet objet et de la transformation finale. Après cela, le rendu alimentera l'api de rendu avec le maillage et la transformation finale sans rien savoir d'autre.
la source