Big Tuto SFML 2 / Action-RPG : Legends of Meruvia

Chapitre 16 : Ajoutons de la magie !

 

Tutoriel présenté par : Jérémie F. Bellanger (Jay81)
Date d'écriture : 7 juillet 2016
Date de révision : -

 

      Prologue

 

   Comme dans tout bon RPG, il nous faut de la magie ! wink

   Alors, bien entendu, quand on parle de magie, l'éventail des possibles est immense. surprise

   Pour notre part, nous allons nous contenter d'implémenter une magie offensive : l'orbe électrique. cool Mais après, il vous sera facile d'en ajouter d'autres en suivant ce modèle. wink

   Pour une boule de feu, il suffira par exemple de changer le sprite, les dégâts causés, et le nombre de points de magie consommés. angel

   Je compte aussi sur vous pour rajouter des magies plus exotiques et impressionnantes ! wink N'hésitez pas à venir les poster sur le forum ! cheeky

   Allez, on est parti !

 

 

 

      Nouveaux fichiers utilisés

 

   Pour ce chapitre, nous allons utiliser le sprite magic.png, situé dans le dossier graphics de votre projet. wink

 

magic.png

      Le code

 

   J'ai bâti la classe Magic en m'inspirant beaucoup de la classe Shuriken de Rabidja, d'où les nombreuses ressemblances que vous ne manquerez pas de remarquer, si vous avez déjà suivi ce tuto. wink

   De plus, cette classe va aussi beaucoup ressembler à celle de nos monstres (et dans le chapitre suivant à celle de nos explosions) donc si vous n'avez suivi que ce tuto-là, vous ne serez pas trop perdu non plus ! laugh

   Et voilà, il est maintenant temps de créer notre nouvelle classe Magic !

 

Fichier : Créer un nouveau fichier magic.h et y copier :

//Legends of Meruvia - C++ / SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
#ifndef MAGIC_H
#define MAGIC_H
 
#include <SFML/Graphics.hpp>
#include <iostream>
 
class Player;
class Map;
class Monster;
 
 
class Magic
{
 
 
public:
 
//Constructeur
Magic();
 
//Accesseurs
int getX(void) const;
int getY(void) const;
int getW(void) const;
int getH(void) const;
int getDirection(void) const;
double getRotation(void) const;
sf::Vector2f getCenter(void) const;
 
//Fonctions
void initialize(int Adirection, int Ax, int Ay);
int update(Player &player, Map &map);
void draw(Map &map, sf::RenderWindow &window);
int checkCollisions(Monster &monster);
void copy(Magic &magic);
 
 
 
private:
 
//Variables de la classe en accès privé
int x, y, h, w;
int direction;
 
//Pour gérer la rotation du sprite (shuriken)
double rotation;
sf::Vector2f center;
 
//Sprite
sf::Texture Texture;
sf::Sprite Sprite;
 
 
/******************/
/* Constantes */
/******************/
 
const int DOWN = 0;
const int UP = 1;
const int RIGHT = 2;
const int LEFT = 3;
 
const int TILE_SIZE = 32;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;
 
 
};
#endif

 

   Comme vous pouvez le voir, pour gérer notre projectile magique, les variables nécessaires ne sont pas très nombreuses. wink
   Il nous faut simplement:
- ses coordonnées x et y,
- ses dimensions w et h,
- son centre center et son angle de rotation pour pouvoir le faire tourner sur lui-même (c'est plus joli), wink
- et enfin son Sprite et sa Texture.
 

   Le reste est très basique. On l'a déjà vu avec la classe Monster, notamment. wink

   Passons donc au code du fichier magic.cpp :

 

Fichier : Créer un nouveau fichier magic.cpp et y copier :

//Legends of Meruvia - C++ / SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#include "player.h"
#include "magic.h"
#include "map.h"
#include "monster.h"
 
 
using namespace std;
using namespace sf;
 
 
//Accesseurs
int Magic::getX(void) const { return x; }
int Magic::getY(void) const { return y; }
int Magic::getW(void) const { return w; }
int Magic::getH(void) const { return h; }
int Magic::getDirection(void) const { return direction; }
double Magic::getRotation(void) const { return rotation; }
sf::Vector2f Magic::getCenter(void) const { return center; }
 
 
 
//Constructeur
 
Magic::Magic()
{
//Chargement du sprite
if (!Texture.loadFromFile("graphics/magic.png"))
{
// Erreur
cout << "Erreur durant le chargement du sprite magic.png." << endl;
}
else
Sprite.setTexture(Texture);
 
//Initialisation des variables :
x = y = h = w = 0;
rotation = 0.0f;
center.x = center.y = 10;
direction = 0;
}
 
 
//Fonctions
void Magic::initialize(int Adirection, int Ax, int Ay)
{
//On initialise notre projectile magique
 
//Rotation
rotation = 0;
 
//Centre du projectile magique pour la rotation (le sprite fait 16 x 16 pixels)
 
center.x = 8;
center.y = 8;
 
w = h = 16;
 
/* Direction du projectile magique
Les valeurs sont proportionnelles au perso - à adpater
manuellement selon les cas :) */
if (Adirection == RIGHT)
{
x = Ax + 30;
y = Ay + 35;
direction = RIGHT;
}
else if (Adirection == LEFT)
{
x = Ax + 10;
y = Ay + 35;
direction = LEFT;
}
else if (Adirection == UP)
{
x = Ax + 10;
y = Ay + 5;
direction = UP;
}
else if (Adirection == DOWN)
{
x = Ax + 10;
y = Ay + 30;
direction = DOWN;
}
}
 
 
 
int Magic::update(Player &player, Map &map)
{
/* On se déplace : vers la droite : */
if (direction == RIGHT)
{
x += 6;
}
/* - vers la gauche : */
else if (direction == LEFT)
{
x -= 6;
}
/* - vers le haut : */
else if (direction == UP)
{
y -= 6;
}
/* - vers le bas : */
else if (direction == DOWN)
{
y += 6;
}
 
//On fait tourner le projectile magique
rotation += 20;
 
if (rotation >= 360)
rotation = 0;
 
 
// S'il sort de l'écran ou touche un mur, on renvoie la valeur 1 pour le supprimer, sinon 0
if (x < map.getStartX() || x > map.getStartX() + SCREEN_WIDTH
|| y < map.getStartY() || y > map.getStartY() + SCREEN_HEIGHT
|| map.getTile(y / TILE_SIZE, x / TILE_SIZE) == 1)
return 1;
else
return 0;
 
}
 
 
 
void Magic::draw(Map &map, RenderWindow &window)
{
//Le décalage voulu entre chaque sprite
int decalage = 8;
 
//On dessine
for (int i = 0; i < 4; i++)
{
//On change la transparence en fonction de i
//Le premier sprite est opaque puis ensuite
//ils deviennent de plus en plus transparents
Sprite.setColor(sf::Color(255, 255, 255, 255 - (i * 60)));
 
//On place le premier sprite à sa position normale, puis on place
//les suivants à la suite, en fonction de la direction
if (direction == UP)
Sprite.setPosition(Vector2f(x - map.getStartX(), y - map.getStartY() + (i * decalage)));
else if (direction == DOWN)
Sprite.setPosition(Vector2f(x - map.getStartX(), y - map.getStartY() - (i * decalage)));
else if (direction == RIGHT)
Sprite.setPosition(Vector2f(x - map.getStartX() - (i * decalage), y - map.getStartY()));
else if (direction == LEFT)
Sprite.setPosition(Vector2f(x - map.getStartX() + (i * decalage), y - map.getStartY()));
 
//On place l'origine du sprite au centre
//pour le faire tourner sur lui-même
Sprite.setOrigin(center);
Sprite.setRotation(rotation);
 
//On dessine le sprite
window.draw(Sprite);
}
 
}
 
 
 
int Magic::checkCollisions(Monster &monster)
{
 
//On teste pour voir s'il n'y a pas collision, si c'est le cas, on renvoie 0
if ((monster.getX() >= x + w)
|| (monster.getX() + monster.getW() <= x)
|| (monster.getY() >= y + h)
|| (monster.getY() + monster.getH() <= y)
)
return 0;
//Sinon, il y a collision et on renvoie 1.
else
return 1;
 
}
 
 
void Magic::copy(Magic &magic)
{
//Copie des variables nécessaires :
x = magic.getX();
y = magic.getY();
h = magic.getH();
w = magic.getW();
direction = magic.getDirection();
rotation = magic.getRotation();
center = magic.getCenter();
}

 

   Revenons un peu sur le contenu de notre fichier :

- on commence par quelques accesseurs classiques pour les variables de notre classe,

- on a ensuite notre constructeur, qui charge le sprite et initialise les variables.

- puis la fonction initialize() qui crée un projectile magique, si c'est possible, et l'oriente en fonction de la direction de notre héros (ce qui est plus logique ! indecision),

- update() s'occupe, quant à elle, de gérer leurs déplacements suivant qu'ils ont été lancés à droite ou à gauche, de les faire tourner en augmentant leur angle de rotation, et vérifie s'ils sortent de l'écran ou touchent une tile MUR (auquel cas, on les supprimera dans le main() wink).

draw() affiche simplement le projectile magique, en prenant en compte sa rotation. Notez que pour créer un effet sympa de déplacement "magique", j'ai choisi de ne pas dessiner un seul projectile mais plusieurs à la suite les uns des autres, et cela de façon de plus en plus transparente. Cela donne ainsi une impression de rapidité au projectile. wink Libre à vous de le garder ou pas, et de l'adapter selon vos besoins ! cheeky

- checkCollisions() sert à tester les collisions entre le projectile magique et un monstre. On s'en servira plus tard, en l'appelant depuis  le main().

- enfin copy() fera une copie de notre objet dans un autre, quand il sera détruit (comme pour les monstres wink).

   Comme vous pouvez le voir, on reste dans du classique. wink

 

   Bien, maintenant que c'est fait, nous allons intégrer tout ça à notre classe Playerwink

   Commençons par l'en-tête de la classe :

 

Fichier : player.h : Modifier le code :

//Rajouter :

class Magic;

 

//Fonctions : prototype à mettre à jour

void update(Input &input, Map &map, Magic magic[]); 

 

   Voici ce qui change :

- Ajout de class Magic;; en haut du fichier, à la suite des autres,

- Ajout de l'argument Magic magic[] au prototype de la fonction update(), pour qu'elle puisse par la suite créer de nouveaux projectiles magiques quand on appuiera sur la touche attaquer ! wink

 

   Passons maintenant au code du fichier player.cpp. Je n'ai reproduit ci-dessous que ce qui change wink:

 

Fichier : player.cpp : Modifier le code :

//Legends of Meruvia - C++ / SFML 2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#include "player.h"
#include "map.h"
#include "input.h"
#include "sounds.h"
 
//Rajouter :
#include "magic.h"
 
 
 
//Code coupé...
 
 
//Fonctions
 
//Fonctions
void Player::initialize(Map &map)
{
//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;
 
x = map.getBeginX();
y = map.getBeginY();
 
//On recentre la caméra
map.setStartX(map.getBeginX() - (SCREEN_WIDTH / 2));
map.setStartY(map.getBeginY() - (SCREEN_HEIGHT / 2));
 
/* 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;
isAttacking = 0;
 
//On réinitialise le nombre de monstres
map.setNombreMonstres(0);
 
//On réinitialise le nombre de projectiles magiques
magicNumber = 0;
 
map.setWarpDirection(-1);
}
 
 
//Code coupé...
 
 
 
void Player::reinitialize(Map &map)
{
// Coordonnées de démarrage de notre héros selon la direction de warp
//Si on n'a pas warpé, alors on commence aux coordonnées de départ de la map
if (map.getWarpDirection() == -1)
{
x = map.getBeginX();
y = map.getBeginY();
 
//On recentre la caméra
map.setStartX(map.getBeginX() - (SCREEN_WIDTH / 2));
map.setStartY(map.getBeginY() - (SCREEN_HEIGHT / 2));
}
//Si on a warpé en haut
else if (map.getWarpDirection() == UP)
{
//On change la valeur en y du héros pour qu'il se
//trouve en bas de la map
y = map.getMaxY() - h - 1;
 
//On recentre la caméra
map.setStartY(map.getMaxY() - SCREEN_HEIGHT);
}
//Si on a warpé en bas
else if (map.getWarpDirection() == DOWN)
{
//On change la valeur en y du héros pour qu'il se
//trouve en haut de la map
y = 1;
 
//On recentre la caméra
map.setStartY(0);
}
//Si on a warpé à gauche
else if (map.getWarpDirection() == LEFT)
{
//On change la valeur en x du héros pour qu'il se
//trouve à droite de la map
x = map.getMaxX() - w - 1;
 
//On recentre la caméra
map.setStartX(map.getMaxX() - SCREEN_WIDTH);
}
//Si on a warpé à droite
else if (map.getWarpDirection() == RIGHT)
{
//On change la valeur en x du héros pour qu'il se
//trouve à gauche de la map
x = 1;
 
//On recentre la caméra
map.setStartX(0);
}
 
//Si on a utilisé une warp spéciale
else if (map.getWarpDirection() == 4)
{
POINT point;
 
//On détecte la warp spéciale utilisée (1, 2, etc)
//et on enregistre ses coordonnées dans point
point.x = map.detectWarpSpe(numberSPE + SPE1).x;
point.y = map.detectWarpSpe(numberSPE + SPE1).y;
 
//On place le héros près de cette warp (sans la toucher)
//suivant la direction qu'il avait en arrivant :
//Ainsi s'il allait vers le haut, on va le faire réapparaître
//au-dessus de la warp, et ainsi de suite...
if (direction == UP)
{
x = point.x + 6;
y = point.y - h - 6;
}
else if (direction == DOWN)
{
x = point.x + 6;
y = point.y + TILE_SIZE + 6;
}
else if (direction == RIGHT)
{
x = point.x + TILE_SIZE + 6;
y = point.y + 6;
}
else if (direction == LEFT)
{
x = point.x - w - 6;
y = point.y + 6;
}
else
{
x = map.getBeginX();
y = map.getBeginY();
}
 
//On recentre la caméra
map.setStartX(x - (SCREEN_WIDTH / 2));
map.setStartY(y - (SCREEN_HEIGHT / 2));
}
 
//On réinitialise le nombre de monstres
map.setNombreMonstres(0);
 
//On réinitialise le nombre de projectiles magiques
magicNumber = 0;
}
 
 
//Code coupé...
 
 
void Player::update(Input &input, Map &map, Magic magic[])
{
//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 nos vecteurs de déplacement, 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;
dirY = 0;
 
//Gestion de la course en appuyant sur la touche courir
if(input.getButton().run)
isrunning = 1;
else
isrunning = 0;
 
//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 + isrunning;
//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 :
if(etat != WALK)
{
//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 + isrunning;
//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
if(etat != WALK)
{
//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 haut
else if(input.getButton().up == true)
{
//On augmente les coordonnées en x du joueur
dirY -= PLAYER_SPEED + isrunning;
//Et on indique qu'il va à droite (pour le flip
//de l'affichage, rappelez-vous).
direction = UP;
 
//Si ce n'était pas son état auparavant
if(etat != WALK)
{
//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 bas
else if(input.getButton().down == true)
{
//On augmente les coordonnées en x du joueur
dirY += PLAYER_SPEED + isrunning;
//Et on indique qu'il va à droite (pour le flip
//de l'affichage, rappelez-vous).
direction = DOWN;
 
//Si ce n'était pas son état auparavant
if(etat != WALK)
{
//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, on charge l'animation marquant l'inactivité (Idle)
else if(input.getButton().right == false && input.getButton().left == false &&
input.getButton().up == false && input.getButton().down == false)
{
//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;
}
}
 
 
//On gère la magie
if(input.getButton().magie)
{
//Si on le peut, on crée un nouveau shuriken
if(magicNumber < MAGIC_MAX && MP > 15)
{
magic[magicNumber].initialize(direction, x, y);
magicNumber++;
MP -= 15;
}
input.setButton(magie, false);
}
 
if(MP < MPmax)
MP += regainTime;
 
 
//On gère l'attaque
if(input.getButton().attack)
{
isAttacking = 1;
input.setButton(attack, false);
}
 
//On rajoute notre fonction de détection des collisions qui va mettre à
//jour les coordonnées de notre héros.
mapCollision(map);
 
//On gère le scrolling (fonction ci-dessous)
centerScrolling(map);
 
}
 
//Gestion de la mort :
//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)
{
// Si on est mort, on réinitialise le niveau
map.changeLevel();
initialize(map);
}
}
}

 

   Passons maintenant rapidement en revue ce qui a changé :

- on a tout d'abord ajouté #include "magic.h" en haut du fichier,

- ensuite, on a mis à jour nos fonctions initialize() et reinitialize() en remettant le nombre de projectiles magiques à zéro : magicNumber = 0;

- et enfin dans la fonction update()

- on lui a ajouté l'argument Magic magic[],

- et on a rajouté un petit bout de code qui va tester si on appuie sur la touche d'attaque magique : if (input.getButton().magie). Si c'est le cas, on crée un projectile magique si la jauge de MP le permet. Notez que chaque projectile coûte 15MP dans notre démo (sur une jauge de 100MP) et qu'on regagne de la magie progressivement : if (MP < MPmax) MP += regainTime; Mais vous pouvez adapter tout ça à votre sauce, bien sûr ! wink

 

   Bon, maintenant, que c'est fait, on va pouvoir mettre à jour notre main() :

 

Fichier : main.h : Modifier le code :

//Legends of Meruvia - C++ / 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 "magic.h"
 
using namespace std;
using namespace sf;
 
 
//Fonctions
void update(Input &input, Map &map, Player &player, Monster monster[], Sounds &sounds, Magic magic[]);
void draw(sf::RenderWindow &window, Map &map, Player &player, Monster monster[], Magic magic[]);
 
 
// 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 projectiles magiques à l'écran
const int MAGIC_MAX = 6;
const int TIME_BETWEEN_2_SHOTS = 30;
const int MOONWALK_TIMER = 8;
 
//Directions
const int DOWN = 0;
const int UP = 1;
const int RIGHT = 2;
const int LEFT = 3;

  

   Bon, en ce qui concerne l'en-tête :

- on rajoute en haut du fichier : #include "magic.h",

- on rajoute aussi MAGIC_MAX qui va définir le nombre max de projectiles qu'on pourra voir en même temps à l'écran, ainsi que quelques autres variables qui vont nous aider à gérer le timer entre 2 projectiles ainsi que la direction dudit projectile. wink

- enfin, on met à jour les prototypes de draw() et update() en rajoutant : Magic magic[].

 

Fichier : main.cpp : Modifier le code :

//Legends of Meruvia - C++ / SFML 2.3.2
//Copyright / Droits d'auteur : www.meruvia.fr - Jérémie F. Bellanger
 
#include "main.h"
 
 
int main(int argc, charargv[])
{
// Création d'une fenêtre en SFML
RenderWindow window(VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32),
"Meruvia - Big Tuto A-RPG/SFML2 - Chapitre 16 - www.meruvia.fr");
 
 
//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 projectiles magiques gérables
Magic magic[MAGIC_MAX];
 
//On lance la musique en boucle
sounds.PlayMusic(true);
 
//On commence au premier niveau
map.setLevel(1);
map.changeLevel();
 
//On initialise le player
player.initialize(map);
player.setGold(100);
 
// Boucle infinie, principale, du jeu
while(window.isOpen())
{
// Gestion des inputs
input.gestionInputs(window);
 
//Updates
update(input, map, player, monster, sounds, magic);
 
// Dessin - draw
draw(window, map, player, monster, magic);
 
window.display();
}
 
// On quitte
return 0;
}
 
 
 
//Fonction de mise à jour du jeu : gère la logique du jeu
void update(Input &input, Map &map, Player &player, Monster monster[], Sounds &soundsMagic magic[])
{
//On met à jour le player
player.update(input, map, magic);
 
//On met à jour les monstres un par un
for(int i = 0; i < map.getNombreMonstres(); i++)
{
if(monster[i].update(i, map, player, monster, 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 projectiles magiques un par un
for(int i = 0; i < player.getMagic(); i++)
{
if(magic[i].update(player, map) == 1)
{
//On supprime le projectile magique s'il sort de l'écran
magic[i].copy(magic[player.getMagic() - 1]);
player.setMagic(player.getMagic() - 1);
}
else
{
//On teste les collisions avec tous les monstres
for(int j = 0; j < map.getNombreMonstres(); j++)
{
if(magic[i].checkCollisions(monster[j]) == 1)
{
//Si la fonction renvoie 2, c'est qu'il y a contact avec le monstre
//Celui-ci doit être blessé et il faut supprimer le projectile magique.
//Et on blesse le monstre s'il n'est pas invincible
if(monster[j].getInvincibleTimer() == 0)
{
monster[j].setLife(monster[j].getLife() - 1);
monster[j].setInvincibleTimer(TIME_BETWEEN_2_SHOTS);
}
 
 
//Si le monstre est mort
if(monster[j].getLife() <= 0)
{
//On copie à sa place le dernier monstre avant de retirer un monstre
monster[j].copy(monster[map.getNombreMonstres() - 1]);
map.setNombreMonstres(map.getNombreMonstres() - 1);
}
else
{
//On le déclare touché, pour qu'il recule en arrière
monster[j].setisHurt(MOONWALK_TIMER);
 
//On détermine sa direction de recul, par rapport au placement
//de l'ennemi
if(magic[i].getDirection() == DOWN)
monster[j].setHurtDirection(DOWN);
else if(magic[i].getDirection() == UP)
monster[j].setHurtDirection(UP);
else if(magic[i].getDirection() == RIGHT)
monster[j].setHurtDirection(RIGHT);
else if(magic[i].getDirection() == LEFT)
monster[j].setHurtDirection(LEFT);
}
//On supprime le projectile magique
magic[i].copy(magic[player.getMagic() - 1]);
player.setMagic(player.getMagic() - 1);
 
//On joue le sound Fx
sounds.PlaySoundFx(sounds.DESTROY);
}
}
}
}
}
 
 
 
//Fonction de dessin du jeu : dessine tous les éléments
void draw(RenderWindow &window, Map &map, Player &player, Monster monster[], Magic magic[])
{
//On efface tout
window.clear();
 
// 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);
}
 
//On affiche les projectiles magiques un par un
for(int i = 0; i < player.getMagic(); i++)
{
magic[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);
}
 

   Dans le main() :

- on instancie d'abord nos objets Magic (comme pour les monstres),

- puis, là aussi, on met à jour les appels à draw() et update().

 

   Dans update() : 

- on ajoute l'argument Magic magic[] à la fonction,

- puis on ajoute l'update des projectiles magiques avec détection des collisions avec les monstres, pour pouvoir les tuer (et supprimer le projectile magique par la même occasion), si on a un contact ! surprise

 

   Dans draw() :

- on ajoute l'argument Magic magic[] à la fonction,

- puis on ajoute le draw des projectiles magiques (sinon, ce sera l'attaque de la magie invisible, ce qui peut aussi avoir son charme ! laugh).

 

   Eh voilà ! On compile, et ça marche !!! Hourra ! wink

   Notre héros est maintenant un magicien chevronné ! 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!