Interrogation vs entrée événementielle

19

Je développe un jeu utilisant le sondage pour la méthode d'entrée. Cependant, maintenant que j'explore plus profondément les menus du jeu et les autres composants de l'interface utilisateur, je constate que j'aimerais probablement avoir une entrée pilotée par les événements. Peut-être même avoir les deux, en utilisant l'événement piloté pour l'interface utilisateur et l'interrogation pour l'entrée "monde". Je suis curieux de savoir quelle est la meilleure façon de procéder.

Je définis l'interrogation comme: à chaque boucle de mise à jour, je vérifie quelles touches sont pressées, où se trouve la souris, les boutons enfoncés, puis les parcoure et fais des actions en fonction des informations collectées.

Je définis un événement piloté comme: des événements basés sur une interruption, lorsqu'un événement se produit et qu'une interruption est déclenchée et qu'un bloc de code est exécuté en fonction de l'événement.

Pensez-vous qu'il est préférable de passer à tous les événements, à tous les sondages, ou une combinaison des deux est-elle acceptable? Si vous avez des avantages et des inconvénients pour l'un ou l'autre, veuillez les énumérer. Merci.

ÉDITER

Le jeu est basé sur Java / OpenGL, il sera donc publié sur Windows / Mac / Linux. La possibilité d'étendre cela aux appareils mobiles est faible. Le jeu est de style RTS, 3e personne en 3D.

EDIT 2

Je ne suis toujours pas totalement satisfait de la façon dont j'ai implémenté cela, mais ce vers quoi je m'oriente est d'attraper des événements dans mon interface utilisateur et s'ils ne sont gérés par aucun de mes composants d'interface utilisateur, je transmets l'événement au "Monde" pour la sélection / sélection. Quelque chose comme:

@Override  
private boolean handleEvent(Event event) {  
    if(hud.handleEvent(event)) {  
        return true;  
    }  
    return WORLD.handleEvent(event);  
}

De cette façon, je ne reçois pas de clics qui fuient dans l'interface utilisateur pour sélectionner des objets derrière les boutons et ce qui ne l'est pas.

Actuellement, les commandes de ma caméra sont toujours basées sur l'interrogation, et cela semble fonctionner pour l'instant, mais je pourrais le mettre à jour plus tard.

J'apprécie toutes les réponses, désolé je n'ai pu en choisir qu'une!

MichaelHouse
la source
6
Je ne suis pas sûr en Java, mais en général, vous devez toujours interroger les entrées. Vous pouvez ensuite publier des événements lorsque les choses changent, mais cela est toujours basé sur un système de sondage.
James
Le point de mire le plus pertinent à mon avis est de concevoir une boucle d'événement qui est exempte de toute charge supplémentaire que la collecte d'entrée. Permettez-moi de vous expliquer: le système d'exploitation fera l'interruption entraînée par les entrées et la traitera dans le "thread d'entrée" global, puis ce thread OS redirigera les messages dans l'application actuellement au point et écrit les informations dans sa file d'attente de messages. La file d'attente de messages doit être interrogée par PeekMessage ou GetMessage. Le moyen le plus rapide pour l'obtenir est d'utiliser GetMessage et de laisser le planificateur vous réveiller, vous pouvez ensuite horodater le message très précisément.
v.oddou

Réponses:

17

Cela dépend des exigences de votre jeu et de votre matériel. La plupart des jeux sont généralement intéressés par les modifications de l'état d'entrée, c'est-à-dire que l'utilisateur appuie sur la touche de tir et que son arme commence à tirer, que l'utilisateur relâche la touche de tir et que son arme arrête de tirer, que l'utilisateur appuie sur la touche de déplacement et commence à bouger, relâche la touche de déplacement et arrête de bouger , etc., donc un système d'entrée piloté par les événements est le plus logique dans ces cas puisque les informations sont déjà dans un format approprié. De plus, sur la plate-forme Windows, vous recevez déjà des événements pour les modifications de l'état du clavier et de la souris, il s'agit donc souvent d'une conversion 1: 1 d'événements de bas niveau en événements de jeu de haut niveau. Avec l'interrogation, vous devrez souvent générer de tels événements manuellement en comparant l'état entre la trame actuelle et la dernière. Fondamentalement, "quels boutons sont pressés maintenant?"

Cela étant dit, sur certaines plateformes, vous êtes bloqué avec une entrée de sondage à un niveau bas et il n'y a aucun moyen de faire vous-même la vérification des bords. Cependant, j'ai toujours obtenu les meilleurs résultats en utilisant des événements pour toute la logique de haut niveau, car c'est naturellement ainsi que ces systèmes ont tendance à fonctionner.

Skyler York
la source
Merci, j'ai inclus des informations supplémentaires sur la plate-forme et le but du jeu.
MichaelHouse
1
Notez que GetAsyncKeyStatec'est un moyen simple d'utiliser l'interrogation sur Win32.
Macke
Derp, j'ai posé une question dans les commentaires de Nate Bross que vous traitez ici, donc je suppose que je vais l'affiner. Est-ce que tous les PC offrent cette relation 1: 1 d'interruption matérielle au clavier du système d'exploitation, et quels types de plates-formes sont limités à l'interrogation de bas niveau?
michael.bartnett
@Macke: parfois, l'antivirus signale des programmes qui utilisent cette API car ils peuvent recevoir une pression de touche de l'ensemble du système mondial, permettant ainsi un enregistrement de touche malveillant. L'article le plus impressionnant à ce sujet sur Internet (je le sais) est celui-ci: securelist.com/analysis/publications/36358/…
v.oddou
7

Je ne vois aucune raison pour laquelle vous ne pouvez pas faire les deux et obtenir le meilleur des deux mondes.

Les événements d'entrée sont générés par interrogation (à un certain niveau, le pilote interroge le matériel pour voir dans quel état il se trouve), et puisque votre boucle principale interroge tous les périphériques d'entrée, vous pouvez facilement implémenter le vôtre. Quelque chose de simple comme ci-dessous est ce que j'ai utilisé dans le passé.

mouseInput = GetMouse();
kbInput = GetKeyboard();


// refactor this out to its own method if it makes sense
if menuState == Showing
    if mouseInput.LeftButton == State.Pressed
        LeftButton(mouseInput.X, mouseInput.Y)

// rest of game input code processing

void LeftButton(int x, int y)
{
    // left button event handler
}

Je sais que vous avez défini les événements comme des interruptions et ce que j'ai mis ici n'est pas "vraiment basé sur des événements", mais je ne vois pas ce que ce qui précède ne vous donne pas que les interruptions vous donnent - la plupart des utilisateurs ne le remarqueront pas la seule image perdue, sauf si votre jeu fonctionne à une fréquence d'images très faible.

Nate
la source
1
Je suis curieux de savoir comment obtenir des données d'entrée à partir d'appareils. Les événements clavier distribués par le système d'exploitation résultent-ils d'une interrogation au niveau du pilote de périphérique? Ou un événement clavier correspond-il à une interruption? Ou y a-t-il des interruptions, mais le système d'exploitation les met en mémoire tampon et les envoie quand il le juge opportun?
michael.bartnett
Je ne suis pas sûr de la façon dont cela fonctionne à ce niveau, mais c'est le plus basique, certains logiciels s'exécutent en boucle et vérifient l'état du clavier et le comparent à l'état précédent, si son changement, le changement se propage.
Nate
5

Il y a deux problèmes différents ici:

  1. Comment lisez-vous les entrées utilisateur à partir du système d'exploitation / matériel?

  2. Comment traitez-vous les entrées utilisateur dans votre moteur?

Pour la lecture, cela dépend clairement de votre plate-forme et du type d'entrée que vous souhaitez lire. Notez qu'il est facile de convertir une chose en une autre dans votre couche d'entrée. (C'est-à-dire interroger et émettre des événements vers le moteur, ou écouter des événements et émettre un état vers le moteur.)

Pour le traitement, il existe différentes options:

  • Pour le contrôle des mouvements des joueurs (et des schémas similaires), l'interrogation peut être plus simple car vous devez recalculer la vitesse de chaque image. Il est très probable que votre boucle interne soit basée sur l'interrogation:

    c'est à dire quelque chose comme speed += 1 if button.down else -1; clamp(speed, 0, 42);

  • Pour les événements discrets (missile de feu, jeu de pause, téléportation vers l'autre côté de la planète), le traitement des événements est préférable, sinon votre code sera jonché d' maybeLaunchMissile(key_state);appels, et c'est juste ... mauvais, m'kay. ;)

J'espère que cela aide.

Macke
la source