Big Tuto SFML 2 : Rabidja v. 3.0

Chapitre 16 : Ajoutons des plateformes volantes !

Tutoriel présenté par : Jérémie F. Bellanger (Jay81)
Date d'écriture : 24 février 2015
Date de révision : 20 mars 2016

      Prologue

   Comme vous n'aurez pas manqué de le remarquer, on se retrouve pour l'instant dans notre jeu avec des tiles de plateformes flottantes, mais elles ne fonctionnent pas ! surprise Impossible donc de terminer le premier niveau officiel, par exemple... frown

   Mais on va remédier à ce problème dès maintenant ! angel

   Pour rappel, les tiles dont je vous parle sont ces tiles représentant une plateforme rouge avec une flèche en-dessous. Il y en a de deux types : celles qui vont de gauche à droite et celles qui vont de haut en bas. wink 

   Et voilà, comment on va les faire fonctionner : quand le jeu va rencontrer une de ces tiles à afficher, il ne va pas l'afficher, mais il va l'effacer et initialiser une plateforme à sa place. Cela correspond exactement à ce qu'on a déjà fait pour créer nos monstres. wink

   Ensuite, suivant le numéro de la tile (et donc suivant la flèche sur le petit dessin de la tile), on déplacera notre plateforme soit de gauche à droite, soit de haut en bas.

   Bien entendu, il va aussi falloir qu'on teste les collisions avec notre lapin-sauteur, si on ne veut pas qu'il passe au-travers ! indecision

   Allez, on est parti ! Les vacances sont finies, car ce tuto s'annonce ancore une fois assez long ! cheeky

 

      Nouveaux fichiers à ajouter au projet

   Avant de commencer, il va nous falloir ajouter un nouveau fichier image pour notre plateforme. Le voilà :


plateforme.png

   Enregistrez-le simplement dans le dossier graphics de votre projet, sous le nom : plateforme.png.
   Passons maintenant au code ! angel

 

      Le code

   On va commencer par créer une nouvelle classe Plateformes avec les fichiers plateformes.h et plateformes.cpp.

   Commençons par le header :   

Fichier : plateformes.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 PLATEFORMES_H
#define PLATEFORMES_H
 
#include <SFML/Graphics.hpp>
#include <iostream>
 
class Player;
class Map;
 
class Plateformes
{
 
 
public:
 
//Constructeur
Plateformes();
 
//Fonctions
void initialize(int Ax, int Ay, int Atype);
void update(Player &player);
void draw(Map &map, sf::RenderWindow &window);
void checkCollisions(Player &player);
 
 
 
private:
 
//Variables de la classe en accès privé
int x, y, h, w;
int direction;
 
//Sprite de la plateforme
sf::Texture Texture;
sf::Sprite Sprite;
 
//Coordonnées de départ
int beginX, beginY;
 
// Type de plateforme (horizontale ou verticale)
// Le joueur est-il dessus ?
int type, player_dessus;
 
 
/******************/
/* Constantes */
/******************/
 
const int PLATEFORM_SPEED = 2;
const int RIGHT = 1;
const int LEFT = 2;
const int UP = 3;
const int DOWN = 4;
 
/* Taille d'une tile (32 x 32 pixels) */
const int TILE_SIZE = 32;
 
 
};
#endif

    Notre classe va contenir tout d'abord plusieurs variables 

-  x et y seront les coordonnées de notre plateforme,

- h et w seront ses dimensions,

- Texture et Sprite contiendront notre sprite,

beginXbeginY : seront les coordonnées de départ de notre plateforme (son point de spawn correspondant au coin haut gauche de notre tile wink),

- type : va nous indiquer s'il s'agit de la plateforme de type 1 (qui va de gauche à droite) ou de type 2 (qui va de haut en bas);

- player_dessus : on l'utilisera comme un booléen, pour savoir si le joueur se trouve sur la plateforme ou non.

   On trouve ensuite plusieurs constantes pour indiquer la direction de la plateforme (une enum aurait fait le même effet, mais bon, pour 4 directions... cheeky), sa vitesse et notre TILE_SIZE habituel. wink

   Au niveau des fonctions maintenant, on reste dans du classique : une fonction d'initialisation, une fonction d'update et une de dessin (draw()), ainsi qu'une dernière fonction qui viendra tester les collisions avec le joueur (pour qu'il tienne dessus ! indecision).

  Passons maintenant au code :

Fichier : plateformes.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 "player.h"
#include "plateformes.h"
#include "map.h"
 
 
using namespace std;
using namespace sf;
 
 
//Constructeur
 
Plateformes::Plateformes()
{
//Chargement de la spritesheet de Rabidja
if (!Texture.loadFromFile("graphics/plateforme.png"))
{
// Erreur
cout << "Erreur durant le chargement du sprite de la plateforme." << endl;
}
else
Sprite.setTexture(Texture);
 
//Initialisation des variables :
x = y = h = w = 0;
beginX = beginY = type = 0;
direction = 0;
}
 
 
//Fonctions
void Plateformes::initialize(int Ax, int Ay, int Atype)
{
//On initialise notre plateforme
x = beginX = Ax;
y = beginY = Ay;
 
//Le sprite de la plateforme fait 96 x 24 pixels
w = 96;
h = 24;
 
type = Atype;
 
//Si elle est du type 2, elle monte, sinon elle va à droite
if (type == 2)
direction = UP;
else
direction = RIGHT;
 
}
 
 
void Plateformes::update(Player &player)
{
 
/* Déplacement UP/DOWN (haut/bas) */
if (type == 2)
{
if (direction == UP)
{
y -= PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec
pour éviter qu'il ne reste immobile et que la
plateforme se barre comme sur certains vieux
(mauvais) jeux...*/
if (player_dessus == 1)
player.setY(player.getY() - PLATEFORM_SPEED);
}
else
{
y += PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec */
if (player_dessus == 1)
player.setY(player.getY() + PLATEFORM_SPEED);
}
 
//Test : si la plateforme dépasse 5 tiles de largeur,
//on lui fait faire demi-tour pour ne pas qu'elle
//sorte de la map ! :D
if (y > beginY + 5 * TILE_SIZE)
direction = UP;
 
if (y < beginY)
direction = DOWN;
}
 
/* Déplacement RIGHT/LEFT */
else
{
if (direction == RIGHT)
{
x += PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec */
if (player_dessus == 1)
player.setX(player.getX() + PLATEFORM_SPEED);
}
else
{
x -= PLATEFORM_SPEED;
 
/* Si le joueur est dessus, on le déplace avec */
if (player_dessus == 1)
player.setX(player.getX() - PLATEFORM_SPEED);
}
 
//Test : si la plateforme dépasse 5 tiles de longueur,
//on lui fait faire demi-tour pour ne pas qu'elle
//fasse toute la map ! :D
if (x > beginX + 5 * TILE_SIZE)
direction = LEFT;
 
if (x < beginX)
direction = RIGHT;
}
 
}
 
 
void Plateformes::draw(Map &map, RenderWindow &window)
{
 
//On dessine la plateforme
Sprite.setPosition(Vector2f(x - map.getStartX(), y - map.getStartY()));
window.draw(Sprite);
 
}
 
 
 
void Plateformes::checkCollisions(Player &player)
{
 
if (player.getX() + player.getW() >= x
&& player.getX() <= x + w
&& player.getY() + player.getH() >= y
&& player.getY() + player.getH() < y + 32)
{
// On place le joueur sur la plateforme mobile
player.setY(y - player.getH());
player.setDirY(0);
player.setOnGround(true);
 
player_dessus = 1;
}
 
else
player_dessus = 0;
 
}

   Passons maintenant au survol de nos nouvelles fonctions cool :

- notre constructeur, tout d'abord, charge le sprite de la plateforme et initialise nos variables. wink
initialize() est appelée depuis la fonction map.draw() et initialise une nouvelle plateforme aux coordonnées passées, et avec le bon type (gauche/droite ou bas/haut). Cela correspond à peu près à ce que l'on fait déjà pour les monstres, si vous vous rappelez bien. cheeky
update() s'occupe de déplacer nos plateformes à la vitesse indiquée et dans le bons sens (tout en gérant le demi-tour au bout 5 tiles),
- draw() affiche simplement nos plateformes.

- et checkCollisions() se charge de vérifier si le joueur entre ou pas en collision avec une plateforme. Si c'est le cas, on le place sur la plateforme de la même façon, qu'on le plaçait sur une tile sol, et on passe la variable player_dessus à 1. Cette variable nous sert dans la fonction précédente update() pour déplacer le joueur en même temps que la plateforme, sinon elle filerait sans lui ! surprise

    Voilà, sinon tout est expliqué dans le code. wink

   Retournons maintenant dans notre classe Map, que l'on va modifier pour initialiser une plateforme quand on rencontrera la tile correspondante. 

 

Fichier : map.h : Remplacer le fichier 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 MAP_H
#define MAP_H
 
#include <SFML/Graphics.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
 
class Player;
class Monster;
class Plateformes;
 
class Map
{
public:
 
//Constructeur
Map();
 
//Accesseurs
int getBeginX(void) const;
int getBeginY(void) const;
int getStartX(void) const;
int getStartY(void) const;
int getMaxX(void) const;
int getMaxY(void) const;
int getTile(int y, int x) const;
int getLevel(void) const;
int getNombreMonstres(void) const;
int getNombrePlateformes(void) const;
 
//Mutateurs
void setLevel(int valeur);
void setStartX(int valeur);
void setStartY(int valeur);
void setTile(int y, int x, int valeur);
void setNombreMonstres(int valeur);
void setNombrePlateformes(int valeur);
 
//Fonctions
void drawBackground(sf::RenderWindow &window);
void loadMap(std::string filename);
void draw(int layer, sf::RenderWindow &window, Monster monster[], Plateformes plateforme[]);
void changeLevel(void);
void testDefilement(void);
void drawText(sf::RenderWindow &window, std::string message, int size, int x, int y, sf::Color color);
void drawHud(Player &player, sf::RenderWindow &window);
 
 
private:
//Variables de la classe en accès privé
 
//Numéro du tileset à utiliser
int tilesetAffiche;
 
/* Coordonnées de départ du héros, lorsqu'il commence le niveau */
int beginx, beginy;
 
/* Coordonnées de début, lorsqu'on doit dessiner la map */
int startX, startY;
 
/* Coordonnées max de fin de la map */
int maxX, maxY;
 
/* Tableau à double dimension représentant la map de tiles */
int tile[150][400];
 
//Deuxième couche de tiles
int tile2[150][400];
 
//Troisième couche de tiles
int tile3[150][400];
 
/* Timer et numéro du tileset à afficher pour animer la map */
int mapTimer, tileSetNumber;
 
//Numéro du niveau en cours
int level;
 
//Background
sf::Texture backgroundTexture;
sf::Sprite background;
 
//Tilesets
sf::Texture tileSet1Texture;
sf::Sprite tileSet1;
sf::Texture tileSet1BTexture;
sf::Sprite tileSet1B;
 
//Nombre max de monstres à l'écran
int nombreMonstres;
 
//Police de caractères
sf::Font font;
 
//HUD
sf::Texture HUDViesTexture;
sf::Sprite HUDVies;
sf::Texture HUDEtoilesTexture;
sf::Sprite HUDEtoiles;
 
//Nombre max de plateformes à l'écran
int nombrePlateformes;
 
 
/*******************/
/* Constantes */
/******************/
 
// Taille de la fenêtre : 800x480 pixels
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
 
/* 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 = 20;
 
//Nombre max de monstres gérés
const int MONSTRES_MAX = 50;
 
//Nombre max de plateformes gérées
const int PLATEFORMES_MAX = 50;
 
 
/*************************/
/* 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
   Dans ce fichier map.h
- on rajoute class Plateformes; en haut du fichier pour avoir accès à notre nouvelle classe.
- on met à jour le prototype de draw().
- on ajoute le prototype de l'accesseur getNombrePlateformes().
- on ajoute le prototype du mutateur setNombrePlateformes().
- on rajoute la variable nombrePlateformes, qui comptera le nombre de plateformes actives (comme pour les monstres).
- on rajoute la constante PLATEFORMES_MAX, qui contiendra le nombre de plateformes max activables en même temps dans un niveau.

   Passons maintenant au fichier map.cpp :

 

Fichier : map.cpp : Modifier le code (cf. changements) :

 
//Rabidja 3 - nouvelle version intégralement en SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#include "map.h"
#include "player.h"
#include "monster.h"
#include "plateformes.h"
 
using namespace std;
using namespace sf;
 
//Code coupé
 
int Map::getNombrePlateformes(void) const { return nombrePlateformes; }
 
//Code coupé
 
void Map::setNombrePlateformes(int valeur) { nombrePlateformes = valeur; }
 
//Code coupé
 
void Map::draw(int layer, RenderWindow &window, Monster monster[], Plateformes plateforme[])
{
int x, y, mapX, x1, x2, mapY, y1, y2, xsource, ysource, a;
 
/* On initialise mapX à la 1ère colonne qu'on doit blitter.
Celle-ci correspond au x de la map (en pixels) divisés par la taille d'une tile (32)
pour obtenir la bonne colonne de notre map
Exemple : si x du début de la map = 1026, on fait 1026 / 32
et on sait qu'on doit commencer par afficher la 32eme colonne de tiles de notre map */
mapX = startX / TILE_SIZE;
 
/* Coordonnées de départ pour l'affichage de la map : permet
de déterminer à quels coordonnées blitter la 1ère colonne de tiles au pixel près
(par exemple, si la 1ère colonne n'est visible qu'en partie, on devra commencer à blitter
hors écran, donc avoir des coordonnées négatives - d'où le -1). */
x1 = (startX % TILE_SIZE) * -1;
 
/* Calcul des coordonnées de la fin de la map : jusqu'où doit-on blitter ?
Logiquement, on doit aller à x1 (départ) + SCREEN_WIDTH (la largeur de l'écran).
Mais si on a commencé à blitter en dehors de l'écran la première colonne, il
va falloir rajouter une autre colonne de tiles sinon on va avoir des pixels
blancs. C'est ce que fait : x1 == 0 ? 0 : TILE_SIZE qu'on pourrait traduire par:
if(x1 != 0)
x2 = x1 + SCREEN_WIDTH + TILE_SIZE , mais forcément, c'est plus long ;)*/
x2 = x1 + SCREEN_WIDTH + (x1 == 0 ? 0 : TILE_SIZE);
 
/* On fait exactement pareil pour calculer y */
mapY = startY / TILE_SIZE;
y1 = (startY % TILE_SIZE) * -1;
y2 = y1 + SCREEN_HEIGHT + (y1 == 0 ? 0 : TILE_SIZE);
 
 
//On met en place un timer pour animer la map
if (mapTimer <= 0)
{
if (tileSetNumber == 0)
{
tileSetNumber = 1;
mapTimer = TIME_BETWEEN_2_FRAMES * 3;
}
else
{
tileSetNumber = 0;
mapTimer = TIME_BETWEEN_2_FRAMES * 3;
}
 
}
else
mapTimer--;
 
 
/* Dessine la carte en commençant par startX et startY */
 
/* On dessine ligne par ligne en commençant par y1 (0) jusqu'à y2 (480)
A chaque fois, on rajoute TILE_SIZE (donc 32), car on descend d'une ligne
de tile (qui fait 32 pixels de hauteur) */
if (layer == 1)
{
for (y = y1; y < y2; y += TILE_SIZE)
{
/* A chaque début de ligne, on réinitialise mapX qui contient la colonne
(0 au début puisqu'on ne scrolle pas) */
mapX = startX / TILE_SIZE;
 
/* A chaque colonne de tile, on dessine la bonne tile en allant
de x = 0 à x = 640 */
for (x = x1; x < x2; x += TILE_SIZE)
{
 
//Si la tile à dessiner n'est pas une tile vide
if (tile[mapY][mapX] != 0)
{
/*On teste si c'est une tile monstre */
if (tile[mapY][mapX] == TILE_MONSTRE)
{
//Si on le peut, on initialise un monstre en envoyant les coordonnées de la tile
if (nombreMonstres < MONSTRES_MAX)
{
monster[nombreMonstres].initialize(mapX * TILE_SIZE, mapY * TILE_SIZE);
nombreMonstres++;
}
 
//Et on efface cette tile de notre tableau pour éviter un spawn de monstres
//infini !
tile[mapY][mapX] = 0;
}
 
/*On teste si c'est une tile plateforme flottante */
else if (tile[mapY][mapX] >= TILE_PLATEFORME_DEBUT
&& tile[mapY][mapX] <= TILE_PLATEFORME_FIN)
{
//On initialise une plateforme flottante, si on le peut.
//Pour obtenir le type (dernier arg), on enlève le numéro de la 1ère tile plateforme
//(TILE_PLATEFORME_DEBUT) au numéro de la tile en cours (map.tile[mapY][mapX])
//et on rajoute 1 pour que le premier type soit le 1 et pas le 0 ;)
if (nombrePlateformes < PLATEFORMES_MAX)
{
plateforme[nombrePlateformes].initialize(mapX * TILE_SIZE, mapY * TILE_SIZE,
tile[mapY][mapX] - TILE_PLATEFORME_DEBUT + 1);
nombrePlateformes++;
}
 
//Et on efface cette tile de notre tableau pour éviter un spawn de plateformes
//infini !
tile[mapY][mapX] = 0;
}
 
}
 
/* Suivant le numéro de notre tile, on découpe le tileset (a = le numéro
de la tile */
a = tile[mapY][mapX];
 
/* Calcul pour obtenir son y (pour un tileset de 10 tiles
par ligne, d'où le 10 */
ysource = a / 10 * TILE_SIZE;
/* Et son x */
xsource = a % 10 * TILE_SIZE;
 
/* Fonction qui blitte la bonne tile au bon endroit suivant le timer */
if (tileSetNumber == 0)
{
tileSet1.setPosition(Vector2f(x, y));
tileSet1.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1);
}
else
{
tileSet1B.setPosition(Vector2f(x, y));
tileSet1B.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1B);
}
 
mapX++;
}
 
mapY++;
}
}
 
else if (layer == 2)
{
//Deuxième couche de tiles ;)
for (y = y1; y < y2; y += TILE_SIZE)
{
mapX = startX / TILE_SIZE;
 
for (x = x1; x < x2; x += TILE_SIZE)
{
 
//Si la tile à dessiner n'est pas une tile vide
if (tile2[mapY][mapX] != 0)
{
/*On teste si c'est une tile monstre */
if (tile2[mapY][mapX] == TILE_MONSTRE)
{
//Si on le peut, on initialise un monstre en envoyant les coordonnées de la tile
if (nombreMonstres < MONSTRES_MAX)
{
monster[nombreMonstres].initialize(mapX * TILE_SIZE, mapY * TILE_SIZE);
nombreMonstres++;
}
 
//Et on efface cette tile de notre tableau pour éviter un spawn de monstres
//infini !
tile2[mapY][mapX] = 0;
}
 
/*On teste si c'est une tile plateforme flottante */
else if (tile2[mapY][mapX] >= TILE_PLATEFORME_DEBUT
&& tile2[mapY][mapX] <= TILE_PLATEFORME_FIN)
{
//On initialise une plateforme flottante, si on le peut.
//Pour obtenir le type (dernier arg), on enlève le numéro de la 1ère tile plateforme
//(TILE_PLATEFORME_DEBUT) au numéro de la tile en cours (map.tile[mapY][mapX])
//et on rajoute 1 pour que le premier type soit le 1 et pas le 0 ;)
if (nombrePlateformes < PLATEFORMES_MAX)
{
plateforme[nombrePlateformes].initialize(mapX * TILE_SIZE, mapY * TILE_SIZE,
tile2[mapY][mapX] - TILE_PLATEFORME_DEBUT + 1);
nombrePlateformes++;
}
 
//Et on efface cette tile de notre tableau pour éviter un spawn de plateformes
//infini !
tile2[mapY][mapX] = 0;
}
}
 
/* Suivant le numéro de notre tile, on découpe le tileset (a = le numéro
de la tile */
a = tile2[mapY][mapX];
 
/* Calcul pour obtenir son y (pour un tileset de 10 tiles
par ligne, d'où le 10 */
ysource = a / 10 * TILE_SIZE;
/* Et son x */
xsource = a % 10 * TILE_SIZE;
 
/* Fonction qui blitte la bonne tile au bon endroit suivant le timer */
if (tileSetNumber == 0)
{
tileSet1.setPosition(Vector2f(x, y));
tileSet1.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1);
}
else
{
tileSet1B.setPosition(Vector2f(x, y));
tileSet1B.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1B);
}
 
mapX++;
}
 
mapY++;
}
}
 
else if (layer == 3)
{
//Troisième couche de tiles ;)
for (y = y1; y < y2; y += TILE_SIZE)
{
mapX = startX / TILE_SIZE;
 
for (x = x1; x < x2; x += TILE_SIZE)
{
 
//Si la tile à dessiner n'est pas une tile vide
if (tile3[mapY][mapX] != 0)
{
/*On teste si c'est une tile monstre */
if (tile3[mapY][mapX] == TILE_MONSTRE)
{
//Si on le peut, on initialise un monstre en envoyant les coordonnées de la tile
if (nombreMonstres < MONSTRES_MAX)
{
monster[nombreMonstres].initialize(mapX * TILE_SIZE, mapY * TILE_SIZE);
nombreMonstres++;
}
 
//Et on efface cette tile de notre tableau pour éviter un spawn de monstres
//infini !
tile3[mapY][mapX] = 0;
}
 
/*On teste si c'est une tile plateforme flottante */
else if (tile3[mapY][mapX] >= TILE_PLATEFORME_DEBUT
&& tile3[mapY][mapX] <= TILE_PLATEFORME_FIN)
{
//On initialise une plateforme flottante, si on le peut.
//Pour obtenir le type (dernier arg), on enlève le numéro de la 1ère tile plateforme
//(TILE_PLATEFORME_DEBUT) au numéro de la tile en cours (map.tile[mapY][mapX])
//et on rajoute 1 pour que le premier type soit le 1 et pas le 0 ;)
if (nombrePlateformes < PLATEFORMES_MAX)
{
plateforme[nombrePlateformes].initialize(mapX * TILE_SIZE, mapY * TILE_SIZE,
tile3[mapY][mapX] - TILE_PLATEFORME_DEBUT + 1);
nombrePlateformes++;
}
 
//Et on efface cette tile de notre tableau pour éviter un spawn de plateformes
//infini !
tile3[mapY][mapX] = 0;
}
}
 
/* Suivant le numéro de notre tile, on découpe le tileset (a = le numéro
de la tile */
a = tile3[mapY][mapX];
 
/* Calcul pour obtenir son y (pour un tileset de 10 tiles
par ligne, d'où le 10 */
ysource = a / 10 * TILE_SIZE;
/* Et son x */
xsource = a % 10 * TILE_SIZE;
 
/* Fonction qui blitte la bonne tile au bon endroit suivant le timer */
if (tileSetNumber == 0)
{
tileSet1.setPosition(Vector2f(x, y));
tileSet1.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1);
}
else
{
tileSet1B.setPosition(Vector2f(x, y));
tileSet1B.setTextureRect(sf::IntRect(xsource, ysource, TILE_SIZE, TILE_SIZE));
window.draw(tileSet1B);
}
 
mapX++;
}
 
mapY++;
}
}
 
}
   Dans ce fichier (map.cpp) : 
- on ajoute #include "plateformes.h"
- on met à jour la fonction draw() et initialisons nos premières plateformes !  Pour cela, on rajoute simplement un système de détection comme pour les monstres et on initialise une plateforme. wink
- on ajoute l'accesseur getNombrePlateformes().
- et enfin, on ajoute le mutateur setNombrePlateformes().
   Voilà, maintenant, que c'est fait, retournon à notre main() :

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"
#include "plateformes.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;
 
//Nombre max de plateformes à l'écran
const int PLATEFORMES_MAX = 50;

  On rajoute simplement à notre en-tête l'include du fichier plateformes.h et notre nouvelle constante PLATEFORMES_MAX.

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 16 : Plateformes - 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 instancie autant de classes que de plateformes gérables
Plateformes plateforme[PLATEFORMES_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(1);
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);
}
 
}
 
//On met à jour les plateformes une par une
for (int i = 0; i < map.getNombrePlateformes(); i++)
{
plateforme[i].update(player);
 
//On teste les collisions avec le joueur
plateforme[i].checkCollisions(player);
}
 
/** 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, plateforme);
 
// Affiche la map de tiles : layer 1 (couche active : sol, etc.)
map.draw(1, window, monster, plateforme);
 
// 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);
}
 
//On affiche les plateformes une par une
for (int i = 0; i < map.getNombrePlateformes(); i++)
{
plateforme[i].draw(map, window);
}
 
// Affiche la map de tiles : layer 3 (couche en foreground / devant)
map.draw(3, window, monster, plateforme);
 
//Affichage du HUD
map.drawHud(player, window);
 
window.display();
}
 
// On quitte
return 0;
 
}

   On met ensuite à jour le main() :

- en instanciant nos objets Plateformes, de la même façon que pour les monstres.
- en ajoutant l'appel à plateforme.update() pour chaque plateforme.
- en dessinant les plateformes une par une (draw()).
- et en mettant à jour map.draw(), en lui envoyant plateforme en argument.

   C'est bon, on a terminé ? indecision
   Presque, mais pas tout à fait cheeky : il faut encore qu'on remette le compteur de plateformes à zéro quand on meurt, sinon on risque de se retrouver avec des plateformes partout !!! angry

   Pour cela, c'est très simple, il suffit d'aller dans la fonction initialize() du fichier player.cpp et d'appeler map.setNombrePlateformes(0); ! angel

 

Fichier : player.cpp : Modifier initialize() en rajoutant setNombrePlateformes(0)  :

void Player::initialize(Map &map, bool newLevel)
{
//PV à 3
life = 3;
 
//Timer d'invincibilité à 0
invincibleTimer = 0;
 
//Indique l'état et la direction de notre héros
direction = RIGHT;
etat = IDLE;
 
//Indique le numéro de la frame où commencer
frameNumber = 0;
 
//...la valeur de son chrono ou timer
frameTimer = TIME_BETWEEN_2_FRAMES_PLAYER;
 
//... et son nombre de frames max (8 pour l'anim' IDLE
// = ne fait rien)
frameMax = 8;
 
/* Coordonnées de démarrage/respawn de notre héros */
if (checkpointActif == true)
{
x = respawnX;
y = respawnY;
}
else
{
x = map.getBeginX();
y = map.getBeginY();
}
 
//On réinitiliase les coordonnées de la caméra
//si on change de niveau
if (newLevel == true)
{
map.setStartX(map.getBeginX());
map.setStartY(map.getBeginY());
}
 
/* Hauteur et largeur de notre héros */
w = PLAYER_WIDTH;
h = PLAYER_HEIGTH;
 
//Variables nécessaires au fonctionnement de la gestion des collisions
timerMort = 0;
onGround = false;
 
//On réinitialise le nombre de monstres
map.setNombreMonstres(0);
 
//On réinitialise le nombre de plateformes
map.setNombrePlateformes(0);
 
}

   Voilà, on compile et on lance le programme ! wink   

   Maintenant, baladez-vous et vous verrez que les tiles plateformes sont maintenant remplacées par de jolies plateformes qui bougent ! surprise

   Si c'est pas chouette, ça ! angel Sautez dessus, et oh magie ! Notre lapin tient dessus et se déplace avec elles ! cheeky

   Vous allez enfin pouvoir parcourir le 1er niveau officiel du jeu en entier ! wink Et quand vous en aurez marre, il sera temps de passer au niveau 2, dans le prochain chapitre ! cool

 

   @ bientôt pour le chapitre 17 ! angel

                                                      Jay 

 

 
 

This site uses cookies to enable you to log in. We do not store or sell any personal data. By continuing to use this website, you agree to their use. Thanks!