Get the Mytodolist Free Android app from SlideME.

samedi 9 août 2014

11/ Jouer de la musique avec JMonkeyEngine


Ce tutoriel explique comment ajouter du son 3D pour un jeu, et comment faire jouer les sons avec des événements, comme le clic. Vous apprendrez à utiliser un écouteur audio et les noeuds audio. Vous pouvez également faire usage d'un écouteur d'action et un MouseButtonTrigger appris dans le tutoriel "Les entrées clavier et souris " pour produire avec un clic de souris le son d'un fusil de chasse.






Exemple de code


package jme3test.helloworld;
 
import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
 
/** Sample 11 - playing 3D audio. */
public class HelloAudio extends SimpleApplication {
 
  private AudioNode audio_gun;
  private AudioNode audio_nature;
  private Geometry player;
 
  public static void main(String[] args) {
    HelloAudio app = new HelloAudio();
    app.start();
  }
 
  @Override
  public void simpleInitApp() {
    flyCam.setMoveSpeed(40);
 
    /** just a blue box floating in space */
    Box box1 = new Box(1, 1, 1);
    player = new Geometry("Player", box1);
    Material mat1 = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
    mat1.setColor("Color", ColorRGBA.Blue);
    player.setMaterial(mat1);
    rootNode.attachChild(player);
 
    /** custom init methods, see below */
    initKeys();
    initAudio();
  }
 
  /** We create two audio nodes. */
  private void initAudio() {
    /* gun shot sound is to be triggered by a mouse click. */
    audio_gun = new AudioNode(assetManager, "Sound/Effects/Gun.wav", false);
    audio_gun.setPositional(false);
    audio_gun.setLooping(false);
    audio_gun.setVolume(2);
    rootNode.attachChild(audio_gun);
 
    /* nature sound - keeps playing in a loop. */
    audio_nature = new AudioNode(assetManager, "Sound/Environment/Ocean Waves.ogg", true);
    audio_nature.setLooping(true);  // activate continuous playing
    audio_nature.setPositional(true);   
    audio_nature.setVolume(3);
    rootNode.attachChild(audio_nature);
    audio_nature.play(); // play continuously!
  }
 
  /** Declaring "Shoot" action, mapping it to a trigger (mouse left click). */
  private void initKeys() {
    inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addListener(actionListener, "Shoot");
  }
 
  /** Defining the "Shoot" action: Play a gun sound. */
  private ActionListener actionListener = new ActionListener() {
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Shoot") && !keyPressed) {
        audio_gun.playInstance(); // play each instance once!
      }
    }
  };
 
  /** Move the listener with the a camera - for 3D audio. */
  @Override
  public void simpleUpdate(float tpf) {
    listener.setLocation(cam.getLocation());
    listener.setRotation(cam.getRotation());
  }
  
}
Lorsque vous exécutez l'exemple, vous devriez voir un cube bleu. Vous devriez entendre un son ambiant de nature semblable. Lorsque vous cliquez, vous entendez un coup fort.


Comprendre le code 


Dans la méthode initSimpleApp (), vous créez une géométrie audio.play() audio.playInstance()
Plays buffered sounds. Plays buffered sounds.
Plays streamed sounds. Cannot play streamed sounds.
The same sound cannot play twice at the same time. The same sounds can play multiple times and overlap.
simple de cube bleu appelé player puis l'attacher à la scène.

Jetons un coup d'oeil sur initAudio () pour apprendre à utiliser AudioNodes. 



AudioNodes 


L'ajout du son à votre jeu est assez simple: Sauvegardez vos fichiers audio dans votre répertoire de musique asset /Sound. JME3 prend en charge  les formats de fichier Ogg Vorbis (Ogg) et Wave (wav). 


Pour chaque son, vous créez un AudioNode. Vous pouvez utiliser un AudioNode comme un nœud dans la scène graphique JME, par exemple, en l'attachant à d'autres nœuds. Vous créez un nœud pour un bruit de tirs, et un nœud pour un son de la nature.


  private AudioNode audio_gun;
  private AudioNode audio_nature;
Regardez la méthode initAudio () personnalisée: là on  initialise des objets sonores et on régle leurs paramètres.


audio_gun = new AudioNode(assetManager, "Sound/Effects/Gun.wav", false);
    ...
audio_nature = new AudioNode(assetManager, "Sound/Environment/Nature.ogg", false);
Ces deux lignes permet de créer de nouveaux nœuds sonores à partir des fichiers audio donnés dans le AssetManager. Le boolean false signifie que vous souhaitez le mettre en mémoire tampon avant de jouer les sons. (Si vous définissez cette option à true, le son sera diffusé, ce qui est logique pour de très longues sons.) 


Vous voulez que le bruit de tirs sonne une fois (vous ne voulez pas faire une boucle). Vous pouvez également spécifier son volume comme facteur de gain (à 0, le son est coupé, à 2, il est deux fois plus fort, etc).


audio_gun.setPositional(false);
    audio_gun.setLooping(false);
    audio_gun.setVolume(2);
    rootNode.attachChild(audio_gun);
Le son de la nature est différente: Vous voulez que la musique joue en boucle comme fond sonore. C'est pourquoi vous définissez la boucle sur "true", et appelez immédiatement la méthode play () sur le noeud. Vous pouvez également choisir de régler son volume à 3.


    audio_nature.setLooping(true); // activate continuous playing
    ...
    audio_nature.setVolume(3);
    rootNode.attachChild(audio_nature);
    audio_nature.play(); // play continuously!
  }
Ici vous faites de audio_nature un son de position qui vient d'un certain endroit. Pour que vous donnez au nœud une translation explicite, dans cet exemple, vous choisissez Vector3f.ZERO (qui signifie les coordonnées 0.0f, 0.0f, 0.0f, le centre de la scène.) Depuis que jme prend en charge l'audio 3D, vous êtes maintenant capable d'entendre ce bruit venant de cet endroit particulier. Faire jouer du son dans un endroit précis est facultative. Si vous n'utilisez pas ces lignes, le bruit ambiant proviendra de toutes les directions.


    ...
    audio_nature.setPositional(true);
    audio_nature.setLocalTranslation(Vector3f.ZERO.clone());
    ...
Astuce: Fixez AudioNodes dans le graphe de scène comme tous les nœuds pour rendre certains nœuds mobiles à jour. Si vous ne les attachez pas, ils seront toujours audible et vous ne recevez pas un message d'erreur, mais les sons 3D ne fonctionneront pas comme prévu. AudioNodes peut être fixé directement au noeud racine ou il peut être fixé à l'intérieur d'un noeud qui se déplace dans la scène. Dans ce cas AudioNodes et la position 3D vont simulaténment générer du son lors du déplacement. 

Astuce: playInstance joue toujours le son à la position de AudioNode de sorte que plusieurs coups de feu d'une arme à feu (par exemple) peuvent être générés de cette façon, mais si plusieurs canons tirent à la fois, une AudioNode est nécessaire pour chacun d'eux. 


Déclenchement d'un son



Jetons un coup d'oeil sur initKeys (): Comme vous l'avez appris dans les tutoriels précédents, vous utilisez InputManager pour répondre à l'entrée de l'utilisateur. Ici vous ajoutez un mappage pour le bouton gauche de la souris, et nommer cet action "Shoot".


 /** Declaring "Shoot" action, mapping it to a trigger (mouse left click). */
  private void initKeys() {
    inputManager.addMapping("Shoot", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
    inputManager.addListener(actionListener, "Shoot");
  }
Vous déclarez que, lorsque le (bouton de la souris) déclencheur est enfoncé et relâché, vous jouez un son d' arme à feu.


  /** Defining the "Shoot" action: Play a gun sound. */
  private ActionListener actionListener = new ActionListener() {
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Shoot") && !keyPressed) {
        audio_gun.playInstance(); // play each instance once!
      }
    }
  };
Puisque vous voulez être en mesure de tirer rapidement à plusieurs reprises, de sorte que vous ne voulez pas attendre le bruit du tirs précédente à la fin avant que le prochain puisse commencer on utilise la méthode playInstance (). Cela signifie que chaque clic démarre une nouvelle instance du son, de sorte que deux cas peuvent se chevaucher. Vous ne définissez pas ce son dans une boucle, de sorte que chaque instance ne joue qu'une seule fois. Comme on peut s'y attendre d'un coup de feu. 


Ambiante ou situationnelle?

Les deux sons sont deux cas d'utilisation différents: 

  • Le coup de feu est la situation. Vous voulez le jouer qu'une seule fois, au moment où il est déclenché.
    • C'est pourquoi vous faite setLooping (false). 
  • Le son de la nature est un bruit de fond ambiant. Vous voulez le jouer depuis le début du jeu et continuer à le jouer, tant que le jeu fonctionne. 
    • C'est pourquoi vous setLooping (true)

Maintenant, pour tous les sons on sait quand on doit les passer en boucle ou non. 

Mis à part le booléen boucle, une autre différence est où  play().playInstance() est appelée sur ces nœuds.: 

  • Vous commencez à jouer le son de fond, celui de la nature juste après que vous l'avez créé, dans la méthode initAudio ().
 audio_nature.play(); // play continuously!
  • Le bruit de tirs, cependant, se déclenche situationnellement une fois, avec l'action d'entrée que vous avez défini dans le ActionListener.

  /** Defining the "Shoot" action: Play a gun sound. */
  private ActionListener actionListener = new ActionListener() {
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Shoot") && !keyPressed) {
        audio_gun.playInstance(); // play each instance once!
      }
    }
  };


Tampon ou streaming? 

       Le booléen dans le constructeur AudioNode définit si l'audio est mise en mémoire tampon (false) ou diffusé en streaming (true). 

Par exemple:

audio_gunshot = new AudioNode(assetManager, "Sound/Effects/Gun.wav", false); // buffered
...
audio_nature = new AudioNode(assetManager, "Sound/Environment/Nature.ogg", true); // streamed 

audio.play()audio.playInstance()
Utiliser la mémoire tampon pour jouer les sons.Utiliser la mémoire tampon pour jouer les sons.
Jouer le son en direct.Ne peut pas jouer directement le son
Le même son ne peut être joué des deux façons à la fois.Le même son peut être joué des deux façons à la fois.



Votre oreille dans la Scène 

         Pour créer un effet audio 3D, JME3 a besoin de connaître la position de la source sonore, et la position des oreilles du joueur. Les oreilles sont représentées par un objet 3D Audio Listener. L'objet écouteur est un objet par défaut dans un SimpleApplication


Afin de profiter au maximum de l'effet audio 3D, vous devez utiliser la méthode simpleUpdate () pour déplacer et faire pivoter l'auditeur (les oreilles du joueur) avec la caméra (les yeux du joueur).


  public void simpleUpdate(float tpf) {
    listener.setLocation(cam.getLocation());
    listener.setRotation(cam.getRotation());
  }
Si vous ne le faites pas, les résultats de l'audio 3D seront aléatoire. 


Global, directionnel, de position? 


Dans cet exemple, vous avez défini le son de la nature comme provenant d'une certaine position, mais pas le bruit de tirs. Cela signifie que votre balle est globale et peut être entendu partout avec le même volume. JME3 prend également en charge les sons directionnels que vous ne pouvez qu'entendre dans une certaine direction. 

Il est logique de faire le son de coup de feu de position, et que le bruit ambiant proviennent de toutes les directions. Comment décidez-vous quel type de son 3D à utiliser au cas par cas? 


  • Dans un jeu avec des ennemis qui bougent vous pouvez faire le coup de feu ou des sons de position . Dans ces cas, vous devez déplacer l' AudioNode à l'emplacement de l'ennemi avant  d'utiliser playInstance (). De cette façon, un joueur avec haut-parleurs stéréo entend de la direction dans laquelle l'ennemi va venir. 
  • De même, vous pouvez avoir des niveaux de jeu où vous voulez, un fond sonore à jouer à l'échelle globale. Dans ce cas, vous feriez de l' AudioNode ni position ni directionnel (mettre les deux à false). 
  • Si vous souhaitez obtenir un son «absorbée par les murs" et qui ne se diffuse que dans un sens, vous feriez un AudioNode directionnel. Ce tutoriel ne traite pas pour le moment des sons directionnels, vous pouvez lire sur Advanced Audio ici. 

En bref, vous devez choisir dans chaque situation si un son est à l'échelle globale, de direction ou de position. 



Conclusion 


Vous savez maintenant comment ajouter les deux types les plus communs de son à votre jeu: sons global et sons de position. Vous pouvez jouer des sons de deux façons: soit en continu dans une boucle, ou situationnel une seule fois. Vous connaissez la différence entre mémoire tampon des sons courts et le streaming sons longs. Vous connaissez la différence entre jouer plusieurs sons à la fois, et jouer des sons uniques qui ne peuvent pas se chevaucher avec eux-mêmes. Vous avez également appris à utiliser des fichiers audio qui sont soit .ogg ou format .wav. 

Astuce: la mise en œuvre audio de JME soutient également des effets plus avancés tels que la réverbération et l'effet Doppler. Utilisez ces fonctions de "pro" pour rendre son son audio différente selon que l'on soit dans le couloir, dans une grotte, à l'extérieur, ou dans une chambre tapissée. Pour en savoir plus sur les effets environnementaux de l'exemple de code inclus dans le répertoire de jme3test et de la documentation audio avancées. 


Vous voulez un peu de feu et d' explosions pour aller avec vos sons? Lisez la suite pour en apprendre davantage sur les effets.

<<Précédent                                   Sommaire                                          

Aucun commentaire:

Enregistrer un commentaire