Get the Mytodolist Free Android app from SlideME.

mercredi 21 août 2013

5/ Les entrées claviers et souris

            


              Par défaut, SimpleApplication met en place un contrôle de la caméra qui vous permet d'orienter la caméra avec les touches WASD, les touches fléchées et la souris. Vous pouvez l'utiliser comme une caméra volante au dessus de l'objet. Mais que faire si vous avez besoin d'avoir une autre vue que la vue de dessus , ou si vous voulez des touches pour déclencher des actions de jeu spéciaux?

Chaque jeu a ses raccourcis clavier personnalisés, et ce tutoriel vous expliquera comment vous les définisserez. Nous définissons d'abord les touches et les événements de la souris, puis nous définissons les actions qu'ils doivent déclencher.






Exemple de code


package jme3test.helloworld;
 
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.math.ColorRGBA;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
 
/** Sample 5 - how to map keys and mousebuttons to actions */
public class HelloInput extends SimpleApplication {
 
  public static void main(String[] args) {
    HelloInput app = new HelloInput();
    app.start();
  }
  protected Geometry player;
  Boolean isRunning=true;
 
  @Override
  public void simpleInitApp() {
    Box b = new Box(Vector3f.ZERO, 1, 1, 1);
    player = new Geometry("Player", b);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setColor("Color", ColorRGBA.Blue);
    player.setMaterial(mat);
    rootNode.attachChild(player);
    initKeys(); // load my custom keybinding
  }
 
  /** Custom Keybinding: Map named actions to inputs. */
  private void initKeys() {
    // You can map one or several inputs to one named action
    inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
    inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_J));
    inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_K));
    inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
                                      new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    // Add the names to the action listener.
    inputManager.addListener(actionListener, new String[]{"Pause"});
    inputManager.addListener(analogListener, new String[]{"Left", "Right", "Rotate"});
 
  }
 
  private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Pause") && !keyPressed) {
        isRunning = !isRunning;
      }
    }
  };
 
  private AnalogListener analogListener = new AnalogListener() {
    public void onAnalog(String name, float value, float tpf) {
      if (isRunning) {
        if (name.equals("Rotate")) {
          player.rotate(0, value*speed, 0);
        }
        if (name.equals("Right")) {
          Vector3f v = player.getLocalTranslation();
          player.setLocalTranslation(v.x + value*speed, v.y, v.z);
        }
        if (name.equals("Left")) {
          Vector3f v = player.getLocalTranslation();
          player.setLocalTranslation(v.x - value*speed, v.y, v.z);
        }
      } else {
        System.out.println("Press P to unpause.");
      }
    }
  };
}


Faire build et exécuter l'exemple.
  • Appuyez sur la barre d'espace ou cliquez pour faire tourner le cube.
  • Appuyez sur les touches J et K pour déplacer le cube.
  • Appuyez sur P pour mettre en pause et reprendre la lecture de la partie. Pendant la pause, le jeu ne devrait répondre aux entrées sauf celui de P.



La définition des mappages et déclencheurs (triggers)

D'abord vous inscrivez le nom de chaque cartographie avec son déclencheur. Rappelez-vous ce qui suit: 
  • Une entrée de déclenchement peut être une touche ou une action de la souris. 
         Par exemple, un mouvement de la souris, un clic de souris ou en appuyant sur la lettre "P". 
  • Le nom de la cartographie est une chaîne de caractère aux choix
          Le nom doit décrire l'action (par exemple, "Rotation"), et non le déclencheur car le déclencheur peut varier. 
  • Une cartographie nommée peut avoir plusieurs déclencheurs. 
          Par exemple, l'action "Rotation" peut être déclenchée par un clic et en appuyant sur la barre d'espace. 

Jetez un oeil sur le code suivant: 
  • Vous enregistrez le mappage nommé "Rotation" au déclencheur touche barre d'espace. 
             new KeyTrigger (KeyInput.KEY_SPACE)).

  • Dans la même ligne, vous enregistrez également "Rotation" au déclencheur clic de souris. 
      new MouseButtonTrigger (MouseInput.BUTTON_LEFT)


  • Vous cartographiez pause, Left, Right en association avec les touches K P, J, respectivement.

// You can map one or several inputs to one named action
    inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
    inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_J));
    inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_K));
    inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
                                      new MouseButtonTrigger(MouseInput.BUTTON_LEFT));



Maintenant, vous devez inscrire vos mappages de déclenchement.
  • Vous enregistrez l'action de pause au ActionListener, parce que c'est une action "on / off". 
  • Vous enregistrez les actions de mouvement à AnalogListener, parce qu'ils sont des actions graduelles.

    // Add the names to the action listener.
    inputManager.addListener(actionListener, new String[]{"Pause"});
    inputManager.addListener(analogListener, new String[]{"Left", "Right", "Rotate"});


Ce code va dans la méthode simpleInitApp (). Mais puisque nous allons probablement ajouter de nombreux raccourcis clavier, nous allons extraire ces lignes et les envelopper dans une méthode auxiliaire, initKeys (). La méthode initKeys () ne fait pas partie de l'entrée qui commande l'interface - vous pouvez l'appeler comme vous le voulez. Il suffit de ne pas oublier d'appeler votre méthode de la méthode initSimpleApp ().


La mise en œuvre des actions

Vous avez mappé les noms d'action aux déclencheurs d'entrée. Maintenant, vous allez spécifier les actions elles-mêmes.

Les deux méthodes importantes ici sont ActionListener avec sa méthode onAction (), et le AnalogListener avec sa méthode de onAnalog (). Dans ces deux méthodes, vous faite le test pour chaque mappage nommé, et faite appel de l'action de jeu que vous souhaitez déclencher.

Dans cet exemple, nous déclenchons les actions suivantes:
  • La cartographie Rotation déclenche l'action player.rotate (0, la valeur 0).
  • Les mappages left et right augmentent et diminuent la valeur de la coordonnée x du joueur.
  • La cartographie Pause retourne un booléen isRunning.
  • Nous voulons également que la vérification du booléen isRunning  se fasse avant toute action (autre que unpausing) est exécutée.



private ActionListener actionListener = new ActionListener() {
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Pause") && !keyPressed) {
        isRunning = !isRunning;
      }
    }
  };
 
  private AnalogListener analogListener = new AnalogListener() {
    public void onAnalog(String name, float value, float tpf) {
      if (isRunning) {
        if (name.equals("Rotate")) {
          player.rotate(0, value*speed, 0);
        }
        if (name.equals("Right")) {
          Vector3f v = player.getLocalTranslation();
          player.setLocalTranslation(v.x + value*speed, v.y, v.z);
        }
        if (name.equals("Left")) {
          Vector3f v = player.getLocalTranslation();
          player.setLocalTranslation(v.x - value*speed, v.y, v.z);
        }
      } else {
        System.out.println("Press P to unpause.");
      }
    }
  };

Vous pouvez également combiner les deux écouteurs en un seul, le moteur va envoyer les événements propres à chaque méthode (onAction ou onAnalog). Par exemple:


private MyCombinedListener combinedListener = new MyCombinedListener();
 
  private static class MyCombinedListener implements AnalogListener, ActionListener {
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Pause") && !keyPressed) {
        isRunning = !isRunning;
      }
    }
 
    public void onAnalog(String name, float value, float tpf) {
      if (isRunning) {
        if (name.equals("Rotate")) {
          player.rotate(0, value*speed, 0);
        }
        if (name.equals("Right")) {
          Vector3f v = player.getLocalTranslation();
          player.setLocalTranslation(v.x + value*speed, v.y, v.z);
        }
        if (name.equals("Left")) {
          Vector3f v = player.getLocalTranslation();
          player.setLocalTranslation(v.x - value*speed, v.y, v.z);
        }
      } else {
        System.out.println("Press P to unpause.");
      }
    }
  }
// ...
inputManager.addListener(combinedListener, new String[]{"Pause", "Left", "Right", "Rotate"});
 

C'est bon d'utiliser un seul des deux écouteurs, au lieu d'implémenter l'autre si vous n'utilisez pas ce type d'interaction. Dans la suite, nous verrons comment décider lequel des deux écouteurs convient le mieux à une situation donnée.



Analog, pressed, ou released ? ( le terme anglais est plus conviviable )



          Techniquement, chaque entrée peut être soit un «analogue» ou une action «numérique». Vous trouverez ici comment trouver le bon écouteur pour chaque type d'entrée.

Les mappages enregistrés à AnalogListener sont déclenchés à plusieurs reprises et progressivement.



  • paramètres:
    • JME vous donne accès au nom de l'action déclenchée.
    • JME vous donne accès à une valeur qui varie selon la force d'une entrée. Dans le cas d'une pression sur une touche ce sera la valeur de TPF pour lequel il a été enfoncée depuis le dernier frame. Pour d'autres entrées tels qu'un joystick la valeur indiquera également la force de l'entrée prémultipliée par TPF.


  • Exemple: les événements de navigation (par exemple, Gauche, Droite, Rotation, Exécuter), des situations où vous interagissez en continu.

Les mappages enregistrés à l' ActionListener sont soit numérique ou  des actions ( Enfoncées, relâchées, On ou Off)
  • paramètres:
    • JME vous donne accès au nom de l'action déclenchée.
    • JME vous donne accès à un booléen si la touche est pressée ou non.
  • Exemple: le bouton de pause, le tir, la sélection, le saut, cliquez interactions une à temps.
Astuce: Il est très fréquent que vous voulez qu'une action soit seulement déclenché une fois au moment où la touche est relâchée. Par exemple lors de l'ouverture d'une porte, en parcourant un état ​​booléen, ou ramasser un objet. Pour ce faire, vous utilisez un ActionListener et boolean de test pour ... &&! ​​KeyPressed. Pour un exemple, regardez le code du bouton de pause:



      if (name.equals("Pause") && !keyPressed) {
        isRunning = !isRunning;
      }


Tableau des déclencheurs

    Vous pouvez trouver la liste des entrées dans src/core/com/jme3/input/KeyInput.javaJoyInput.java, et MouseInput.java.


Voici un aperçu des constantes déclencheurs les plus courants:

DéclencheursCode
Sourie: click gaucheMouseButtonTrigger(MouseInput.BUTTON_LEFT)
Sourie: click droitMouseButtonTrigger(MouseInput.BUTTON_RIGHT)
Clavier: Caractères et nombresKeyTrigger(KeyInput.KEY_X)
Clavier: espaceKeyTrigger(KeyInput.KEY_SPACE)
Clavier: Return, EntréeKeyTrigger(KeyInput.KEY_RETURN), KeyTrigger(KeyInput.KEY_NUMPADENTER)
Clavier: echapKeyTrigger(KeyInput.KEY_ESCAPE)
Clavier: flêchesKeyTrigger(KeyInput.KEY_UP), KeyTrigger(KeyInput.KEY_DOWN)
KeyTrigger(KeyInput.KEY_LEFT), KeyTrigger(KeyInput.KEY_RIGHT)
Conseils:  Si vous ne vous souvenez pas d'une entrée constante au cours du développement, vous bénéficierez de la fonction de complétion de code automatique de l' IDE: Placez le curseur après par exemple KeyInput |. Et déclencher la complétion de code (avec ctrl+espace par exemple) pour sélectionner les identificateurs d'entrée possibles.



Conclusion:


Vous êtes maintenant en mesure d'ajouter des interactions personnalisées à votre jeu: Vous savez que vous devez d'abord définir les mappages de touches, puis les actions pour chaque mappage. Vous avez appris à répondre à des événements de la souris et au clavier. Vous comprenez la différence entre les entrées "analogique" (progressivement répétées) et les entrées "numérique" (on / off).

Maintenant, vous pouvez déjà écrire un petit jeu interactif! Mais ne serait-il pas plus cool si ces vieilles boîtes étaient un peu plus de jolies?

<<< Précédent                        Sommaire                                          Suivant >>>







2 commentaires: