Bonjour,
# Préambule (pas important):
Comme une partie d'entre-vous le sait déjà, je suis en plein développement d'un moteur de jeu, celui-ci est basé sur une architecture modulaire hiérarchisée de façon stricte, chaque module est une bibliothèque donnant accès à un set de fonctionnalités accessibles uniquement au sein du module même et des modules dépendant de celui-ci.
Par exemple, cela signifie que le moteur possède un module gérant l'audio, et un module gérant le rendu. Ces deux modules n'ont aucune connaissance l'un de l'autre.
Afin de permettre la création d'un jeu, il convient de réunir tous les modules ensembles, via une surcouche, une bibliothèque liée avec tous les modules nécessaires, afin de les faire fonctionner ensemble et de faciliter la création d'une application.
# Le problème (plus important):
La bibliothèque en question, appelée NDK (Nazara Development Kit), est basée sur un Entity Component System, celui-ci est je pense assez classique, voici un code d'exemple pour plus de clarté: http://pastebin.com/QJwWuZE3.
Actuellement, ce n'est qu'un squelette d'ECS, tout fonctionne mais le NDK ne fournit aucun composant/système de base d'interaction avec le moteur.
Et c'est précisément pour ça que je me tourne vers vous avant de me lancer dans la création d'une architecture, j'aimerai y réfléchir, et que vous m'aidiez à y réfléchir.
Mes pistes de réflexions:
- Tout d'abord, j'hésite à faire hériter Ndk::Entity (une entité de l'ECS) par NzNode (venant du moteur).
Le faire signifierait donner une position (vecteur 3D), une rotation (quaternion) et une échelle (vecteur 3D) à CHAQUE entité, ainsi qu'un système de hiérarchie.
Cela permettrait de simplifier l'interface:
1 2 3 4 | Ndk::EntityHandle entity = world.CreateEntity(); Ndk::EntityHandle entity2 = world.CreateEntity(); entity->SetParent(entity2); entity->SetPosition({42.f, 666.f, -1337.f}); |
L'alternative serait:
1 2 3 | auto& nodeComponent = entity->GetComponent<Ndk::NodeComponent>(); nodeComponent.SetParent(entity2); // assertion: entity2 doit posséder un NodeComponent nodeComponent.SetPosition({42.f, 666.f, -1337.f}); |
Le problème de la première option est d'ajouter une inconsistence:
1 2 | entity->SetPosition(NzVector3f::Zero()); // Méthode de l'entité entity->GetComponent<Ndk::VelocityComponent>() = NzVector3f::Up() * 10.f; // Méthode/opérateur du composant |
Cependant, l'extrême majorité des entités va avoir besoin d'un positionnement, d'une rotation, etc.
Et même si elles n'utilisent que la position (ex: point light), la rotation est transmise aux entités attachées, donc pas inutile.
- La gestion du rendu, c'est le point qui me pose le plus de difficultés.
Actuellement, une classe NzScene dans le module graphique s'occupe à la fois de gérer la scène visuelle (avec hiérarchie) et d'en effectuer le rendu. Le fait que le rendu et la scène soient gérés au même endroit par la même classe pose évidemment problème.
Ce système va disparaître au profit de l'ECS, contenant la scène et s'occupant de gérer l'audio, le rendu, la physique, etc. grâce à des systèmes.
L'idée serait que le module graphique ne contienne plus que des algorithmes (culling, technique de rendu, gestion des matériaux) qui seraient utilisés par le NDK.
Et c'est bien sur ce deuxième point, car j'ai du mal avec l'organisation nécessaire autour du rendu.
Sachant qu'il faut gérer la génération des shadow maps, le culling, et bien d'autres.
Bien sûr, il serait possible de faire un gros système s'occupant du rendu de façon automatique, traitant les entités automatiquement selon leurs composants, c'est d'ailleurs une solution que j'explore.
Cependant, je pense aussi à certaines difficultés, par exemple:
Imaginons une scène, celle-ci possède une télévision qui montre au joueur un endroit particulier de la scène. Au niveau du moteur cela signifie qu'il existe une caméra à un endroit de la scène effectuant son rendu vers une texture réutilisée par le matériau de la télévision.
Cependant:
1) Le culling de la télévision doit être appliqué avant toute chose (ça ne sert à rien d'effectuer le second rendu si la télévision n'est pas visible par le joueur).
2) Le rendu secondaire doit ensuite être effectué (cela implique du culling du point de vue de la caméra secondaire et du rendu complet)
3) Gestion des opérations pré-rendu (rendu des réflexions, génération des shadow maps)
4) Rendu de la scène principale.
Et maintenant imaginons que dans le champs de la caméra secondaire apparaisse une deuxième télévision pointant à un autre endroit. Ou pire, que la télévision apparaisse sur la caméra secondaire (donnant un bel effet de tunnel).
L'idéal serait que le moteur gère ça tout seul, mais j'ai vraiment du mal à imaginer la façon dont il faut gérer tout ça pour l'instant.
Vous n'avez peut-être pas de solution miracle à me proposer, mais votre avis peut certainement m'aider, c'est pourquoi je vous le demande.
Si je n'ai pas été assez clair (à mon habitude ), n'hésitez pas à demander plus de précisions, il est presque trois heures du matin donc je passe certainement à côté de détails importants.
Merci d'avoir lu !