2017-01-20 4 views
1

En résumé, j'ai des problèmes pour implémenter non-buggy commandes clavier directionnelles (haut, bas, gauche, droite et combinaisons de deux touches de ces touches) en appuyant sur l'une des combinaisons (ou des touches simples) a un effet de clé collante. Autrement dit, en haut + à gauche, l'objet de jeu reste dans la position haut + gauche.SDL2 souhaités plusieurs contrôles collants clés, difficulté à empêcher l'interprétation erronée de la touche précoce comme nouvelle commande

Malheureusement, ce n'est pas ce qui se passe. Si j'appuie sur l'une des combinaisons à deux touches, le programme interprétera le plus souvent le léger retard entre la suppression d'une des deux touches en appuyant sur une touche. So down + right peut être interprété comme (down + right, nevermind right).

J'ai rencontré le même problème dans, par exemple, le traitement, et il est logique dans une certaine mesure que cela se produise. Si vous traitez les touches fléchées comme un d-pad virtuel, comment diriez-vous la différence entre up + right et up + right mais en basculant vers le haut immédiatement? La logique requise n'est pas parfaitement claire.

J'ai regardé sur stackoverflow et les forums officiels de SDL pour des solutions, mais rien ne semble m'aider dans ce cas particulier. Voici quelques questions que j'ai pu trouver: A way to make keyboard event queue both responsive and not take whole CPU power

Certaines "solutions" que j'ai essayées comprennent: vérifier si les mêmes clés sont maintenues à l'itération suivante (en d'autres termes, gaspiller un cadre ... cela fonctionne presque mais pas toujours, et il a semblé être une manière hacky d'aller) ou vérifiant seulement l'entrée de clavier toutes les 4 itérations. Aucun d'entre eux ne donne un très bon résultat. Notez que dans mon programme, haut/bas, gauche/droite, haut + gauche/bas + droite et haut + droite/bas-gauche sont considérés comme les mêmes commandes, donc il y a quatre options.

La principale logique de rendu en omettant la boucle:

while (is_running) 
{ 
    const Uint8 up = key_states[SDL_SCANCODE_UP]; 
    const Uint8 down = key_states[SDL_SCANCODE_DOWN]; 
    const Uint8 left = key_states[SDL_SCANCODE_LEFT]; 
    const Uint8 right = key_states[SDL_SCANCODE_RIGHT]; 

    SDL_Event event; 
    while (SDL_PollEvent(&event)) 
    { 
     switch (event.type) 
     { 
      case SDL_QUIT: 
       is_running = false; 
       break; 
     } 
    } 

    if ((up || down) && (!left && !right)) 
    { 
     if (prev != 0) // to avoid printing the same position repeatedly 
     { 
      puts("UP/DOWN"); 
      prev = 0; 
     } 
    } 
    else if ((left || right) && (!up && !down)) 
    { 
     if (prev != 1) 
     { 
      puts("LEFT/RIGHT"); 
      prev = 1; 
     } 
    } 
    else if ((up && left) || (down && right)) 
    { 
     if (prev != 2) 
     { 
      puts("UP-LEFT/DOWN-RIGHT"); 
      prev = 2; 
     } 
    } 
    else if ((up && right) || (down && left)) 
    { 
     if (prev != 3) 
     { 
      puts("UP-RIGHT/DOWN-LEFT"); 
      prev = 3; 
     } 
    } 
} 

(Une autre note: J'ai l'intention d'utiliser bitmasking plutôt que les nombreux contrôles booléens vu ci-dessus, mais cela ne concerne pas le problème.)

Je définis le programme pour sortir la direction de la console.

Output: 

UP/DOWN 
LEFT/RIGHT 
UP/DOWN 
UP-RIGHT/DOWN-LEFT // worked here 
UP-LEFT/DOWN-RIGHT // worked here 
UP-RIGHT/DOWN-LEFT // did not work here, reverted to LEFT/RIGHT 
LEFT/RIGHT // unexpected 
UP-LEFT/DOWN-RIGHT // also did not work here, reverted to LEFT/RIGHT 
LEFT/RIGHT // unexpected 

Les résultats sont apparemment au hasard, et étrangement, il est encore pire si je sépare les cas en haut, en bas, à gauche, droite, haut + à droite, vers le bas + droite, vers le bas + gauche, en haut + gauche.

Ma meilleure estimation? J'ai besoin d'un mécanisme de synchronisation et/ou d'une solution qui utilise le système d'événements. Je pense que je me suis retrouvé dans une impasse. Puis-je avoir de l'aide pour résoudre le problème? C'est le principal problème qui m'empêche de terminer ma démo de jeu.

Merci beaucoup.

EDIT: Je figure que le plus grand défi se différencie entre le passage d'une diagonale à verticale ou horizontale sans lâcher toutes les clés et le léger retard naturel entre le lâcher d'une clé et l'autre quand tout simplement taper un combinaison de touches.

EDIT 2: Ce principalement (quelques exceptions) fonctionne, sauf que je ne peux pas passer de diagonale à orthogonale sans relâcher toutes les touches.Il pourrait être impossible d'obtenir une version complètement lisse sans que toutes les clés soient libérées en premier sans changer l'orientation. Pourtant, je pense que ce serait possible avec un contrôleur de jeu ... c'est définitivement fait en pratique. Pourquoi pas avec un clavier?

while (is_running) 
{  
    /* 
    const Uint8 up = (key_states[SDL_SCANCODE_UP] == 0) ? 0 : UP; 
    const Uint8 down = (key_states[SDL_SCANCODE_DOWN] == 0) ? 0 : DOWN; 
    const Uint8 left = (key_states[SDL_SCANCODE_LEFT] == 0) ? 0 : LEFT; 
    const Uint8 right = (key_states[SDL_SCANCODE_RIGHT] == 0) ? 0 : RIGHT; 
    */ 



    bool _u = false; 
    bool _d = false; 
    bool _l = false; 
    bool _r = false; 

    Uint8 key_down = 0; 
    bool single_key_down = true; 
    SDL_Event event; 
    while (SDL_PollEvent(&event)) 
    { 
     switch (event.type) 
     { 
      case SDL_QUIT: 
       is_running = false; 
       break; 
      case SDL_KEYDOWN: 
        switch (event.key.keysym.scancode) 
        { 
         case SDL_SCANCODE_UP: 
          _u = true; 
          break; 
         case SDL_SCANCODE_DOWN: 
          _d = true; 
          break; 
         case SDL_SCANCODE_LEFT: 
          _l = true; 
          break; 
         case SDL_SCANCODE_RIGHT: 
          _r = true; 
          break; 
        } 
     } 
    } 

    const Uint8 up = key_states[SDL_SCANCODE_UP]; 
    const Uint8 down = key_states[SDL_SCANCODE_DOWN]; 
    const Uint8 left = key_states[SDL_SCANCODE_LEFT]; 
    const Uint8 right = key_states[SDL_SCANCODE_RIGHT]; 

    if ((_u && _l) || (_d && _r) 
     || (up && left) || (down && right)) 
    { 
     if (prev != 2) 
     { 
      puts("UP-LEFT/DOWN-RIGHT"); 
      prev = 2; 

     } 
     which_index = 2; 

    } 
    else if ((_u && _r) || (_d && _l) 
      || (up && right) || (down && left)) 
    { 
     if (prev != 3) 
     { 
      puts("UP-RIGHT/DOWN-LEFT"); 
      prev = 3; 
     } 
     which_index = 3; 
    } 
    else if (_u || _d) 
    { 
     puts("UP/DOWN"); 
     which_index = 0; 
    } 
    else if (_r || _l) 
    { 
     puts("LEFT/RIGHT"); 
     which_index = 1; 
    } 
} 

EDIT 3:

Moins d'une rotation transparente (pas de prise-like-a-d-pad-ness), mais moins de pression sur les doigts puisque vous pouvez simplement taper. Cela ne semble pas avoir de défauts:

while (is_running) 
{  
    /* 
    const Uint8 up = (key_states[SDL_SCANCODE_UP] == 0) ? 0 : UP; 
    const Uint8 down = (key_states[SDL_SCANCODE_DOWN] == 0) ? 0 : DOWN; 
    const Uint8 left = (key_states[SDL_SCANCODE_LEFT] == 0) ? 0 : LEFT; 
    const Uint8 right = (key_states[SDL_SCANCODE_RIGHT] == 0) ? 0 : RIGHT; 
    */ 



    bool _u = false; 
    bool _d = false; 
    bool _l = false; 
    bool _r = false; 

    Uint8 key_down = 0; 
    bool single_key_down = true; 
    SDL_Event event; 
    while (SDL_PollEvent(&event)) 
    { 
     switch (event.type) 
     { 
      case SDL_QUIT: 
       is_running = false; 
       break; 
      case SDL_KEYDOWN: 
        switch (event.key.keysym.scancode) 
        { 
         case SDL_SCANCODE_UP: 
          _u = true; 
          break; 
         case SDL_SCANCODE_DOWN: 
          _d = true; 
          break; 
         case SDL_SCANCODE_LEFT: 
          _l = true; 
          break; 
         case SDL_SCANCODE_RIGHT: 
          _r = true; 
          break; 
        } 
     } 
    } 

    const Uint8 up = key_states[SDL_SCANCODE_UP]; 
    const Uint8 down = key_states[SDL_SCANCODE_DOWN]; 
    const Uint8 left = key_states[SDL_SCANCODE_LEFT]; 
    const Uint8 right = key_states[SDL_SCANCODE_RIGHT]; 
    bool none_held = false; 
    if (up || down || left || right) 
    { 
     keys_reset = true; 
    } 
    else 
    { 
     none_held = true; 
    } 

    if (!none_held && keys_reset) 
    { 
     if ((_u && _l) || (_d && _r) 
      || (up && left) || (down && right)) 
     { 
      if (prev != 2) 
      { 
       puts("UP-LEFT/DOWN-RIGHT"); 
       prev = 2; 
      } 
      which_index = 2; 
      keys_reset = false; 
     } 
     else if ((_u && _r) || (_d && _l) 
       || (up && right) || (down && left)) 
     { 
      if (prev != 3) 
      { 
       puts("UP-RIGHT/DOWN-LEFT"); 
       prev = 3; 
      } 
      which_index = 3; 
      keys_reset = false; 
     } 
     else if (keys_reset) 
     { 
      if (_u || _d) 
      { 
       if (prev != 0) 
       { 
        puts("UP/DOWN"); 
        prev = 0; 
       } 
       which_index = 0; 
       keys_reset = false; 
      } 
      else if (_r || _l) 
      { 
       if (prev != 1) 
       { 
        puts("LEFT/RIGHT"); 
        prev = 1; 
       } 
       which_index = 1; 
       keys_reset = false; 
      } 
     } 
    } 
} 

Répondre

1

Vous ne recevrez jamais deux clés en même temps; il y aura toujours un certain retard qui laissera un espace pour que votre boucle d'interrogation principale s'exécute avant que la deuxième version de clé ne soit traitée.

Vous devrez adapter votre logique pour gérer cela. Il est possible que vous ne puissiez pas passer d'une combinaison de touches multiples (UP-RIGHT) à une seule (UP) sans relâcher toutes les touches. Ou supprimez complètement les combinaisons multi-touches et utilisez une autre touche unique (Home, Page Up, etc.).

Vous devez également tenir compte de ce qui se passe si l'utilisateur a 3 ou 4 touches enfoncées, soit maintenues, soit momentanément pendant une transition.

+0

Merci, mais j'ai en quelque sorte pensé que cela pourrait faire partie du problème. S'il vous plaît jeter un oeil à une modification à mon poste principal pour voir ce que je pensais jusqu'à présent. Fondamentalement, vous ne pouvez pas passer à une seule touche à partir d'une combinaison. Un seul robinet va fonctionner. Le problème est que j'ai aimé l'idée de soutenir les robinets ainsi que le style d-pad. Je pense que je devrais gérer une logique similaire avec une manette de jeu pour la saisie, dans ce cas, il doit y avoir un moyen de soutenir les robinets ainsi que de tenir plusieurs à la fois. Le jeu est rapide. Quoi qu'il en soit, j'ai des problèmes avec la logique de codage. Comment serait la version "sans changement"? – synchronizer

+0

Plus précisément, s'il n'y a pas de solution qui permette de tenir et de taper, comment vérifier que toutes les clés sont libérées? – synchronizer

+1

@synchronizer Toutes les touches sont relâchées lorsqu'aucune touche n'est enfoncée. D-pads sont des choses simples, et peuvent être conçus de manière à ce que les diagonales peuvent être tenues avec un doigt et libéré assez propre. Leur sortie est généralement de 4, 5, 8 ou 9 bits. Un clavier peut être assez compliqué, avec son propre microcontrôleur programmable (délai de la touche, taux de répétition, lumières). Maintenir une diagonale nécessite généralement d'utiliser deux doigts sur les touches, ce qui entraîne des intervalles plus longs entre les deux versions. Peut-être ajouter quelque chose de sorte que si une direction est tenue moins de 1/4 seconde, elle revient à la direction précédente? – 1201ProgramAlarm