
Big Tuto SFML 2 : Rabidja v. 3.0
Chapitre 14 : Monte le son !
Tutoriel présenté par : Jérémie F. Bellanger (Jay81)
Date d'écriture : 22 février 2015
Date de révision : 20 mars 2016
Prologue
Dans Rabidja... Personne ne vous entendra crier ! ![]()
Oui, c'est clair, y'a pas de son !
![]()
On va donc remédier à cela dès maintenant en rajoutant une jolie musique (de ma composition - on critique pas !
) et des effets sonores aussi appelés sounds Fx (ou effects). Mais si, vous savez ces petits bip, bip, blip, etc. ! ![]()
Allez, on est parti !
Nouveaux fichiers à ajouter au projet
Avant de commencer, il va nous falloir ajouter ces nouveaux fichiers à notre projet. Vous pourrez les télécharger dans l'archive ci-dessus. Là, copiez les dossier music et sounds dans votre projet. Bien sûr, si vous en avez, vous pouvez aussi utiliser vos propres fichiers (sachant que les miens sont sous copyright et restent utilisables uniquement dans le cadre de ce tuto - n'allez pas les vendre avec votre jeu
).
Attention : la SFML ne gère pas le format MP3 pour des problèmes de droits, utilisez donc le format ogg !
Il existe des sites web qui convertiront automatiquement et gratuitement vos mp3 en ogg. ![]()
Passons maintenant au code ! Youpi ! ![]()
Le code
On va commencer par créer une nouvelle classe Sounds. Vous devriez maintenant en avoir l'habitude. ![]()
Copiez-y le code suivant :
Fichier : sounds.h : Créer le fichier et y copier :
|
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#ifndef SOUNDS_H
#define SOUNDS_H
#include <SFML/Audio.hpp>
#include <iostream>
class Sounds
{
public:
//Constructeur
Sounds();
//Fonctions
void PlayMusic(bool valeur);
void PlaySoundFx(int type);
private:
//Variables de la classe en accès privé
//Attention : il faut bien déclarer les SoundBuffer AVANT les Sound !
sf::SoundBuffer bumper;
sf::SoundBuffer destroy;
sf::SoundBuffer jump;
sf::SoundBuffer star;
sf::Sound soundFxBumper;
sf::Sound soundFxDestroy;
sf::Sound soundFxJump;
sf::Sound soundFxStar;
sf::Music music;
public:
//Une enum pour la gestion des sons.
enum { BUMPER, DESTROY, JUMP, STAR };
};
#endif
|
Comme vous pouvez le voir, c'est très basique. ![]()
Au niveau variables, on va créer autant de SoundBuffer que de Sound pour contenir nos effets sonores en .wav. Le fonctionnement de ces variables en SFML ressemble beaucoup à celui des Sprites et des Textures, et je vous renvoie à la doc pour plus de détails. ![]()
Une variable music contiendra notre fichier ogg, qui sera lu en streaming (et pas copié en mémoire).
Enfin, une enum nous permettra de retrouver facilement le son à jouer, plutôt que de les appeler 1, 2, 3, etc. ![]()
Attention : Rappelez-vous de bien déclarer vos sf::SoundBuffer AVANT les sf::Sound, sinon, vous aurez une erreur de violation mémoire en quittant car le programme détruira les variables en sens inverse, ce qui donnera un pointeur sur une variable qui n'existe plus ! ![]()
Passons maintenant au fichier sounds.cpp :
Fichier : sounds.cpp : Créer le fichier et y copier :
|
//Rabidja 3 - nouvelle version intégralement en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#include "sounds.h"
using namespace std;
using namespace sf;
//Constructeur
Sounds::Sounds()
{
//On charge les sounds effects
if (!bumper.loadFromFile("sounds/bumper.wav"))
cout << "Erreur durant le chargement des sound Fx." << endl;
soundFxBumper.setBuffer(bumper);
if (!destroy.loadFromFile("sounds/destroy.wav"))
cout << "Erreur durant le chargement des sound Fx." << endl;
soundFxDestroy.setBuffer(destroy);
if (!jump.loadFromFile("sounds/jump.wav"))
cout << "Erreur durant le chargement des sound Fx." << endl;
soundFxJump.setBuffer(jump);
if (!star.loadFromFile("sounds/star.wav"))
cout << "Erreur durant le chargement des sound Fx." << endl;
soundFxStar.setBuffer(star);
//On joue la musique en boucle - celle-ci doit être au format ogg
//ATTENTION : FORMAT MP3 NON SUPPORTE !
if (!music.openFromFile("music/Caviator.ogg"))
cout << "Erreur durant le chargement de la musique." << endl;
}
//Fonctions
void Sounds::PlayMusic(bool valeur)
{
//On allume / éteint la musique en boucle suivant
//le booléen true ou false envoyé.
music.setLoop(true);
if (valeur)
music.play();
else
music.stop();
}
void Sounds::PlaySoundFx(int type)
{
//Suivant le type, on joue l'effet sonore
switch (type)
{
case BUMPER:
soundFxBumper.play();
break;
case DESTROY:
soundFxDestroy.play();
break;
case JUMP:
soundFxJump.play();
break;
case STAR:
soundFxStar.play();
break;
}
}
|
Bien, il va maintenant nous falloir intégrer nos sons dans nos classes pré-existantes. ![]()
Bien que ce ne soit pas particulièrement difficile, c'est assez fastidieux, car il y a de nombreuses petites choses à modifier.
Plutôt que de les voir les unes après les autres, j'ai donc choisi de vous redonner le code complet pour les headers, et le code complet des fonctions à modifier (plus faciles à copier/coller à la place de l'ancien code
) et de vous indiquer à côté les points du code qui ont été modifiés.
Fichier : monster.h : Remplacer le code précédent par :
|
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#ifndef MONSTER_H
#define MONSTER_H
#include <SFML/Graphics.hpp>
#include <iostream>
class Map;
class Player;
class Sounds;
class Monster
{
public:
//Constructeur
Monster();
//Accesseurs
int getX(void) const;
int getY(void) const;
int getW(void) const;
int getH(void) const;
float getDirX(void) const;
float getDirY(void) const;
bool getOnGround(void) const;
int getFrameNumber(void) const;
int getFrameTimer(void) const;
int getFrameMax(void) const;
int getEtat(void) const;
int getDirection(void) const;
int getSaveX(void) const;
int getSaveY(void) const;
bool getJumping(void) const;
float getDirXmem(void) const;
float getDirYmem(void) const;
int getPosXmem(void) const;
int getPosYmem(void) const;
int getWasOnGround(void) const;
int getWasOnSlope(void) const;
int getTimerMort(void) const;
//Mutateurs
void setX(int valeur);
void setY(int valeur);
void setW(int valeur);
void setH(int valeur);
void setDirX(float valeur);
void setDirY(float valeur);
void setOnGround(bool valeur);
void setTimerMort(int valeur);
//Fonctions
void initialize(int x1, int y1);
void draw(Map &map, sf::RenderWindow &window);
int update(Map &map, Player &player, Sounds &sounds);
void mapCollision(Map &map, Player &player);
int checkSlope(Map &map, Player &player);
int collide(Player &player);
int checkFall(Map &map);
void copy(Monster &monster);
private:
//Variables de la classe en accès privé
// Points de vie/santé + chrono d'invicibilité
int life, invincibleTimer;
// Coordonnées du sprite
int x, y;
// Largeur, hauteur du sprite
int h, w;
// Checkpoint pour le héros (actif ou non)
int checkpointActif;
// + coordonnées de respawn (réapparition)
int respawnX, respawnY;
// Variables utiles pour l'animation :
// Numéro de la frame (= image) en cours + timer
int frameNumber, frameTimer, frameMax;
// Nombre max de frames, état du sprite et direction
// dans laquelle il se déplace (gauche / droite)
int etat, direction;
// Variables utiles pour la gestion des collisions :
//Est-il sur le sol, chrono une fois mort
int timerMort;
bool onGround;
//Vecteurs de déplacement temporaires avant détection
//des collisions avec la map
float dirX, dirY;
//Sauvegarde des coordonnées de départ
int saveX, saveY;
//Variable pour le double saut
bool jumping;
//Gestion des pentes par Stephantasy
float dirXmem, dirYmem;
int posXmem, posYmem;
int wasOnGround;
int wasOnSlope;
//Spritesheet
sf::Texture Texture;
sf::Sprite Sprite;
/******************/
/* Constantes */
/******************/
/* Taille maxi de la map : 400 x 150 tiles */
const int MAX_MAP_X = 400;
const int MAX_MAP_Y = 150;
/* Taille d'une tile (32 x 32 pixels) */
const int TILE_SIZE = 32;
/* Constante pour l'animation */
const int TIME_BETWEEN_2_FRAMES_PLAYER = 4;
//Dimensions du monstre
const int MONSTER_WIDTH = 40;
const int MONSTER_HEIGTH = 50;
//Valeurs attribuées aux états/directions
const int IDLE = 0;
const int WALK = 1;
const int JUMP1 = 2;
const int JUMP2 = 3;
const int DEAD = 4;
const int RIGHT = 1;
const int LEFT = 2;
//Constantes définissant la gravité et la vitesse max de chute
const double GRAVITY_SPEED = 0.6;
const int MAX_FALL_SPEED = 15;
const int JUMP_HEIGHT = 10;
// Taille de la fenêtre : 800x480 pixels
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
/*************************/
/* VALEURS DES TILES */
/************************/
// Constante définissant le seuil entre les tiles traversables
// (blank) et les tiles solides
const int BLANK_TILE = 99;
//Plateformes traversables
const int TILE_TRAVERSABLE = 80;
//Tiles Power-ups
const int TILE_POWER_UP_DEBUT = 77;
const int TILE_POWER_UP_FIN = 79;
const int TILE_POWER_UP_COEUR = 78;
//Autres Tiles spéciales
const int TILE_RESSORT = 125;
const int TILE_CHECKPOINT = 23;
const int TILE_MONSTRE = 136;
const int TILE_PIKES = 127;
//Tiles plateformes mobiles
const int TILE_PLATEFORME_DEBUT = 130;
const int TILE_PLATEFORME_FIN = 131;
// Tiles pentes à 26.5° ; BenH = de BAS en HAUT ; HenB = De HAUT en BAS
const int TILE_PENTE_26_BenH_1 = 69;
const int TILE_PENTE_26_BenH_2 = 70;
const int TILE_PENTE_26_HenB_1 = 71;
const int TILE_PENTE_26_HenB_2 = 72;
};
#endif
|
Voici la liste des modifications opérées : ![]()
- on rajoute class Sounds; en haut du fichier.
- on rajoute Sounds &sounds en argument à la fonction update().
Fichier : monster.cpp : Remplacer seulement le code supplémentaire et les fonctions modifiées (ne pas supprimer les autres !) :
|
//Rabidja 3 - nouvelle version intégralement en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#include "monster.h"
#include "player.h"
#include "map.h"
//Include à rajouter
#include "sounds.h"
using namespace std;
using namespace sf;
//Code coupé...
int Monster::update(Map &map, Player &player, Sounds &sounds)
{
//Même fonctionnement que pour le joueur
if (timerMort == 0)
{
dirX = 0;
dirY += GRAVITY_SPEED;
if (dirY >= MAX_FALL_SPEED)
dirY = MAX_FALL_SPEED;
//Test de collision dans un mur : si la variable x reste la même, deux tours de boucle
//durant, le monstre est bloqué et on lui fait faire demi-tour.
if (x == saveX || checkFall(map) == 1)
{
if (direction == LEFT)
{
direction = RIGHT;
}
else
{
direction = LEFT;
}
}
//Déplacement du monstre selon la direction
if (direction == LEFT)
dirX -= 2;
else
dirX += 2;
//On sauvegarde les coordonnées du monstre pour gérer le demi-tour
//avant que mapCollision() ne les modifie.
saveX = x;
//On détecte les collisions avec la map comme pour le joueur
mapCollision(map, player);
//On détecte les collisions avec le joueur
//Si c'est égal à 1, on diminue ses PV
if (collide(player) == 1)
{
if (player.getLife() > 1)
{
//On blesse le joueur
player.playerHurts(sounds);
//Et on tue le monstre
timerMort = 1;
}
else
{
player.killPlayer(sounds);
}
}
else if (collide(player) == 2)
{
//On met le timer à 1 pour tuer le monstre intantanément
timerMort = 1;
//On joue le sound Fx
sounds.PlaySoundFx(sounds.DESTROY);
}
}
//Si le monstre meurt, on active une tempo
if (timerMort > 0)
{
timerMort--;
/* Si le monstre meurt, on renvoie 2 pour le remplace simplement par le dernier
monstre du tableau dans le main puis on rétrécit le tableau d'une case
(on ne peut pas laisser de case vide), sinon on renvoie 0 */
if (timerMort == 0)
return 2;
else
return 0;
}
else
return 0;
}
//Code coupé...
|
Voici la liste des modifications opérées :
- on rajoute #include "sounds.h" en haut du fichier.
- on rajoute Sounds &sounds en argument à update()
- dans la fonction update() :
- on rajoute un appel à PlaySoundFx() dans : if (collide(player) == 2).
- on met à jour l'appel à killPlayer() et playerHurts() en leur passant sounds en argument.
Passons à la classe Player : ![]()
Fichier : player.h : Remplacer le code précédent par :
|
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#ifndef PLAYER_H
#define PLAYER_H
#include <SFML/Graphics.hpp>
#include <iostream>
class Map;
class Input;
class Sounds;
class Player
{
public:
//Structures
struct Point { int x, y; };
//Constructeur
Player();
//Accesseurs
int getX(void) const;
int getY(void) const;
int getW(void) const;
int getH(void) const;
float getDirX(void) const;
float getDirY(void) const;
int getOnGround(void) const;
int getLife(void) const;
int getVies(void) const;
int getEtoiles(void) const;
int getDirection(void) const;
//Mutateurs
void setX(int valeur);
void setY(int valeur);
void setW(int valeur);
void setH(int valeur);
void setDirX(float valeur);
void setDirY(float valeur);
void setOnGround(bool valeur);
void setTimerMort(int valeur);
void setVies(int valeur);
void setEtoiles(int valeur);
void setCheckpoint(bool valeur);
void killPlayer(Sounds &sounds);
void playerHurts(Sounds &sounds);
//Fonctions
void initialize(Map &map, bool newLevel);
void draw(Map &map, sf::RenderWindow &window);
void update(Input &input, Map &map, Sounds &sounds);
void centerScrolling(Map &map);
void mapCollision(Map &map, Sounds &sounds);
Point segment2segment(int Ax0, int Ay0, int Bx0, int By0, int Cx0, int Cy0, int Dx0, int Dy0);
void getSlopeSegment(int tx, int ty, int pente, Point &s1, Point &s2);
int slopeEquation(int pente, double *a, double *b);
int checkSlope(Map &map);
private:
//Variables de la classe en accès privé
// Points de vie/santé + chrono d'invicibilité
int life, invincibleTimer;
//Vies et étoiles (100 étoiles = 1 vie)
int vies, etoiles;
// Coordonnées du sprite
int x, y;
// Largeur, hauteur du sprite
int h, w;
// Checkpoint pour le héros (actif ou non)
bool checkpointActif;
// + coordonnées de respawn (réapparition)
int respawnX, respawnY;
// Variables utiles pour l'animation :
// Numéro de la frame (= image) en cours + timer
int frameNumber, frameTimer, frameMax;
// Nombre max de frames, état du sprite et direction
// dans laquelle il se déplace (gauche / droite)
int etat, direction;
// Variables utiles pour la gestion des collisions :
//Est-il sur le sol, chrono une fois mort
int timerMort;
bool onGround;
//Vecteurs de déplacement temporaires avant détection
//des collisions avec la map
float dirX, dirY;
//Sauvegarde des coordonnées de départ
int saveX, saveY;
//Variable pour le double saut
bool Playerjump;
//Gestion des pentes par Stephantasy
float dirXmem, dirYmem;
int posXmem, posYmem;
int wasOnGround;
int wasOnSlope;
//Spritesheet de Rabidja
sf::Texture rabidjaTexture;
sf::Sprite rabidja;
//Nombre max de levels
const int LEVEL_MAX = 2;
/******************/
/* Constantes */
/******************/
/* Taille maxi de la map : 400 x 150 tiles */
const int MAX_MAP_X = 400;
const int MAX_MAP_Y = 150;
/* Taille d'une tile (32 x 32 pixels) */
const int TILE_SIZE = 32;
/* Constante pour l'animation */
const int TIME_BETWEEN_2_FRAMES_PLAYER = 4;
/* Taille du sprite de notre héros (largeur = width et hauteur = heigth) */
const int PLAYER_WIDTH = 40;
const int PLAYER_HEIGTH = 50;
//Vitesse de déplacement en pixels du sprite
const int PLAYER_SPEED = 4;
//Valeurs attribuées aux états/directions
const int IDLE = 0;
const int WALK = 1;
const int JUMP1 = 2;
const int JUMP2 = 3;
const int DEAD = 4;
const int RIGHT = 1;
const int LEFT = 2;
//Constantes définissant la gravité et la vitesse max de chute
const double GRAVITY_SPEED = 0.6;
const int MAX_FALL_SPEED = 15;
const int JUMP_HEIGHT = 10;
// Taille de la fenêtre : 800x480 pixels
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
//Constantes pour les limites de la caméra avant scrolling
const int LIMITE_X = 400;
const int LIMITE_Y = 220;
const int LIMITE_W = 100;
const int LIMITE_H = 80;
//Enum pour les boutons
const enum{ up, down, right, left, attack, jump, enter };
/*************************/
/* VALEURS DES TILES */
/************************/
// Constante définissant le seuil entre les tiles traversables
// (blank) et les tiles solides
const int BLANK_TILE = 99;
//Plateformes traversables
const int TILE_TRAVERSABLE = 80;
//Tiles Power-ups
const int TILE_POWER_UP_DEBUT = 77;
const int TILE_POWER_UP_FIN = 79;
const int TILE_POWER_UP_COEUR = 78;
//Autres Tiles spéciales
const int TILE_RESSORT = 125;
const int TILE_CHECKPOINT = 23;
const int TILE_MONSTRE = 136;
const int TILE_PIKES = 127;
//Tiles plateformes mobiles
const int TILE_PLATEFORME_DEBUT = 130;
const int TILE_PLATEFORME_FIN = 131;
// Tiles pentes à 26.5° ; BenH = de BAS en HAUT ; HenB = De HAUT en BAS
const int TILE_PENTE_26_BenH_1 = 69;
const int TILE_PENTE_26_BenH_2 = 70;
const int TILE_PENTE_26_HenB_1 = 71;
const int TILE_PENTE_26_HenB_2 = 72;
};
#endif
|
Voici la liste des modifications opérées :
- On rajoute class Sounds; en haut du fichier.
- on rajoute Sounds &sounds en argument à killPlayer() et playerHurts().
- on rajoute Sounds &sounds en argument à update() et mapCollision().
Fichier : player.cpp : Remplacer seulement le code supplémentaire et les fonctions modifiées (ne pas supprimer les autres !) :
|
//Rabidja 3 - nouvelle version intégralement en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#include "player.h"
#include "map.h"
#include "input.h"
//Include à rajouter
#include "sounds.h"
using namespace std;
using namespace sf;
//Code coupé...
void Player::killPlayer(Sounds &sounds)
{
//On met le timer à 1 pour tuer le joueur intantanément
timerMort = 1;
//On joue le sound Fx
sounds.PlaySoundFx(sounds.DESTROY);
}
void Player::playerHurts(Sounds &sounds)
{
//Si le timer d'invincibilité est à 0
//on perd un coeur
if (invincibleTimer == 0)
{
life--;
invincibleTimer = 80;
//et on fait sauter le joueur
dirY = -JUMP_HEIGHT;
//On joue le sound Fx
sounds.PlaySoundFx(sounds.DESTROY);
}
}
//Code coupé...
void Player::update(Input &input, Map &map, Sounds &sounds)
{
//On rajoute un timer au cas où notre héros mourrait lamentablement en tombant dans un trou...
//Si le timer vaut 0, c'est que tout va bien, sinon, on le décrémente jusqu'à 0, et là,
//on réinitialise.
//C'est pour ça qu'on ne gère le joueur que si ce timer vaut 0.
if (timerMort == 0)
{
//On gère le timer de l'invincibilité
if (invincibleTimer > 0)
invincibleTimer--;
//On réinitialise notre vecteur de déplacement latéral (X), pour éviter que le perso
//ne fonce de plus en plus vite pour atteindre la vitesse de la lumière ! ;)
//Essayez de le désactiver pour voir !
dirX = 0;
// La gravité fait toujours tomber le perso : on incrémente donc le vecteur Y
dirY += GRAVITY_SPEED;
//Mais on le limite pour ne pas que le joueur se mette à tomber trop vite quand même
if (dirY >= MAX_FALL_SPEED)
dirY = MAX_FALL_SPEED;
//Voilà, au lieu de changer directement les coordonnées du joueur, on passe par un vecteur
//qui sera utilisé par la fonction mapCollision(), qui regardera si on peut ou pas déplacer
//le joueur selon ce vecteur et changera les coordonnées du player en fonction.
if (input.getButton().left == true)
{
dirX -= PLAYER_SPEED;
//Et on indique qu'il va à gauche (pour le flip
//de l'affichage, rappelez-vous).
direction = LEFT;
//Si ce n'était pas son état auparavant et qu'il est bien sur
//le sol (car l'anim' sera différente s'il est en l'air)
if (etat != WALK && onGround == true)
{
//On enregistre l'anim' de la marche et on l'initialise à 0
etat = WALK;
frameNumber = 0;
frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
frameMax = 8;
}
}
//Si on détecte un appui sur la touche fléchée droite
else if (input.getButton().right == true)
{
//On augmente les coordonnées en x du joueur
dirX += PLAYER_SPEED;
//Et on indique qu'il va à droite (pour le flip
//de l'affichage, rappelez-vous).
direction = RIGHT;
//Si ce n'était pas son état auparavant et qu'il est bien sur
//le sol (car l'anim' sera différente s'il est en l'air)
if (etat != WALK && onGround == true)
{
//On enregistre l'anim' de la marche et on l'initialise à 0
etat = WALK;
frameNumber = 0;
frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
frameMax = 8;
}
}
//Si on n'appuie sur rien et qu'on est sur le sol, on charge l'animation marquant l'inactivité (Idle)
else if (input.getButton().right == false && input.getButton().left == false && onGround == true)
{
//On teste si le joueur n'était pas déjà inactif, pour ne pas recharger l'animation
//à chaque tour de boucle
if (etat != IDLE)
{
//On enregistre l'anim' de l'inactivité et on l'initialise à 0
etat = IDLE;
frameNumber = 0;
frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
frameMax = 8;
}
}
//Et voici la fonction de saut très simple :
//Si on appuie sur la touche saut et qu'on est sur le sol, alors on attribue une valeur
//négative au vecteur Y
//parce que sauter veut dire se rapprocher du haut de l'écran et donc de y=0.
if (input.getButton().jump == true)
{
if (onGround == true)
{
dirY = -JUMP_HEIGHT;
onGround = false;
Playerjump = true;
//On joue le sound Fx
sounds.PlaySoundFx(sounds.JUMP);
}
// Si on est en saut 1, on peut faire un deuxième bond et on remet jump1 à 0
else if (Playerjump == true)
{
dirY = -JUMP_HEIGHT;
Playerjump = false;
//On joue le sound Fx
sounds.PlaySoundFx(sounds.JUMP);
}
input.setButton(jump, false);
}
/* Réactive la possibilité de double saut si on tombe sans sauter */
if (onGround == true)
Playerjump = true;
//On gère l'anim du saut
if (onGround == false)
{
//Si on est en saut 1, on met l'anim' du saut normal
if (Playerjump == true)
{
if (etat != JUMP1)
{
etat = JUMP1;
frameNumber = 0;
frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
frameMax = 2;
}
}
else
{
if (etat != JUMP2)
{
etat = JUMP2;
frameNumber = 0;
frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
frameMax = 4;
}
}
}
//On rajoute notre fonction de détection des collisions qui va mettre à
//jour les coordonnées de notre super lapin.
mapCollision(map, sounds);
//On gère le scrolling (fonction ci-dessous)
centerScrolling(map);
}
//Gestion de la mort quand le héros tombe dans un trou :
//Si timerMort est différent de 0, c'est qu'il faut réinitialiser le joueur.
//On ignore alors ce qui précède et on joue cette boucle (un wait en fait) jusqu'à ce que
// timerMort == 1. A ce moment-là, on le décrémente encore -> il vaut 0 et on réinitialise
//le jeu avec notre bonne vieille fonction d'initialisation ;) !
if (timerMort > 0)
{
timerMort--;
if (timerMort == 0)
{
//On perd une vie
vies--;
// Si on est mort, on réinitialise le niveau
map.changeLevel();
initialize(map, false);
}
}
}
//Code coupé...
void Player::mapCollision(Map &map, Sounds &sounds)
{
//Code coupé...
|
Voici la liste des modifications opérées :
- on rajoute #include "sounds.h" en haut du fichier.
- on rajoute Sounds &sounds en argument à killPlayer() et playerHurts().
- on rajoute Sounds &sounds en argument à update() et mapCollision().
- dans killPlayer() : on rajoute un appel à PlaySoundFx().
- dans playerHurts() : on rajoute un appel à PlaySoundFx().
- dans update() :
- on rajoute un appel à PlaySoundFx() quand on saute et double saute.
- on rajoute l'argument sounds à l'appel de mapCollision().
Fichier : main.h : Remplacer le code précédent par :
|
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#include <cstdlib>
#include <iostream>
#include <SFML/Graphics.hpp>
#include "input.h"
#include "map.h"
#include "player.h"
#include "monster.h"
#include "sounds.h"
using namespace std;
using namespace sf;
// Taille de la fenêtre : 800x480 pixels
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
//Nombre max de monstres à l'écran
const int MONSTRES_MAX = 50;
|
Et voilà, passons maintenant au main(). Ici, on rajoute simplement : #include "sounds.h". ![]()
Fichier : main.cpp : Remplacer le code précédent par :
|
//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
//Big Tuto C++/SFML 2.2 - Février 2015 - Mise à jour 1.2
#include "main.h"
int main(int argc, char *argv[])
{
// Création d'une fenêtre en SFML
RenderWindow window(VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32),
"Rabidja 3.0 - Chapitre 14 : Son - Big Tuto SFML2 - www.meruvia.fr");
//Limite les fps à 60 images / seconde
window.setFramerateLimit(60);
//On active la synchro verticale
window.setVerticalSyncEnabled(true);
//Instanciation des classes
Input input;
Map map;
Player player;
Sounds sounds;
//On instancie autant de classes que de monstres gérables
Monster monster[MONSTRES_MAX];
//On lance la musique en boucle
sounds.PlayMusic(true);
//On commence au premier niveau (vous pouvez aussi mettre 2 pour tester le 2ème niveau)
map.setLevel(2);
map.changeLevel();
//On initialise le player
player.initialize(map, true);
player.setVies(3);
player.setEtoiles(0);
// Boucle infinie, principale, du jeu
while (window.isOpen())
{
/** GESTION DES INPUTS (CLAVIER, JOYSTICK) **/
input.gestionInputs(window);
/** MISES A JOUR - UPDATES **/
//On met à jour le player : Rabidja
player.update(input, map, sounds);
//On met à jour les monstres un par un
for (int i = 0; i < map.getNombreMonstres(); i++)
{
if (monster[i].update(map, player, sounds) == 2)
{
//Si l'update du monstre renvoie 2, c'est qu'il doit mourir :
//on copie à sa place le dernier monstre avant de retirer un monstre
monster[i].copy(monster[map.getNombreMonstres() - 1]);
map.setNombreMonstres(map.getNombreMonstres() - 1);
}
}
/** DESSIN - DRAW **/
//On dessine tout
window.clear();
//On affiche le background
map.drawBackground(window);
// Affiche la map de tiles : layer 2 (couche du fond)
map.draw(2, window, monster);
// Affiche la map de tiles : layer 1 (couche active : sol, etc.)
map.draw(1, window, monster);
// Affiche le joueur
player.draw(map, window);
//On affiche les monstres un par un
for (int i = 0; i < map.getNombreMonstres(); i++)
{
monster[i].draw(map, window);
}
// Affiche la map de tiles : layer 3 (couche en foreground / devant)
map.draw(3, window, monster);
//Affichage du HUD
map.drawHud(player, window);
window.display();
}
// On quitte
return 0;
}
|
Et enfin, voici la liste des modifications opérées dans le main() :
- on instancie la classe Sounds : Sounds sounds;
- puis on lance la musique en boucle : sounds.PlayMusic(true);
- on rajoute l'argument sounds à monster.update().
- on rajoute l'argument sounds à player.update().
Voilà, on compile et on lance le programme !
Et ?! Y'a du son !!
Hourra !
On va pouvoir entendre crier notre lapin ! ![]()
Bon, allez, je vous laisse sur un petit screenshot qui vous en dit long sur la musique de folie qui passe en arrière-plan, et je vous dis à bientôt ! ![]()

@ bientôt pour le chapitre 15 ! ![]()
Jay

English
Français 