Je sais que cette question a été posée plusieurs fois, mais je ne sais toujours pas comment implémenter la gestion des entrées dans un moteur basé sur des composants.
La conception basée sur les composants que j'ai utilisée était basée sur la série de blogs de T = Machine et sur Artemis dans lequel les entités ne sont que des identifiants.
Il y a trois idées principales que j'ai dans la mise en œuvre de la gestion des entrées:
- Le composant d'entrée contiendra les événements qui l'intéressent. Le système d'entrée traduira les événements de touches et de souris en événements de jeu et parcourra les entités avec le composant d'entrée et s'ils sont intéressés par l'événement, une action appropriée sera prise par le système d'entrée. Cette action serait codée en dur dans le système d'entrée.
- Aucun composant d'entrée. Vous devez enregistrer des entités avec des événements spécifiques dans le système d'entrée. Le système d'entrée enverrait alors des messages (avec l'ID d'entité et le type d'événement) à d'autres systèmes afin que ceux-ci puissent prendre les mesures appropriées. Ou comme dans le premier cas, les actions seraient codées en dur dans le système d'entrée.
- Semblable à la première méthode, mais au lieu de coder en dur l'action sur le système d'entrée, le composant contiendrait une carte des événements aux fonctions (c'est-à-dire
std::map<std::function>
) qui serait appelée par le système d'entrée. Cela a pour effet supplémentaire de pouvoir coupler le même événement à différentes actions.
Recommanderiez-vous l'une des méthodes ci-dessus ou avez-vous des suggestions qui pourraient m'aider à mettre en œuvre un système de gestion des entrées flexible? De plus, je ne suis pas encore familier avec le multi-threading mais toutes les suggestions qui rendraient l'implémentation compatible avec les threads sont également les bienvenues.
Remarque: Une exigence supplémentaire que j'aimerais que l'implémentation remplisse est que je puisse transmettre la même entrée à de nombreuses entités, comme par exemple déplacer une entité caméra et le lecteur en même temps.
la source
Réponses:
Je pense que, tout comme ma réponse concernant les matériaux dans un système de composants , vous rencontrez un problème où vous essayez de tout mettre dans un "composant". Vous n'avez pas besoin de le faire et, ce faisant, vous créez probablement une interface vraiment encombrante en essayant de placer un tas de chevilles carrées dans des trous ronds.
Il semble que vous disposiez déjà d'un système qui gère l'acquisition des entrées du lecteur. J'opterais pour une approche qui traduirait ensuite cette contribution en actions («avancer» ou «reculer») ou en événements et les envoyer aux parties intéressées. Dans le passé, j'ai des composants non autorisés d'enregistrer eux - mêmes pour ces événements, préférant une approche où le système de niveau supérieur sélectionné explicitement la « entité contrôlée ». Mais cela pourrait fonctionner de cette autre manière si vous préférez, surtout si vous allez réutiliser les mêmes messages pour entreprendre des actions qui n'ont pas été directement stimulées par la saisie.
Je ne suggérerais pas nécessairement de mettre en œuvre un comportement de suivi de caméra en faisant en sorte que l'entité caméra et l'entité joueur répondent au message "aller de l'avant" (et cetera). Cela crée une connexion extrêmement rigide entre les deux objets qui ne se sentira probablement pas bien pour le joueur, et cela rend également un peu plus difficile de gérer des choses comme avoir la caméra en orbite autour du joueur lorsque le joueur tourne à gauche ou à droite: vous avez une entité répondre à "tourner à gauche" en supposant qu'il est asservi au joueur, mais cela signifie qu'il ne peut pas répondre correctement s'il a jamais été asservi ... à moins que vous n'introduisiez ce concept comme un état que vous pouvez vérifier. Et si vous voulez faire cela, vous pouvez aussi bien mettre en œuvre un système approprié pour asservir deux objets physiques ensemble, avec des ajustements d'élasticité appropriés, etc.
En ce qui concerne le multi-threading, je ne vois pas vraiment la nécessité de l'utiliser ici car cela entraînerait probablement plus de complications que cela en vaut la peine, et vous avez affaire à un problème intrinsèquement série, il vous suffit donc d'impliquer beaucoup de thread primitives de synchronisation.
la source
Mon expérience peut être biaisée, mais dans les projets multi-plateformes, les périphériques d'entrée ne sont pas directement exposés au système d'entité.
Les périphériques d'entrée sont gérés par un système de niveau inférieur qui reçoit les événements des touches, boutons, axe, souris, surfaces tactiles, accéléromètres ...
Ces événements sont ensuite envoyés via une couche de générateurs d'intentions dépendant du contexte.
Chaque générateur enregistre les changements d'état des composants, des entités et des systèmes qui sont pertinents pour ses fonctions.
Ces générateurs envoient ensuite des messages / intentions pour le routage vers le système d'intentions où les entités ont un composant ou directement vers les bons composants.
De cette façon, vous pouvez simplement compter sur "toujours" la même entrée, c'est-à-dire JUMP_INTENT (1), JUMP_INTENT (0), AIM_INTENT (1) ...
Et «tout» le travail d'entrée dépendant de la plate-forme sale reste en dehors de votre système d'entité.
En ce qui concerne la caméra, si vous souhaitez la déplacer dans le lecteur, elle peut enregistrer son propre composant d'intention et écouter les intentions que vous enverrez.
Sinon, si suit le lecteur, il ne doit jamais écouter les entrées destinées au lecteur. Il doit écouter les changements d'état émis par le lecteur (ENTITY_MOVED (transform)) ... et se déplacer en conséquence. Si vous utilisez un système physique, vous pouvez même attacher la caméra au lecteur en utilisant l'une des différentes articulations.
la source
Quel est l'avantage d'un InputComponent? C'est certainement la prérogative de la commande d'entrée de décider sur quelles entités elle exécute une action. L'exemple classique est celui de faire sauter le joueur. Au lieu d'avoir un InputComponent sur chaque entité à l'écoute des événements "Jump", pourquoi ne pas demander à la commande jump de rechercher l'entité marquée "player" et d'effectuer elle-même la logique nécessaire?
Un autre exemple, du PO:
la source