J'ai conçu un système d'entité pour un FPS. Cela fonctionne fondamentalement comme ceci:
Nous avons un "monde" -object, appelé GameWorld. Cela contient un tableau de GameObject, ainsi qu'un tableau de ComponentManager.
GameObject contient un tableau de composants. Il fournit également un mécanisme d'événement qui est vraiment simple. Les composants eux-mêmes peuvent envoyer un événement à l'entité, qui est diffusé à tous les composants.
Le composant est fondamentalement quelque chose qui donne à un GameObject certaines propriétés, et comme GameObject n’est en fait qu’un conteneur, tout ce qui a trait à un objet de jeu a lieu dans les composants. Les exemples incluent ViewComponent, PhysicsComponent et LogicComponent. Si la communication entre eux est nécessaire, vous pouvez utiliser des événements.
ComponentManager juste une interface comme Component, et pour chaque classe de composant, il devrait généralement y avoir une classe ComponentManager. Ces gestionnaires de composants sont responsables de la création des composants et de leur initialisation avec des propriétés lues à partir d'un fichier XML.
ComponentManager prend également en charge les mises à jour massives de composants, comme le composant PhysicsComponent où je vais utiliser une bibliothèque externe (qui fait tout dans le monde à la fois).
Pour la configurabilité, j'utiliserai une fabrique pour les entités qui liront soit un fichier XML, soit un script, créer les composants spécifiés dans le fichier (qui y ajoute également une référence dans le bon gestionnaire de composants pour les mises à jour en masse), et puis les injecter dans un objet GameObject.
Vient maintenant mon problème: je vais essayer de l’utiliser pour les jeux multijoueurs. Je ne sais pas comment aborder cela.
Premièrement: quelles entités les clients devraient-ils avoir depuis le début? Je devrais commencer par expliquer comment un moteur mono-joueur déterminerait quelles entités créer.
Dans l'éditeur de niveau, vous pouvez créer des "pinceaux" et des "entités". Les brosses sont conçues pour les murs, les sols et les plafonds, des formes simples. Les entités sont les GameObject dont je vous ai parlé. Lors de la création d'entités dans l'éditeur de niveaux, vous pouvez spécifier des propriétés pour chacun de ses composants. Ces propriétés sont directement transmises à quelque chose comme un constructeur dans le script de l'entité.
Lorsque vous enregistrez le niveau à charger par le moteur, il est décomposé en une liste d'entités et de leurs propriétés associées. Les brosses sont converties en une entité "worldspawn".
Lorsque vous chargez ce niveau, il instancie simplement toutes les entités. Cela semble simple, hein?
Maintenant, pour la mise en réseau des entités, je rencontre de nombreux problèmes. Premièrement, quelles entités devraient exister sur le client dès le début? En supposant que le serveur et le client possèdent le fichier de niveau, le client peut également instancier toutes les entités du niveau, même si elles ne sont là que pour les règles du jeu sur le serveur.
Une autre possibilité est que le client instancie une entité dès que le serveur envoie des informations à ce sujet, ce qui signifie que le client ne disposera que des entités dont il a besoin.
Un autre problème est de savoir comment envoyer les informations. Je pense que le serveur pourrait utiliser la compression-delta, ce qui signifie qu'il envoie uniquement de nouvelles informations lorsque quelque chose change, plutôt que d'envoyer un instantané au client à chaque image. Bien que cela signifie que le serveur doit garder une trace de ce que chaque client sait pour le moment.
Et enfin, comment le réseau devrait-il être injecté dans le moteur? Je pense à un composant, NetworkComponent, qui est injecté dans chaque entité censée être mise en réseau. Mais comment le composant réseau doit-il savoir quelles variables doivent être connectées au réseau et comment y accéder, et enfin comment le composant réseau correspondant sur le client doit savoir comment modifier les variables en réseau?
J'ai beaucoup de difficulté à aborder cela. J'apprécierais vraiment si vous m'aviez aidé sur le chemin. Je suis ouvert aux conseils sur la manière d'améliorer la conception du système de composants, alors n'ayez pas peur de le suggérer.
la source
Était sur le point d'écrire un commentaire mais a décidé que cela pourrait être assez d'information pour une réponse.
Tout d’abord, +1 pour une question aussi bien écrite avec beaucoup de détails pour juger de la réponse.
Pour le chargement des données, je demanderais au client de charger le monde à partir du fichier monde. Si vos entités contiennent des identifiants provenant du fichier de données, je les chargerais également par défaut afin que votre système de gestion de réseau puisse simplement s'y référer pour savoir de quels objets il s'agit. Tous ceux qui chargent les mêmes données initiales doivent avoir le même identifiant pour ces objets.
Deuxièmement, ne créez pas de composant NetworkComponent, car cela ne ferait que répliquer des données dans d’autres composants existants (la physique, l’animation et autres sont des éléments courants à transmettre). Pour utiliser votre propre nom, vous souhaiterez peut-être créer un NetworkComponentManager. Ce serait légèrement différent de l'autre relation entre Composant et Gestionnaire que vous avez, mais cela pourrait être instancié lorsque vous démarrez un jeu en réseau et que tout type de composants ayant un aspect réseau confère au gestionnaire ses données pour qu'il puisse les regrouper. et l'envoyer. C’est là que votre fonctionnalité de sauvegarde / chargement pourrait être utilisée si vous disposiez d’une sorte de mécanisme de sérialisation / désérialisation que vous pourriez également utiliser pour conditionner les données, comme mentionné,
Compte tenu de votre question et du niveau d’information, je ne pense pas avoir besoin d’entrer beaucoup plus dans les détails, mais si quelque chose n’est pas clair, merci de poster un commentaire et je mettrai à jour la réponse pour y remédier.
J'espère que cela t'aides.
la source