Big Tuto SFML 2 : Rabidja v. 3.0

Annexe 2 : Ajoutons des lumières !

Tutoriel présenté par : Skrool
Relecture et corrections : Jérémie F. Bellanger (Jay81)

Date d'écriture : 29 mars 2015
Date de révision : 20 mars 2016

      Introduction

   Dans le chapitre précédent, nous avons créé notre gestionnaire de lumières, ajouté des ombres et des ambiances lumineuses, et nous les avons implantées dans notre jeu grâce aux tiles.

   Maintenant, nous allons (enfin) créer nos lumières ! angel

   Accrochez-vous, car le niveau monte d'un cran ! devil

      Théorie

   De quoi allons-nous avoir besoin ? frown
   Tout d'abord, nous allons avoir besoin d'une nouvelle class lightEntity. Dans celle-ci, nous allons stocker les informations telles que le rayon de la lumière, sa couleur, sa position, etc...

   Nous allons aussi stocker sa forme. Mais la question est : quelle forme a une lumière ? surprise

   Vous avez probablement pensé à un cercle pour représenter une lumière, dont l'opacité au centre serait plus grande que celle à ses côtés. wink Bien que techniquement la SFML gère les cercles, et que ce soit possible, nous allons voir que ce n'est pas pratique du tout ! surprise

   En effet, un cercle ne nous permettra ni de gérer les collisions mur / lumière, ni de créer des lumières directionnelles (des lumières qui, contrairement aux lumières omnidirectionnelles, n'éclairent pas tout autour d'elles. Un projecteur, si vous voulez wink).

   Nous allons donc utiliser... des triangles ! indecision

   Des triangles, mais pour quoi faire ? surprise

   Nous allons créer plusieurs triangles partant du centre de la lumière pour donner l'impression que la lumière est un cercle et qu'elle est exponentielle. wink

Demonstration :

   Comme vous pouvez le voir sur l'image 1, nos lumières ne seront pas réellement rondes, mais plus "polygonales". Ce n'est cependant pas grave, puisque cela ne se verra pas (image 2). De plus, ces lumières se subdiviseront en de plus petits triangles quand nous aborderons la question des murs et des collisions. wink

   Sur l'image 3, nous pouvons voir une lumière directionnelle, il s'agit en fait du même système que les lumières omnidirectionnelles, sauf que les triangles ne se bouclent pas sur eux mêmes.

   Enfin, sur la quatrième image, nous pouvons voir de manière simplifiée comment la lumière réagira face à un mur : les triangles se redimensionneront pour "longer le mur". cool

   Vous avez assimilé la théorie ? wink Parce qu'on va entrer dans le vif du sujet : j'ai bien sûr nommé notre class lightEntity !

 

      Ajoutons notre class lightEntity !

   Et on est parti ! Tout d'abord, nous allons créer une nouvelle class lightEntity avec les fichiers lightEntity.cpp et lightEntity.h.

   Voilà ce à quoi va maintenant ressembler notre header :

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

//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur du tuto : www.meruvia.fr - Jérémie F. Bellanger
//Copyright / Droits d'auteur du fichier : Skrool, 2015.
 
//Nous allons avoir besoin d'inclure ces bibliothèques
#include <SFML/Graphics.hpp>
#include <iostream>
#include <math.h>
 
//Ainsi que la class Map
class Map;
 
 
class lightEntity // La lumière en elle-même
{
public:
 
// Constructeur et destructeur
lightEntity();
~lightEntity();
 
// Mutateurs
void SetIntensity(float);
void SetRadius(float);
void SetQuality(int);
void SetColor(sf::Color);
void SetPosition(sf::Vector2f);
void SetAbsolutePosition(sf::Vector2f);
 
// Accesseurs
float GetIntensity() const;
float GetRadius() const;
int GetQuality() const;
sf::Color GetColor() const;
sf::Vector2f getPosition(void) const;
sf::Vector2f getAbsolutePosition(void) const;
int getSourceX(void) const;
int getSourceY(void) const;
int getSourceID(void) const;
 
//Fonctions
 
//Affichage
void Draw(sf::RenderTarget &window) const;
 
//Fonction pour générer les triangles
void Generate(Map &map);
 
//Fonction pour ajouter un triangle (sera plus tard couplée avec une autre fonction)
void AddTriangle(sf::Vector2f pt1, sf::Vector2f pt2, Map &map);
 
//Création d'une lumière omnidirectionnelle
void create(int quality, sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, Map &map, int sourceX, int sourceY);
 
//Création d'une lumière directionnelle
void createDirectionalLight(sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, float angle, float o_angle, Map &map,
int sourceX, int sourceY);
 
//Suppression des triangles de subdivision pour nettoyer la class
void clear(void);
 
//Mise à jour de la lumière (on gèrera des animations ainsi que des déplacement et
//plein d'autres petites choses ici
void update(Map &map);
 
 
//Modification de la position de chacun des points de chaque triangle de la lumière
void move(sf::Vector2f mouvement);
 
 
 
private:
 
//Intensité de la lumière
float m_intensity;
 
//Position de la lumière dans la map
int m_absoluteX, m_absoluteY;
 
// Tableau dynamique de triangles de subdivision
std::vector <sf::VertexArray> m_triangle;
 
//Position à l'écran
sf::Vector2f m_position;
 
//Couleur
sf::Color m_color;
 
//Qualité : nombre de triangle de subdivision de base (lumière omnidirectionnelle seulement)
int m_quality;
 
//Rayon
float m_radius;
 
//Booleen pour savoir si la lumière est directionnelle
bool m_directionnal;
 
//Angle et angle d'ouverture pour les lumières directionnelles
float m_angle, m_opening_angle;
 
//Le type de la lumière, pour créer des animations dans la fonction update
int m_type;
 
//Timer interne pour gérer certaines lumières dans la fonction update
int m_timer;
 
//Variable pour gérer l'apparition de la lumière de manière plus esthétique
float m_targetIntensity;
 
//Tile source, pour replacer la tile de lumière à sa place quand elle sortira de l'écran pour économiser du CPU
int m_sourceX, m_sourceY, m_sourceID;
 
//Constante
const float M_PI = 3.14;
 
};
 
   C'est gros, mais c'est complet (pour le moment laugh) !
   Nous avons un grand nombre de variables et de fonctions que je vous laisse le soin d'analyser. wink
   Quelque chose devrait attirer votre oeil : mais qu'est ce que c'est que std::vector <sf::VertexArray> m_triangle; ??? surprise
   Utiliser std::Vector <typeDeVariable> nomDeVariable crée un tableau dynamique d'une variable. C'est comme un tableau, sauf que l'on pourra ajouter/supprimer des cases comme on veut. wink
   Nous avons donc créé un tableau dynamique de triangles, ce qui nous permettra d'en ajouter et d'en supprimer comme nous en aurons envie. Et c'est un aspect capital de notre class ! cool
   Cela nous permettra de subdiviser notre lumière en plein de triangles, si c'est nécessaire. Pour l'instant, nous ne verrons pas tout son potentiel à l'oeuvre, mais au prochain chapitre, nous nous pencherons plus sur son rôle. wink
   La variable quality vous a peut être aussi interpelée. Elle nous servira à déterminer le nombre de triangles de subdivision de base de notre lumière. Plus il y en aura, plus elle paraitra ronde, mais plus nos fonctions mettront du temps à traiter les informations. indecision
   Le reste ne devrait pas trop poser de problème. cheeky
 
   Maintenant, passons à notre code dans lightEntity.cpp :
 

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

//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur du tuto : www.meruvia.fr - Jérémie F. Bellanger
//Copyright / Droits d'auteur du fichier : Skrool, 2015.
 
#include "lightEntity.h"
#include "map.h"
 
/**********************************************************************************/
/********************************* lightEntity **********************************/
/**********************************************************************************/
 
lightEntity::lightEntity()
{
}
 
lightEntity::~lightEntity()
{
m_triangle.clear();
}
 
void lightEntity::SetIntensity(float value){ m_intensity = value; }
void lightEntity::SetRadius(float value){ m_radius = value; }
void lightEntity::SetQuality(int value){ m_quality = value; }
void lightEntity::SetColor(sf::Color color){ m_color = color; }
void lightEntity::SetPosition(sf::Vector2f value){ m_position = value; }
 
float lightEntity::GetIntensity() const { return (m_intensity); }
float lightEntity::GetRadius() const { return (m_radius); }
int lightEntity::GetQuality() const { return (m_quality); }
sf::Color lightEntity::GetColor() const { return (m_color); }
sf::Vector2f lightEntity::getPosition(void) const { return (m_position); }
sf::Vector2f lightEntity::getAbsolutePosition(void) const { return
(sf::Vector2f(m_absoluteX, m_absoluteY)); }
int lightEntity::getSourceX(void) const { return m_sourceX; }
int lightEntity::getSourceY(void) const { return m_sourceY; }
int lightEntity::getSourceID(void) const { return m_sourceID; }
 
 
void lightEntity::clear(void){ m_triangle.clear(); }
 
 
void lightEntity::move(sf::Vector2f mouvement)
{
//Cette fonction déplace tous les points d'une lumière, triangle par triangle
 
m_position += mouvement;//On modifie la position du centre de la lumière
 
//Pour chaque triangle de la lumière nous ajoutons aux trois points le vecteur de mouvement
for (unsigned int i = 0; i < m_triangle.size(); i++)
{
//Nous utilisons ici un opérateur pour ajouter le vecteur de mouvement aux points
m_triangle[i].operator[](0).position += mouvement;
m_triangle[i].operator[](1).position += mouvement;
m_triangle[i].operator[](2).position += mouvement;
}
}
 
 
void lightEntity::create(int quality, sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, Map &map, int sourceX, int sourceY)
{
//Initialisation de variables
m_quality = quality;
m_color = color;
m_radius = radius;
m_intensity = intensity;
m_absoluteX = (int)position.x;
m_absoluteY = (int)position.y;
m_position = position; // Par défaut. Sera modifié au prochain update
m_type = type;
 
//Récupération des données de tiles
m_sourceX = sourceX;
m_sourceY = sourceY;
 
m_sourceID = map.getTile(sourceY, sourceX);
 
m_directionnal = false;
 
Generate(map);
}
 
 
void lightEntity::createDirectionalLight(sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, float angle, float o_angle, Map &map, int sourceX, int sourceY)
{
//Initialisation de variables
m_color = color;
m_radius = radius;
m_intensity = intensity;
m_type = type;
m_angle = angle;
m_opening_angle = o_angle;
 
m_absoluteX = (int)position.x;
m_absoluteY = (int)position.y;
m_position = position; // Par défaut. Sera modifié au prochain update
 
//Récupération des données de tiles
m_sourceX = sourceX;
m_sourceY = sourceY;
 
m_sourceID = map.getTile(sourceY, sourceX);
 
m_directionnal = true;
 
Generate(map);
}
 
 
void lightEntity::Draw(sf::RenderTarget &window) const
{
// On boucle sur m_triangle pour afficher tous les triangles si la lumière
//n'est pas hors de l'écran.
if (m_position.x > 0 - m_radius && m_position.x < 800 + m_radius
&& m_position.y > 0 - m_radius && m_position.y < 600 + m_radius)
{
for (int i = 0; i < (int)m_triangle.size(); i++)
{
window.draw(m_triangle[i], sf::BlendAdd);
}
}
}
 
 
void lightEntity::update(Map &map)
{
//Pour l'instant vide, mais plus tard, on y ajoutera des animations
 
Generate(map);
}
 
   Voilà le code. Pas de grosse difficulté ici. cheeky
   Pour ceux qui se poseraient la question quant à l'utilité de sourceX, sourceY et sourceID, il s'agit des coordonnées de la tile ayant généré la lumière, ainsi que son numéro dans le tileset. Nous nous en servirons pour décharger nos lumières et replacer la tile à son emplacement d'origine.
   Mais il manque deux fonctions : Generate() et AddTriangle() surprise
   Elles arrivent wink, je les ai mises après car elles sont beaucoup plus complexes, et elles doivent être regardées précisément. C'est le coeur de notre class wink
   Voilà donc la fonction Generate :
 

Fichier : lightEntity.cpp : Rajouter :

void lightEntity::Generate(Map &map)
{
//On libère tout les triangles pour les recalculer ensuite
m_triangle.clear();
 
//Si la lumière n'est pas directionnelle, on calcule la taille des triangles
//par rapport à sa qualité et Pi
if (!m_directionnal)
{
float buf = (M_PI * 2) / (float)m_quality;
 
for (int i = 0; i < m_quality; i++)
{
AddTriangle(sf::Vector2f((float)((float)m_radius*cos((float)i*buf))
, (float)((float)m_radius*sin((float)i*buf))),
sf::Vector2f((float)((float)m_radius*cos((float)(i + 1)*buf))
, (float)((float)m_radius*sin((float)(i + 1)*buf))), map);
}
}
else
{
//Tant que l'angle d'ouverture est > 360, on lui retire 360° pour qu'il corresponde
//à un angle normal
 
while (m_opening_angle > 360)
m_opening_angle -= 360;
 
//Si la lumière est directionnelle et que l'angle est inférieur à 180°, on crée
//un triangle de la taille de la lumière, ce qui donne l'effet "spot"
if (m_opening_angle < 179)
{
float angle = m_angle * M_PI / 180;
float o_angle = m_opening_angle * M_PI / 180;
 
AddTriangle(sf::Vector2f((m_radius*cos(angle + o_angle * 0.5))
, (m_radius*sin(angle + o_angle * 0.5))),
sf::Vector2f((m_radius*cos(angle - o_angle * 0.5))
, (m_radius*sin(angle - o_angle * 0.5))), map);
}
 
//Si l'angle est supérieur à 180°, on divise le triangle en plusieurs triangles
//de 30° max, pour donner un effet rond à la lumière
else if (m_opening_angle < 361)
{
int sub = m_opening_angle / 30;
float angle = m_angle * M_PI / 180;
float o_angle = (m_opening_angle / sub) * M_PI / 180;
 
for (int i = 0; i < sub; i++)
{
AddTriangle(sf::Vector2f((m_radius*cos(angle + (i*o_angle) + o_angle * 0.5))
, (m_radius*sin(angle + (i*o_angle) + o_angle * 0.5))),
sf::Vector2f((m_radius*cos(angle + (i*o_angle) - o_angle * 0.5))
, (m_radius*sin(angle + (i*o_angle) - o_angle * 0.5))), map);
}
 
}
}
}

 

   La fonction est séparée en deux parties, qui correspondent aux lumières omnidirectionnelles et directionnelles.
   Dans le premier cas, on détermine l'angle de chaque sous-triangle grâce au calcul : buf = (M_PI * 2) / (float)m_quality;
   On calcule ensuite les coordonnées de chaque point de chaque triangle grâce aux joies de la trigonométrie angel, puis on les envoie à la fonction AddTriangle().
 
   Le second cas se divise en deux sous-cas. Soit l'angle d'ouverture est inférieur à 180°, soit il est supérieur. En effet, on utilise un seul triangle, quand l'angle est inférieur à 180°, et plusieurs triangles de 30° ou moins quand l'angle est supérieur à 180°, parce que sinon, au lieu d'avoir un angle obtus, on aurait un angle aigu dans l'autre sens... indecision
   On génère donc des variables selon le cas, afin de définir les coordonnées de points pour AddTriangle() encore une fois.
   Maintenant, place à la fonction AddTriangle() :

Fichier : lightEntity.cpp : Rajouter :

// Ajout d'un triangle
void lightEntity::AddTriangle(sf::Vector2f pt1, sf::Vector2f pt2, Map &map)
{
// Variable qui contiendra l'intensité calculée, pour le dégradé de lumière
float intensity;
 
// On ajoute une shape
m_triangle.push_back(sf::VertexArray());
m_triangle.back().setPrimitiveType(sf::Triangles);
 
// On lui donne comme point de départ (0,0), le centre de la lumière, avec
//la couleur et intensité maximales
m_triangle.back().append(sf::Vertex(m_position,
sf::Color((int)(m_intensity*m_color.r / 255),
(int)(m_intensity*m_color.g / 255),
(int)(m_intensity*m_color.b / 255))));
 
// On calcul où l'on se trouve par rapport au centre, pour savoir à quelle intensité on est
intensity = m_intensity - sqrt(pt1.x*pt1.x + pt1.y*pt1.y)*m_intensity / m_radius;
 
// Et on ajoute un point au triangle
m_triangle.back().append(sf::Vertex(m_position + pt1,
sf::Color((int)(intensity*m_color.r / 255),
(int)(intensity*m_color.g / 255),
(int)(intensity*m_color.b / 255))));
 
// Pareil que précédemment
intensity = m_intensity - sqrt(pt2.x*pt2.x + pt2.y*pt2.y)*m_intensity / m_radius;
 
m_triangle.back().append(sf::Vertex(m_position + pt2,
sf::Color((int)(intensity*m_color.r / 255),
(int)(intensity*m_color.g / 255),
(int)(intensity*m_color.b / 255))));
}

 

Note : le contenu de cette fonction sera plus tard déplacé dans une sous fonction du nom de AddShape(), quand on gérera les collisions, pour éviter des calculs interminables. wink

   Ici, on utilise m_triangle.push_back(sf::VertexArray()); pour ajouter une case à notre tableau dynamique, comprenant les triangles. Du coup, on ajoute un triangle. wink

   Avec m_triangle.back().setPrimitiveType(sf::Triangles); on indique que la dernière case contient un triangle (il faut tout lui dire à cet ordinateur laugh ).

   Ensuite, on place les trois points du triangle en prenant en compte l'intensité pour générer une couleur. Souvenez-vous, nous allons appliquer sur les lumières en elles-même un mode de rendu "add", ce qui nous permet de mélanger la couleur au noir. Puisque le noir ne sera pas affiché, les cotés paraitront transparents, et il y aura un dégradé par rapport au centre. wink

   Mais pourquoi avoir mis map en paramètre alors qu'on ne l'utilise pas ? surprise
   Pour l'instant, on ne l'utilise pas, mais on l'utilisera quand on devra gérer les collisions, et plutôt que de changer toutes les déclarations de fonctions plus tard, je préfère mettre map en paramètre tout de suite wink .

     Affichons notre première lumière !

   S’il y a une chose qu'il ne faut pas oublier de faire, c'est de mettre notre gestionnaire de lumière (dans la classe Light wink) à jour. Allons-y, donc :

 

Fichier : light.h : Remplacer le code précédent par :

//Rabidja 3 - nouvelle version convertie en SFML 2
//Copyright / Droits d'auteur du tuto : www.meruvia.fr - Jérémie F. Bellanger
//Copyright / Droits d'auteur du fichier : Skrool, 2015.
 
//Nous allons avoir besoin d'inclure ces bibliothèques
#include <SFML/Graphics.hpp>
#include <iostream>
#include <math.h>
 
//Ainsi que les classes
class Map;
class lightEntity;
 
 
class Light // Class permettant de gérer les lumière
{
 
public:
//Constructeur et destructeur
Light(void);
~Light(void);
 
//Accesseurs
sf::Color getShadowColor(void) const;
sf::Color getTargetShadowColor(void) const;
 
//Mutateurs
void setShadowColor(sf::Color value);
void setTargetShadowColor(sf::Color value);
 
//Fonctions
void draw(sf::RenderWindow &window);
void update(Map &map);
 
//Ajout de lumière
void AddLight(int quality, sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, Map &map, int sourceX, int sourceY);
void AddDirectionalLight(sf::Color color, float radius, float intensity, sf::Vector2f position,
int type, float angle, float o_angle, Map &map, int sourceX, int sourceY);
 
//On vide les lumières
void clear(void);
 
//Cette fonction retourne "true" uniquement si le timer pour recalculer les lumières est arrivé à 0
bool decrementeTimer(void);
 
 
private:
 
//Tesxture de l'ombre
sf::RenderTexture m_shadowTexture;
 
//Notre couleur d'ombre
sf::Color m_shadowColor, m_targetShadowColor;
 
bool m_shadow;
 
//Les lumières vont être déclarées dans un tableau dynamique.
//Cela nous permettra de les supprimer beaucoup plus simplement qu'en utilisant
//le même système qu'avec les autre entités.
std::vector<lightEntity> m_light;
 
//Le timer pour ne pas avoir à mettre à jour les lumières toutes les frames
int m_refreshTimer;
 
 
/*****************/
/* Constantes */
/*****************/
 
//Nombre max de lumières
const unsigned int MAX_LIGHT = 15;
 
//Temps en deux générations de lumière
const int TIME_BETWEN_TWO_UPDATES = 3;
 
};
 
   Tous les autres ajouts étant commentés, je ne m'attarderai pas dessus. wink
   Passons à nos fonctions de light.cpp
   On ajoute un destructeur :
 
Fichier : light.cpp : Faire les modifications nécessaires :
Light::~Light(void)
{
clear();
};
 
   Ici, on prend soin de vider notre tableau de lumières, c'est plus propre ! angel
   Et on passe maintenant à la suite des modifications apportées aux fonctions de notre fichier. On a ainsi, dans l'ordre :
- la fonction draw() qui appelle désormais celle de lightEntity,
- la fonction update() qui met à jour les corrdonnées des lumières en fonction du scrolling,
- notre fonction decrementeTimer(), indiquant quand mettre à jour nos lumières. Oui, on ne va pas refaire les calculs toutes les frames, ce serait trop coûteux pour nos performances, et totalement inefficace ! indecision
- les fonctions permettant d'ajouter nos deux types d'éclairages,
- et enfin la fonction clear() qui fait le ménage. wink
 

Fichier : light.cpp : Faire les modifications nécessaires :

void Light::draw(sf::RenderWindow &window)
{
// On crée un RenderStates avec le mode de rendu multiply, il nous sera indispensable pour la suite
sf::RenderStates render(sf::BlendMultiply);
 
// On vide notre render texture et la remplit de la couleur de l'ombre
m_shadowTexture.clear(m_shadowColor);
 
for (unsigned int i = 0; i < m_light.size(); i++) //On boucle sur nos lumières pour les afficher une à une
{
//Attention ! La fonction lightEntity::draw prend comme paramètre un render target.
//Nous allons en effet envoyer notre render texture d'ombre pour afficher les lumières dessus, et
//ensuite les afficher sur notre fenêtre
m_light[i].Draw(m_shadowTexture);
}
 
//On affiche les lumières se trouvant sur notre render texture
m_shadowTexture.display();
 
// On affiche notre render texture avec le mode multiply
window.draw(sf::Sprite(m_shadowTexture.getTexture()), render);
}
 
 
void Light::update(Map &map)
{
// On rajoute une partie de la différence entre les valeurs r, g et b des
//deux variables pour avoir un effet de transition en douceur
if (m_shadowColor.r < m_targetShadowColor.r)
m_shadowColor.r++;
else if (m_shadowColor.r > m_targetShadowColor.r)
m_shadowColor.r--;
 
if (m_shadowColor.g < m_targetShadowColor.g)
m_shadowColor.g++;
else if (m_shadowColor.g > m_targetShadowColor.g)
m_shadowColor.g--;
 
if (m_shadowColor.b < m_targetShadowColor.b)
m_shadowColor.b++;
else if (m_shadowColor.b > m_targetShadowColor.b)
m_shadowColor.b--;
 
// Si le timer est arrivé à 0, on met la variable timerOk à true.
bool timerOk = decrementeTimer();
 
//On boucle sur toutes les lumières
for (unsigned int i = 0; i<m_light.size(); i++)
{
//On met à jour les coordonnées m_position de la lumière par
//rapport à sa position sur la carte, et à map.startX et startY
m_light[i].move(sf::Vector2f((m_light[i].getAbsolutePosition().x
- m_light[i].getPosition().x) - map.getStartX(),
(m_light[i].getAbsolutePosition().y - m_light[i].getPosition().y)
- map.getStartY()));
 
if (timerOk) //Si le timer s'est écoulé on met à jour la lumière
m_light[i].update(map);
}
}
 
 
bool Light::decrementeTimer(void)
{
m_refreshTimer--;
 
if (m_refreshTimer < 0)
{
m_refreshTimer = TIME_BETWEN_TWO_UPDATES;
return true;
}
return false;
}
 
 
void Light::AddLight(int quality, sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, Map &map, int sourceX, int sourceY)
{
if (m_light.size() < MAX_LIGHT)
{
m_light.push_back(lightEntity());
m_light.back().create(quality, color, radius, intensity, position, type,
map, sourceX, sourceY);
}
}
 
 
void Light::AddDirectionalLight(sf::Color color, float radius, float intensity,
sf::Vector2f position, int type, float angle, float o_angle, Map &map, int sourceX, int sourceY)
{
if (m_light.size() < MAX_LIGHT)
{
m_light.push_back(lightEntity());
m_light.back().createDirectionalLight(color, radius, intensity, position,
type, angle, o_angle, map, sourceX, sourceY);
}
}
 
 
void Light::clear()
{
//On vide tout
for (unsigned int i = 0; i < m_light.size(); i++)
{
m_light[i].clear();
}
m_light.clear();
}

   Et on rajoute le paramètre map à l'appel de la fonction d'update() dans notre boucle principale de main.cpp, et on vérifie aussi que la fonction draw() est correctement appelée wink:

Fichier : main.cpp : Ajouter / changer les éléments suivants :

//On met à jour le Gestionaire de lumière
manager.update(map);
 
//Code coupé...  
 
//Gestion des lumières dynamiques par Skrool
manager.draw(window);

   On compile et... rien !!... surprise
   Bah oui, on n'a pas initialisé de lumière ! indecision Avant de gérer ça avec notre map et nos tiles de lumières dans le chapitre suivant, nous pouvons en générer une directement dans le main() pour tester :

Fichier : main.cpp : Ajouter juste avant la boucle principale :

//On crée des lumières pour tester
manager.AddLight(15, sf::Color::White, 200, 250, sf::Vector2f(200, 500), 0, map, 0, 0);
manager.AddDirectionalLight(sf::Color::Magenta, 300, 200, sf::Vector2f(400, 200), 0, 40, 70, map, 0, 0);
 
// Boucle infinie, principale, du jeu
while (window.isOpen())
{

    On compile, et ... MAGNIFIQUE !! cool Cela marche ! angel

   Essayez de changer les valeurs des lumières ci-dessus pour voir ce que cela fait, puis, quand vous aurez terminé d'expérimenter, supprimez ces lignes surprise. Eh oui, on va raccorder notre système avec nos tiles, comme on a fait avec les tiles d'obscurité.

   Mais, ça, ce sera pour le prochain chapitre ! laugh

   @ bientôt pour l'annexe 3 ! angel

                                          Skrool 

 

 
 

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!