Appels de fonction par trame par rapport à la messagerie basée sur les événements dans la conception de jeux

11

La conception de jeu traditionnelle , telle que je la connais, utilise le polymorphisme et les fonctions virtuelles pour mettre à jour les états des objets de jeu. En d'autres termes, le même ensemble de fonctions virtuelles est appelé à intervalles réguliers (ex: par image) sur chaque objet du jeu.

Récemment, j'ai découvert qu'il existe un autre système de messagerie basé sur les événements pour mettre à jour les états des objets de jeu. Ici, les objets ne sont généralement pas mis à jour image par image. Au lieu de cela, un système de messagerie d'événements très efficace est construit et les objets de jeu ne sont mis à jour qu'après avoir reçu un message d'événement valide.

L'architecture de jeu basée sur les événements est bien décrite dans: Game Coding Complete de Mike McShaffry .

Puis-je demander de l'aide pour les questions suivantes:

  • Quels sont les avantages et les inconvénients des deux approches?
  • Où est-on meilleur que l'autre?
  • La conception de jeux basée sur les événements est-elle universelle et meilleure dans tous les domaines? Est-il donc recommandé pour une utilisation même sur les plateformes mombile?
  • Laquelle est la plus efficace et la plus difficile à développer?

Pour clarifier, ma question n'est pas de supprimer complètement le polymorphisme d'une conception de jeu. Je souhaite simplement comprendre la différence et bénéficier de l'utilisation de la messagerie événementielle par rapport aux appels réguliers (par image) aux fonctions virtuelles pour mettre à jour l'état du jeu.


Exemple: Cette question a suscité un peu de controverse ici, alors laissez-moi vous donner un exemple: Selon MVC, le moteur de jeu est divisé en trois parties principales:

  1. Couche d'application (communication matérielle et OS)
  2. Game Logic
  3. Vue du jeu

Dans un jeu de course, la vue du jeu est responsable du rendu de l'écran le plus rapidement possible, au moins 30 ips. La vue de jeu écoute également les commentaires du joueur. Maintenant, cela se produit:

  • Le joueur enfonce la pédale de carburant à 80%
  • GameView construit un message "Pédale de carburant de la voiture 2 enfoncée à 80%" et l'envoie à Game Logic.
  • Game Logic reçoit le message, évalue, calcule la position et le comportement de la nouvelle voiture et crée les messages suivants pour GameView: "Dessiner la pédale de carburant de la voiture 2 à 80%", "Accélération sonore de la voiture 2", "Coordonnées de la voiture 2 X, Y" .. .
  • GameView reçoit les messages et les traite en conséquence
Bunkai.Satori
la source
où avez-vous trouvé? quelques liens ou références? je ne connais pas cette approche (mais je connais assez bien le modèle de conception en général, et je conseille une bonne utilisation des principes d'orientation des objets en général), mais je pense que celui basé sur les événements est mieux .. pensez à l'évolution des systèmes de réseau: de polling aux appels asynchrones .. il est optimisé dans les calculs et au niveau abstraction
nkint
Salut Nkint, merci pour ton commentaire. Je souhaitais essentiellement comparer la communication événementielle et les appels à des fonctions virtuelles. Je vais modifier un peu ma question. Btw, jetez un oeil à ce lien contenant les modèles de conception de jeu: gameprogrammingpatterns.com .
Bunkai.Satori
5
Peut-être que je suis stupide, mais comment allez-vous faire fonctionner un système de messagerie sans utiliser le polymorphisme? N'allez-vous pas avoir besoin d'une sorte de classe de base (abstraite ou autre) pour définir votre interface de récepteur d'événements? (Edit: en supposant que vous ne travaillez pas dans une langue avec une réflexion appropriée.)
Tetrad
2
En outre, l'efficacité va être fortement liée aux détails de mise en œuvre. Je ne pense pas que "lequel est le plus efficace" soit une question à laquelle on puisse répondre dans sa forme actuelle.
Tetrad
1
Les objets du jeu doivent cocher. Les objets du jeu doivent communiquer entre eux. Ces deux choses doivent se produire. La première chose que vous ne faites pas avec la messagerie car elle est redondante (vous avez probablement une liste de tous les objets quelque part, appelez-les simplement update). La seconde, vous pouvez le faire avec la messagerie pour diverses raisons.
Tetrad

Réponses:

8

Je crois fermement à la nécessité d'être la mère de l'invention. Je n'aime rien coder sauf si son besoin est clair et bien défini. Je pense que si vous démarrez votre projet en mettant en place un système de messagerie d'événements, vous le faites mal. Je crois qu'une fois que vous avez créé et testé votre infrastructure et que tous les éléments de votre projet sont bien définis, des modules de travail doivent vous concentrer sur la façon dont vous allez connecter ces modules les uns aux autres. Essayer de concevoir un système de messagerie d'événements avant de comprendre la forme et les besoins de chaque module est hors service.

Quels sont les avantages et les inconvénients des deux approches?

Je pense que certaines personnes diraient qu'il existe de bons systèmes de messagerie prêts à être installés et utilisés. C'est peut-être vrai. Il est certain que les performances d'une solution personnalisée spécialement adaptée à vos besoins seraient supérieures à celles d'un bus de messages à usage général. La grande question est - combien de temps allez-vous passer à construire un système de messagerie plutôt que d'utiliser quelque chose qui a déjà été construit. De toute évidence, si vous pouviez trouver une sorte de système d'événements avec exactement l'ensemble de fonctionnalités dont vous avez besoin, alors c'est une décision assez facile. C'est pourquoi je m'assure de bien comprendre ce dont j'ai besoin avant de prendre cette décision.

Où est-on meilleur que l'autre?

Nous pourrions parler de mémoire et de ressources ici. Si vous développez pour n'importe quel matériel avec des ressources limitées, il est certainement difficile d'utiliser un système d'événement qui le réduira considérablement. Vraiment, cependant, je pense que le problème se résume à ce dont vous avez besoin, ce qui, comme je l'ai déjà mentionné, est quelque chose que vous ne savez pas jusqu'à ce que vous voyiez à quoi ressemblent toutes les pièces. Si vous avez suffisamment d'expérience dans la construction de ces systèmes pour savoir à l'avance à quoi ressembleront toutes les pièces, vous pouvez également répondre à cette question à l'avance. Je suppose que vous n'avez pas cette expérience, car vous ne poseriez pas cette question si vous en aviez.

La conception de jeux basée sur les événements est-elle universelle et meilleure dans tous les domaines? Est-il donc recommandé pour une utilisation même sur des plateformes mobiles?

Universel et meilleur dans tous les domaines? Une jolie déclaration générale comme celle-ci est facilement rejetée. Tout ce qui ajoute des frais généraux doit supporter sa part de la charge de travail. Si vous n'utilisez pas suffisamment d'événements pour justifier les frais généraux de la conception, c'est la mauvaise conception.

Laquelle est la plus efficace et la plus difficile à développer?

L'efficacité dépend de la façon dont elle est mise en œuvre. Je pense qu'un design traditionnel bien développé surpassera un système basé sur les événements n'importe quel jour de la semaine. En effet, la communication entre les pièces peut être micro-gérée et rendue super efficace. Bien sûr, cela rend également la conception plus difficile du point de vue de l'expérience et du temps requis pour la compléter et la rendre plus efficace. D'un autre côté, si vous manquez de cette expérience ou si vous n'avez pas le temps de bien développer l'application, il sera plus efficace d'utiliser une conception événementielle adaptée à vos besoins. Si vous avez des besoins d'événement personnalisés qui ne s'intègrent pas facilement dans une structure basée sur des événements, cela pourrait rendre la structure basée sur des événements très difficile à concevoir - en particulier pour garder la conception efficace.

Erick Robertson
la source
Bonjour Eric, merci pour votre avis détaillé sur ma question. Au fur et à mesure que je lis vos réponses et celles des autres, la mise en œuvre des messages d'événement ne provoque probablement pas de miracle dans l'augmentation globale des performances du jeu. Au lieu de cela, cela va beaucoup compliquer les choses. J'aimerais voir d'autres réponses avant de clore cette question. Comme tout le livre couvrait ce sujet, cela semblait être une bonne idée à considérer. Je ne suis pas très sûr, si la décision d'utiliser ou de ne pas utiliser les messages peut être prise au milieu du projet. Si des messages d'événement sont utilisés, je dirais que la conception globale de l'objet doit également être ajustée.
Bunkai.Satori
Je ne suis pas d'accord. Si la conception globale de l'objet est bien encapsulée, elle doit être suffisamment flexible pour être utilisée dans tout type de cadre. J'ai pu échanger des méthodes de communication dans de grands projets avec très peu de travail car chaque pièce était bien encapsulée.
Erick Robertson,
7

Je pense que vous comparez des pommes et des oranges ici. Le polymorphisme n'est pas du tout remplacé par la messagerie. Vous souhaiterez probablement que des événements / messages connectent des composants à couplage lâche. Par exemple. pour envoyer un message d'une entité en cas de collision, pour mettre à jour le score du joueur ou peut-être pour déclencher un effet sonore. Pour que ces classes individuelles ne connaissent pas les autres classes et envoient et / ou gèrent simplement des messages.

Mais votre jeu aura très probablement une boucle de mise à jour quelque part et puisque vous avez cette boucle de mise à jour, il peut facilement être utilisé pour mettre à jour toutes les entités de jeu qui doivent également être mises à jour à chaque image. Cela ne vous empêche pas d'utiliser la messagerie ...

Si vous avez une sorte de structure dans laquelle vous ajoutez / supprimez des entités de jeu, vous pouvez tout aussi bien les inclure dans votre boucle de mise à jour au lieu de leur envoyer un message de mise à jour à chaque image. Alors pourquoi ne pas appeler directement la mise à jour de vos entités de jeu pendant que vous utilisez la messagerie pour connecter différents sous-systèmes de votre jeu? J'aime aussi le concept Signal / Slot ( voir exemple qt ) pour les systèmes événementiels.

Conclusion: il n'y a pas de meilleure approche ni d'exclusivité.

bummzack
la source
Salut, Bummzack. Enfin, la première réponse est arrivée. Merci pour cela :-) Quand j'ai mentionné l'architecture pilotée par les événements, je parlais d'un système MVC avec trois couches clés: Appliaction, GameView, GameLogic. Toute la communication entre ces trhee se ferait par messagerie. Ceci est considérablement différent du système traditionnel avec boucle de mise à jour. Chaque système a une architecture différente, certains avantages et inconvénients, et leur coût de performance est différent. Je pense donc que l'on serait légèrement meilleur dans certains domaines. Après une bonne analyse, nous devrions pouvoir conclure laquelle est la meilleure.
Bunkai.Satori,
3
Je ne vois pas pourquoi c'est différent? Vous aurez besoin d'une boucle de mise à jour quelque part et cela mettra probablement à jour le contrôleur si vous voulez rester avec MVC. Ensuite, le contrôleur peut envoyer un message au modèle et à la vue .. mais comme le contrôleur connaît généralement la vue et le modèle, il peut également les mettre à jour directement. Mais cela ne remplace aucun polymorphisme. Votre question et vos hypothèses semblent très théoriques ... peut-être les étayer avec un exemple de code ou des références?
bummzack
Le livre mentionné ci-dessus, Game Coding Complete, recommande la messagerie d'événements sur les appels directs aux méthodes virtuelles. Bien que le système de messagerie semble plus complexe, son avantage est que chaque objet de jeu n'a pas besoin de vérifier le monde du jeu. Le monde du jeu n'est vérifié par la logique du jeu qu'une seule fois, puis seuls les objets sont censés changer leurs états. C'est une différence et cela peut signifier des économies de coûts. Si vous décidez que vos objets de jeu communiqueront via des messages, ils ne seront pas appelés à chaque image - par conséquent, les deux approches s'excluent mutuellement.
Bunkai.Satori,
1
A voté pour une réponse qui reflète les commentaires de Tetrad sous la question d'origine. @ Bunkai.Satori Le «monde du jeu n'est vérifié qu'une seule fois» est la boucle de mise à jour, tout ce qui a besoin d'une mise à jour l'obtient. Les messages d'événement sont censés être les éléments clés du moteur (PlayerDied, MonsterDied, etc.) qui sont rarement effectués, mais que la vérification de chaque image dans une boucle Update () serait un gaspillage, mais ils sont très probablement générés par le Mettre à jour () la boucle elle-même.
James
1
Si vous avez la deuxième édition, consultez le chapitre intitulé Contrôle de la boucle principale. Il devrait porter le même nom dans la 3e édition. Cela devrait vraiment répondre à votre question.
Ray Dey
4

Cela a commencé comme un commentaire à la réponse de Bummzack, mais est devenu long.

À moins que vous ne le rendiez réellement asynchrone (répartissez les événements sur un nouveau thread), vos objets reçoivent toujours le mémo de manière synchrone. En supposant que votre répartiteur d'événements utilise une table de hachage de base avec une liste liée dans une cellule, l'ordre sera l'ordre dans lequel les objets ont été ajoutés à cette cellule.

En outre, sauf si vous décidez d'utiliser des pointeurs de fonction pour une raison quelconque, vous utilisez toujours des appels de fonction virtuels, car chaque objet recevant un message doit implémenter IEventListener (ou tout ce que vous appelez). Les événements sont une abstraction de haut niveau que vous créez à l'aide du polymorphisme.

Utilisez des événements où vous devez appeler une liste de méthodes pour divers événements dans le jeu afin de synchroniser différents systèmes dans le jeu ou où la réaction de divers objets et systèmes de sorte que ces événements ne peuvent pas être clairement définis ou que vous voulez pour ajouter plus de réactions à ces événements à l'avenir.

Ils sont un excellent outil, mais comme l'a dit Bummzack, ne supposez pas que le polymorphisme et les événements résolvent le même problème.

michael.bartnett
la source
Salut Bearcdp, merci pour votre réponse. Ça me semble logique. Il y a une chose dans mon esprit qui vote pour les messages d'événement: disons, il y a 200 objets dans la scène. Si vous utilisez des appels de fonction par image sur tous les objets, vous devez vérifier la colision des 200 objets à chaque image (un exemple; bien sûr, les intervalles d'appel peuvent être gérés.) Avec la messagerie d'événements, le gameworld n'est examiné qu'une seule fois. S'il y a 5 collisions, seuls 5 objets sont avertis par des messages sur l'événement de collision, au lieu de 200 tests de détection de collisions avec appels par trame. Quel est ton opinion?
Bunkai.Satori,
2
examiner le gameworld ?? Qu'est-ce que ça veut dire? Cela devrait signifier exécuter les mêmes 200 contrôles pour isoler les 5 dont il a besoin pour envoyer des messages. Avec le concept de fonction virtuelle, le monde du jeu n'est vérifié qu'une seule fois (la fonction de chaque objet à son tour), puis passe uniquement aux 5 qui nécessitent des changements d'état ... sans les frais généraux d'un système de messagerie.
Steve H
1
Écoutez Steve H, le monde ne se heurte pas. J'utilise principalement des événements pour des événements de haut niveau, tels que PlayerJump, EnemyHit. Pour gérer l'efficacité de la vérification des collisions, vous devez choisir une structure de données pour organiser l'emplacement physique des objets dans votre jeu afin de pouvoir hiérarchiser les objets dont la collision a besoin ou non. Une fois que vous avez déterminé toutes les paires d'objets qui sont entrées en collision, vous pouvez envoyer un événement avec les données de collision pertinentes (les deux objets, les données de vitesse / position / normales, etc.).
michael.bartnett
Salut Steve et Beardcp, merci pour vos commentaires. Ce que vous avez écrit est logique. Il semble qu'il puisse y avoir de nombreuses implémentations possibles du système de messagerie d'événements. Il peut y avoir le remplacement pur du concept de fonction virtuelle par trame, comme le dit le livre ci-dessus. Cependant, comme vous le dites, le système de messagerie peut coexister avec le concept de fonction virtuelle par trame.
Bunkai.Satori,
Pourquoi dites-vous "pour une raison quelconque" en référence aux pointeurs de fonction? C'est à peu près ainsi que j'ai implémenté un système d'événements lorsque j'en ai écrit un à partir de zéro (je travaille dans des langages qui ont des fonctions de première classe mais c'est la même idée; passez la fonction à l'objet hub d'événements et cet objet mappe les fonctions d'écoute à événements) donc je me demande s'il y a un inconvénient à cette approche.
jhocking
2

Je dirais que choisir l'un ou l'autre est assez mauvais. Certains objets doivent appeler chaque trame, d'autres non. Si vous souhaitez rendre un objet, vous devez lui faire un appel de rendu à chaque image. Les événements ne peuvent pas faire ce changement. La même chose est vraie pour tous les objets physiques basés sur le temps - vous devez les appeler à chaque image.

Cependant, je n'appelle pas chaque trame vers mes objets de gestion d'objet, ou mes objets d'entrée utilisateur, ou quelque chose comme ça. Les appels virtuels de masse à chaque objet sur le cadre sont une idée terrible.

La conception utilisée pour un objet particulier doit être basée sur les besoins de ces objets, et non sur une idéologie pour le système dans son ensemble.

Modifié pour être plus clair sur ma première phrase.

DeadMG
la source
Salut DeadMG, laissez-moi vous expliquer: dans le cas mentionné ci-dessus, la conception est divisée en trois parties principales: couche Appliaction (accès matériel), Game Logic, Game View. Ce qui est rendu par image est la vue du jeu. Cependant, lorsque Game View enregistre une entrée utilisateur (ex. Pédale de frein enfoncée dans le jeu de poursuite), il envoie un message "Car 2 Brake Pressed" à Game Logic pour traitement. Game Logic évalue cette action, calcule le comportement de la voiture et envoie un message à la vue du jeu: "Car 2 Block Tires", "Car 2 Move to X, Y". De cette façon, il n'est pas nécessaire de vérifier par cadre si le frein a été pressé sur chaque voiture.
Bunkai.Satori
@Bunkai: Vous avez donc des conceptions qui sont déclenchées par des événements et certaines conceptions qui sont appelées chaque image. Cela correspond à peu près à ma réponse.
DeadMG
Je suis heureux de trouver de la compréhension avec vous, car cette question a été un peu controversée aujourd'hui :-)
Bunkai.Satori