Dois-je, et comment, séparer les préoccupations des objets d'entrée et de jeu?


20

Dans chaque jeu, un développeur doit probablement gérer les entrées, que ce soit de simples événements de clavier et de souris, des événements tactiles ou quelque chose comme entrée d'accéléromètre. Cette entrée affecte directement les objets du jeu. Parfois, la même entrée peut affecter différents objets. Maintenant, je réfléchis à la façon de modéliser cela. Selon moi, il existe deux approches différentes.

  • Laissez l'objet de jeu le gérer lui-même, abonnez-vous aux événements et appelez ses propres méthodes. Cela a l'avantage de laisser les objets du jeu décider eux-mêmes quelles entrées provoquent quelle action. Un inconvénient semble être que le code d'entrée est altéré avec le code d'objet de jeu "de base". De plus, les objets du jeu ne connaissent pas l'état du reste du jeu et ne doivent parfois pas agir sur les événements d'entrée. Cela ne semble pas correct.

  • Demandez à un contrôleur général des entrées de s'occuper de toutes les entrées et de décider qui peut gérer quel événement. Cela semble mieux séparer les préoccupations, mais couple étroitement la classe de contrôleur d'entrée aux objets de jeu. Il a en quelque sorte besoin de savoir qui veut recevoir quel événement et dans quel état. Cela ne semble pas correct non plus.

Quelles stratégies utilisez-vous pour gérer cela?

Réponses:


7

Je recommande de séparer les événements d'entrée des objets de jeu afin que vous puissiez rapidement changer / mettre à niveau les méthodologies d'entrée sans avoir à modifier et déboguer 10 classes d'objets. Des exemples étant le passage de commandes clavier uniquement à souris + clavier, ou simplement la réaffectation de touches.

Au lieu de coupler étroitement l'entrée aux objets de jeu individuels, appelez une seule méthode par signal d'entrée unique sur l'objet de jeu et laissez-le décider de la façon de l'exécuter.

Utilisez un contrôleur d'entrée pour suivre l'état de l'entrée:

Up press event   -> dir = up
Down press event -> dir = down

Chaque fois que l'état d'entrée change, évaluez si les objets du jeu sont prêts à être modifiés:

set dir  ->  if gamestate != paused && battlemode == false
             ->  character.changeDir(dir);

Implémentez des méthodes générales sur vos objets de jeu, qui peuvent être appelées par le contrôleur d'entrée ou d'autres objets de jeu, selon les besoins:

changeDir (dir)
setSpeed (walk/run)

7

Je recommande l'approche MVC. Dans MVC, les objets de jeu n'ont qu'à se soucier de la modélisation du système de jeu et à fournir une interface de haut niveau comme move_left. Ensuite, ayez un objet contrôleur qui s'inquiète de mapper l'entrée aux appels de modèle. Non seulement cela permet un changement facile des contrôles, mais cela donne une bonne interface pour l'IA, ils ne sont qu'un autre contrôleur.

Dans votre deuxième option, je diviserais le contrôleur d'entrée en deux parties, une qui gère le toucher de l'appareil, le clavier, l'accélération, tout ce que vous pouvez lui apporter, le faire mapper en un ensemble générique d'entrées. Ensuite, ayez une deuxième partie qui mappe les entrées génériques aux entrées spécifiques au jeu. Dire que les flèches du clavier sont mappées sur input1, puis toucher le haut d'un écran tactile mappe également sur input1 et maintenant vous écrivez un deuxième morceau qui mappe l'entrée 1 pour sauter. Vous pouvez maintenant mapper n'importe quel périphérique IO ainsi que des entrées de lecture ou AI stockées sur ce système d'entrée générique et avoir une petite partie spécifique au jeu qui charge ce que input1 one signifie pour le modèle.


5
Il y a beaucoup de discussions ailleurs sur ce site pour savoir pourquoi MVC n'est généralement pas un modèle approprié pour les jeux; ce que stonemetal décrit n'est même pas MVC, c'est juste de l'abstraction; et "Utiliser MVC" n'est pas une réponse, car MVC est une description de toute une classe d'architectures et non un moyen particulier de séparer les préoccupations (ni la seule façon de le faire).

2
MVC devrait lui donner A) un article de Wikipédia à lire B) un certain nombre de variations sur la façon d'aborder la solution qui s'est avérée fonctionner C) Je mentionne la façon dont je la mettrais en place là où le modèle expose une interface de haut niveau que le le contrôleur mappe une entrée de bas niveau (réelle ou synthétique) à une action de haut niveau et manipule directement le modèle plutôt qu'un système d'événement.
stonemetal

1

Je suggère que votre jeu (le modèle ) définisse une liste d'événements d'entrée possibles (implémentés sous forme d'énumérations ou d'objets avec une interface de base en commun). Des choses comme ça MovingRightStarted, MovingRightStopped, FiredWeapon1,Escape , etc ...

Le jeu définit une structure de données (par exemple a queue) que votre code d'entrée (le contrôleur ) peut remplir avec des événements d'entrée.

Ensuite, votre jeu peut interroger la structure de données pour obtenir les événements d'entrée.

De cette façon, vous pouvez brancher différents types de contrôleurs pour alimenter le modèle:

  • Clavier uniquement
  • Clavier + souris
  • Manette
  • Écran tactile
  • Intelligence artificielle

Vous les avez juste pour pousser les événements d'entrée vers le modèle.


Je pense que je comprends ce que vous voulez dire, à l'exception de votre choix d'un queuetype de données pour stocker cela. Pourriez-vous expliquer pourquoi?
Robert Massa

Bien entre deux interrogations d'événement d'entrée du modèle, le contrôleur peut avoir poussé plusieurs événements d'action, et il est important de garder l'ordre d'entrée utilisateur. C'est pourquoi j'ai choisi une structure de données FIFO. En fait, vous devrez peut-être également spécifier à quelle heure exacte l'entrée s'est produite.
Splo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.