Je vais vous présenter un moteur de lumière dynamiques de ma création. Il permet de gérer des lumières dans un environnement en deux dimensions, avec des murs sans épaisseur. La version que je vous montre ici n'est pas optimisée pour la gestion des vues. Je part du principe que nous avons toujours un environnement fixe. Mais il est aisément faisable de rajouter des conditions pour éviter d'afficher des lumières en dehors de l'écran, en prenant par exemple des quadtree.
Vous trouverez des explications sur le moteur sur le blog d'Alpha-Arts : http://www.alpha-arts.net/blog/articles/view/18/moteur-de-lumieres.
Ou en encore plus détaillé sur Developpez : http://gregouar.developpez.com/tutoriels/jeux/moteur-lumieres-dynamiques-2d/.
Si vous voulez télécharger le projet de démonstration, c'est par ici.
Le code source d'exemple est réalisé pour la SFML2, que vous pourrez trouver sur la SVN.
ATTENTION : Ce moteur n'est pas encore à 100% optimisé. Il peut toujours avoir des problèmes. Vos remarques à ce propos sont les bienvenues sur ce sujet.
Le projet est découpé en 4 fichiers pour les lumières, plus un fichier main.cpp de démonstration et un fichier singleton.h pour la gestion des singletons.
#include "Light.h" #ifndef LIGHTMANAGERH #define LIGHTMANAGERH #include "Singleton.h" class Light_Manager : public CSingleton<Light_Manager> { protected : Light_Manager(); ~Light_Manager(); // Les tableaux de murs, lumières statiques et dynamiques std::vector <Wall> m_wall; std::vector <Light> m_StaticLight; std::vector <Light> m_DynamicLight; public : // Constructeur et destructeur friend Light_Manager* CSingleton<Light_Manager>::GetInstance(); friend void CSingleton<Light_Manager>::Kill(); //Différents moyen d'ajouter une lumière dynamique, soit on l'ajoute sans aucune valeur par défaut, soit on lui donne une lumière par défaut, soit on lui donne ses valeurs "à la main" Light_Entity Add_Dynamic_Light(); Light_Entity Add_Dynamic_Light(Light); Light_Entity Add_Dynamic_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color); //Différents moyen d'ajouter une lumière dynamique, soit on lui donne une lumière par défaut, soit on lui donne ses valeurs "à la main" //On ne peut ajouter une lumière static sans rien, ça ne servirait à rien car elle ne peut être modifiée par la suite Light_Entity Add_Static_Light(Light); Light_Entity Add_Static_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color); // Ajouter un mur Wall_Entity Add_Wall(sf::Vector2f pt1,sf::Vector2f pt2); // Désactiver une lumière ou supprimer un mur void Delete_Light(Light_Entity); void Delete_Wall(Wall_Entity); void Delete_All_Wall(); void Delete_All_Light(); // Calculer toutes les lumières dynamiques void Generate(); void Generate(Light_Entity); // Afficher toutes les lumières à l'écran void Draw(sf::RenderWindow *App); // Différentes méthodes pour modifier les attributs d'une lumière, ou les récupérer. Il faut à chaque fois envoyer une Light_Entity en paramètre pour // savoir de quelle lumière on parle/ void SetPosition(Light_Entity, sf::Vector2f ); void SetQuality(Light_Entity, int ); void SetRadius(Light_Entity, int ); void SetColor(Light_Entity, sf::Color ); void SetIntensity(Light_Entity, int); float GetIntensity(Light_Entity); float GetRadius(Light_Entity); int GetQuality(Light_Entity); sf::Color GetColor(Light_Entity); sf::Vector2f GetPosition(Light_Entity); void SetPosition(Wall_Entity, sf::Vector2f ); sf::Color m_basicLight; int m_lightSmooth; private: sf::Shader BlurEffect; std::vector<Light>::iterator Iter; sf::RenderImage m_renderImg; }; #endif
#include "LightManager.h" Light_Manager::Light_Manager() { m_lightSmooth=0; // Chargement du postFX pour adoucir les bords. BlurEffect.LoadFromFile("blur.sfx"); BlurEffect.SetTexture("texture", sf::Shader::CurrentTexture); m_renderImg.Create(800,600); } Light_Manager::~Light_Manager() { m_wall.clear(); m_StaticLight.clear(); m_DynamicLight.clear(); } // Les différents moyens d'ajouter des lumières Light_Entity Light_Manager::Add_Dynamic_Light() { m_DynamicLight.push_back(Light ()); return Light_Entity((int)m_DynamicLight.size()-1,true); } Light_Entity Light_Manager::Add_Dynamic_Light(Light light) { m_DynamicLight.push_back(light); return Light_Entity((int)m_DynamicLight.size()-1,true); } Light_Entity Light_Manager::Add_Dynamic_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color) { m_DynamicLight.push_back(Light (position,intensity,radius,quality,color)); return Light_Entity((int)m_DynamicLight.size()-1,true); } // Notez bien qu'on calcule les lumières statiques lors de leur ajout. Light_Entity Light_Manager::Add_Static_Light(Light light) { m_StaticLight.push_back(light); m_StaticLight.back().Generate(m_wall); return Light_Entity((int)m_StaticLight.size()-1,false); } Light_Entity Light_Manager::Add_Static_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color) { m_StaticLight.push_back(Light (position,intensity,radius,quality,color)); m_StaticLight.back().Generate(m_wall); return Light_Entity((int)m_StaticLight.size()-1,false); } // Ajouter un mur Wall_Entity Light_Manager::Add_Wall(sf::Vector2f pt1,sf::Vector2f pt2) { bool Add_Wall = true; for(int i=0;i<(int)m_wall.size();i++) if((pt1.y-pt2.y)/(pt1.x-pt2.y)==(m_wall[i].pt1.y-m_wall[i].pt2.y)/(m_wall[i].pt1.x-m_wall[i].pt2.y)) if(pt1==m_wall[i].pt1 || pt2==m_wall[i].pt1 || pt1==m_wall[i].pt2 || pt2==m_wall[i].pt2) { sf::Vector2f min=pt1,max=pt2; if(pt2.x<min.x) min.x=pt2.x; if(pt1.x>max.x) max.x=pt2.x; if(m_wall[i].pt1.x<min.x) min.x=m_wall[i].pt1.x; if(m_wall[i].pt2.x<min.x) min.x=m_wall[i].pt2.x; if(m_wall[i].pt1.x>max.x) max.x=m_wall[i].pt1.x; if(m_wall[i].pt2.x>max.x) max.x=m_wall[i].pt2.x; if(pt2.y<min.y) min.y=pt2.y; if(pt1.y>max.y) max.y=pt2.y; if(m_wall[i].pt1.y<min.y) min.y=m_wall[i].pt1.y; if(m_wall[i].pt2.y<min.y) min.y=m_wall[i].pt2.y; if(m_wall[i].pt1.y>max.y) max.y=m_wall[i].pt1.y; if(m_wall[i].pt2.y>max.y) max.y=m_wall[i].pt2.y; m_wall[i].pt1=min; m_wall[i].pt2=max; return Wall_Entity(i); } m_wall.push_back(Wall (pt1,pt2)); return Wall_Entity(m_wall.size()-1); } // On désactive une lumière void Light_Manager::Delete_Light(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].m_actif=false; else if(e.ID()>=0&&e.ID()<(int)m_StaticLight.size()) m_StaticLight[e.ID()].m_actif=false; } // On supprime un mur void Light_Manager::Delete_Wall(Wall_Entity e) { m_wall.erase(m_wall.begin()+e.ID()); } void Light_Manager::Delete_All_Wall() { m_wall.clear(); } void Light_Manager::Delete_All_Light() { m_StaticLight.clear(); m_DynamicLight.clear(); } // On calcule toutes les lumières dynamiques actives void Light_Manager::Generate() { m_renderImg.Clear(m_basicLight); BlurEffect.SetParameter("offset",0.005 * m_lightSmooth); for(Iter=m_DynamicLight.begin();Iter!=m_DynamicLight.end();++Iter) if(Iter->m_actif) Iter->Generate(m_wall), Iter->Draw(&m_renderImg); for(Iter=m_StaticLight.begin();Iter!=m_StaticLight.end();++Iter) if(Iter->m_actif) Iter->Draw(&m_renderImg); m_renderImg.Display(); } void Light_Manager::Generate(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].Generate(m_wall); } // On crée une image avec toutes les lumières actives void Light_Manager::Draw(sf::RenderWindow *App) { sf::Sprite sprite; sprite.SetImage(m_renderImg.GetImage()); sprite.SetBlendMode(sf::Blend::Multiply); App->Draw(sprite,BlurEffect); } // On modifie ou récupère les attributs de lumières dynamiques void Light_Manager::SetPosition(Light_Entity e, sf::Vector2f p) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].SetPosition(p); } void Light_Manager::SetQuality(Light_Entity e, int q) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].SetQuality(q); } void Light_Manager::SetRadius(Light_Entity e, int r) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].SetRadius(r); } void Light_Manager::SetColor(Light_Entity e, sf::Color c) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].SetColor(c); } void Light_Manager::SetIntensity(Light_Entity e, int i) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) m_DynamicLight[e.ID()].SetIntensity(i); } float Light_Manager::GetIntensity(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) return m_DynamicLight[e.ID()].GetIntensity(); return 0; } float Light_Manager::GetRadius(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) return m_DynamicLight[e.ID()].GetRadius(); return 0; } int Light_Manager::GetQuality(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) return m_DynamicLight[e.ID()].GetQuality(); return 0; } sf::Color Light_Manager::GetColor(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) return m_DynamicLight[e.ID()].GetColor(); return sf::Color (0,0,0); } sf::Vector2f Light_Manager::GetPosition(Light_Entity e) { if(e.Dynamic()) if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size()) return m_DynamicLight[e.ID()].GetPosition(); return sf::Vector2f (0,0); } // On modifie ou récupère différents attributs des murs void Light_Manager::SetPosition(Wall_Entity e, sf::Vector2f p) { if(e.ID()>=0&&e.ID()<(int)m_wall.size()) { sf::Vector2f buffer=m_wall[e.ID()].pt1; m_wall[e.ID()].pt1=p; m_wall[e.ID()].pt2.x= m_wall[e.ID()].pt2.x + (p.x-buffer.x); m_wall[e.ID()].pt2.y= m_wall[e.ID()].pt2.y + (p.y-buffer.y); } }
#include <SFML/System.hpp> #include <SFML/Graphics.hpp> #include <SFML/Window.hpp> #ifndef LIGHTH #define LIGHTH struct Wall { Wall (sf::Vector2f p1,sf::Vector2f p2) { pt1=p1; pt2=p2; } // Pt1 et Pt2 sont les deux extrémités du mur sf::Vector2f pt1; sf::Vector2f pt2; // Position du mur sf::Vector2f position; }; // Wall_Entity est une variable qui permet de représenter dans le programme un mur struct Wall_Entity { Wall_Entity (int id) { m_ID=id; } int ID() { return m_ID; } private: int m_ID; }; // Light_Entity est une variable qui permet de représenter dans le programme une lumière struct Light_Entity { Light_Entity (){m_Dynamic=false,m_ID=0;} Light_Entity (int id,bool d) { m_ID=id; m_Dynamic=d; } int ID() { return m_ID; } bool Dynamic() { return m_Dynamic; } private: int m_ID; bool m_Dynamic; }; class Light { public : // Constructeur et destructeur Light(); Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color); ~Light(); // Afficher la lumière void Draw(sf::RenderTarget *App); // Calculer la lumière void Generate(std::vector <Wall> &m_wall); // Ajouter un triangle à la lumière, en effet, les lumières sont composée de triangles void AddTriangle(sf::Vector2f pt1,sf::Vector2f pt2, int minimum_wall,std::vector <Wall> &m_wall); // Changer différents attributs de la lumière void SetIntensity(float); void SetRadius(float); void SetQuality(int); void SetColor(sf::Color); void SetPosition(sf::Vector2f); // Retourner différents attributs de la lumière float GetIntensity(); float GetRadius(); int GetQuality(); sf::Color GetColor(); sf::Vector2f GetPosition(); // Une petite bool pour savoir si la lumière est allumée ou éteinte bool m_actif; private : //Position à l'écran sf::Vector2f m_position; //Intensité, gère la transparence ( entre 0 et 255 ) float m_intensity; //Rayon de la lumière float m_radius; //Couleur de la lumière sf::Color m_color; //Qualité de la lumière, c'est à dire le nombre de triangles par défaut qui la compose. int m_quality; //Tableau dynamique de Shape, ce sont ces shapes de type triangle qui compose la lumière std::vector <sf::Shape> m_shape; }; #endif
#include <iostream> #include <math.h> #include "light.h" Light::Light() { m_intensity=0; m_radius=0; m_quality=0; m_actif=true; } Light::Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color) { m_position=position; m_intensity=intensity; m_radius=radius; m_color=color; m_quality=quality; } Light::~Light() { m_shape.clear(); } void Light::Draw(sf::RenderTarget *App) { // On boucle sur m_shape pour afficher tous les triangles. for(int i=0;i<(int)m_shape.size();i++) App->Draw(m_shape[i]); } sf::Vector2f Intersect(sf::Vector2f p1, sf::Vector2f p2, sf::Vector2f q1, sf::Vector2f q2) { sf::Vector2f i; if((p2.x - p1.x) == 0 && (q2.x - q1.x) == 0) i.x = 0, i.y = 0; else if((p2.x - p1.x) == 0) { i.x = p1.x; float c = (q2.y - q1.y) / (q2.x - q1.x); float d = q1.y - q1.x * c; i.y = c * i.x + d; } else if((q2.x - q1.x) == 0) { i.x = q1.x; float a = (p2.y - p1.y) / (p2.x - p1.x); float b = p1.y - p1.x * a; i.y = a * i.x + b; } else { float a = (p2.y - p1.y) / (p2.x - p1.x); float b = p1.y - p1.x * a; float c = (q2.y - q1.y) / (q2.x - q1.x); float d = q1.y - q1.x * c; i.x = (d-b)/(a-c); i.y = a * i.x + b; } return i; } sf::Vector2f Collision(sf::Vector2f p1, sf::Vector2f p2, sf::Vector2f q1, sf::Vector2f q2) { sf::Vector2f i; i = Intersect(p1, p2, q1, q2); if(((i.x >= p1.x - 0.1 && i.x <= p2.x + 0.1) || (i.x >= p2.x - 0.1 && i.x <= p1.x + 0.1)) && ((i.x >= q1.x - 0.1 && i.x <= q2.x + 0.1) || (i.x >= q2.x - 0.1 && i.x <= q1.x + 0.1)) && ((i.y >= p1.y - 0.1 && i.y <= p2.y + 0.1) || (i.y >= p2.y - 0.1 && i.y <= p1.y + 0.1)) && ((i.y >= q1.y - 0.1 && i.y <= q2.y + 0.1) || (i.y >= q2.y - 0.1 && i.y <= q1.y + 0.1))) return i; else return sf::Vector2f (0,0); } void Light::AddTriangle(sf::Vector2f pt1,sf::Vector2f pt2, int minimum_wall,std::vector <Wall> &m_wall) { int w = minimum_wall; // On boucle sur tous les murs for(std::vector<Wall>::iterator IterWall=m_wall.begin()+minimum_wall;IterWall!=m_wall.end();++IterWall,++w) { // l1 et l2 sont les positions relatives au centre de la lumière des deux extrémités du mur sf::Vector2f l1(IterWall->pt1.x-m_position.x, IterWall->pt1.y-m_position.y); sf::Vector2f l2(IterWall->pt2.x-m_position.x, IterWall->pt2.y-m_position.y); if(l1.x * l1.x + l1.y * l1.y < m_radius * m_radius) { sf::Vector2f i = Intersect(pt1,pt2,sf::Vector2f (0,0),l1); if((pt1.x > i.x && pt2.x < i.x) || (pt1.x < i.x && pt2.x > i.x)) if((pt1.y > i.y && pt2.y < i.y) || (pt1.y < i.y && pt2.y > i.y)) if(l1.y > 0 && i.y > 0 || l1.y < 0 && i.y < 0) if(l1.x > 0 && i.x > 0 || l1.x < 0 && i.x < 0) AddTriangle(i, pt2, w, m_wall), pt2 = i; } if(l2.x * l2.x + l2.y * l2.y < m_radius * m_radius) { sf::Vector2f i = Intersect(pt1,pt2,sf::Vector2f (0,0),l2); if((pt1.x > i.x && pt2.x < i.x) || (pt1.x < i.x && pt2.x > i.x)) if((pt1.y > i.y && pt2.y < i.y) || (pt1.y < i.y && pt2.y > i.y)) if(l2.y > 0 && i.y > 0 || l2.y < 0 && i.y < 0) if(l2.x > 0 && i.x > 0 || l2.x < 0 && i.x < 0) AddTriangle(pt1, i, w, m_wall), pt1 = i; } sf::Vector2f m = Collision(l1, l2, sf::Vector2f(0,0), pt1); sf::Vector2f n = Collision(l1, l2, sf::Vector2f(0,0), pt2); sf::Vector2f o = Collision(l1, l2, pt1, pt2); if((m.x != 0 || m.y != 0) && (n.x != 0 || n.y != 0)) pt1 = m, pt2 = n; else { if((m.x != 0 || m.y != 0) && (o.x != 0 || o.y != 0)) AddTriangle(m ,o , w, m_wall), pt1 = o; if((n.x != 0 || n.y != 0) && (o.x != 0 || o.y != 0)) AddTriangle(o ,n , w, m_wall), pt2 = o; } } // Variable qui contiendra l'intensité calculée, pour le dégradé float intensity; // On ajoute un shape m_shape.push_back(sf::Shape ()); // On lui donne comme point de départ (0,0), le centre de la lumière, avec la couleur et intensité maximal m_shape.back().AddPoint(0, 0, sf::Color((int)(m_intensity*m_color.r/255), (int)(m_intensity*m_color.g/255), (int)(m_intensity*m_color.b/255)),sf::Color(255,255,255)); // On calcul ou l'on se trouve par rapport au centre, pour savoir à quel 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 shape m_shape.back().AddPoint(pt1.x, pt1.y, sf::Color((int)(intensity*m_color.r/255), (int)(intensity*m_color.g/255), (int)(intensity*m_color.b/255)),sf::Color(255,255,255)); // Idem intensity=m_intensity-sqrt(pt2.x*pt2.x + pt2.y*pt2.y)*m_intensity/m_radius; m_shape.back().AddPoint(pt2.x, pt2.y, sf::Color((int)(intensity*m_color.r/255), (int)(intensity*m_color.g/255), (int)(intensity*m_color.b/255)),sf::Color(255,255,255)); // On met que le shape soit en Add et on lui donne sa position m_shape.back().SetBlendMode(sf::Blend::Add); m_shape.back().SetPosition(m_position); } void Light::Generate(std::vector <Wall> &m_wall) { // On vide la mémoire m_shape.clear(); // buf est l'angle de chaque triangle, c'est donc 2pi divisé par le nombre de triangles float buf=(M_PI*2)/(float)m_quality; // On ajoute tous les triangles qui composent la lumière 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))),0,m_wall); } } // Différentes fonctions pour modifier les attributs de la lumière, et pour les récupérer void Light::SetIntensity(float intensity) { m_intensity=intensity; } void Light::SetRadius(float radius) { m_radius=radius; } void Light::SetQuality(int quality) { m_quality=quality; } void Light::SetColor(sf::Color color) { m_color=color; } void Light::SetPosition(sf::Vector2f position) { m_position=position; } float Light::GetIntensity(){ return m_intensity; } float Light::GetRadius(){ return m_radius; } int Light::GetQuality(){ return m_quality; } sf::Vector2f Light::GetPosition(){ return m_position;} sf::Color Light::GetColor(){ return m_color; }
Le code d'exemple :
#include "LightManager.h" int main() { // Création de la fenêtre de rendu. sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Holyspirit Light Test"); // Création de l'horloge pour gérer le temps. sf::Clock Clock; // Création d'un tableau dynamique qui contient les images des murs. std::vector <sf::Shape> Wall; // On ajoute des lignes à "Wall" pour représenter les murs de facon graphique. Wall.push_back(sf::Shape::Line(450, 325, 300, 200, 5, sf::Color(255,255,255))); Wall.push_back(sf::Shape::Line(250, 240, 400, 365, 5, sf::Color(255,255,255))); Wall.push_back(sf::Shape::Line(125, 125, 100, 100, 5, sf::Color(255,255,255))); Wall.push_back(sf::Shape::Line(500, 200, 600, 300, 5, sf::Color(255,255,255))); Wall.push_back(sf::Shape::Line(500, 300, 600, 200, 5, sf::Color(255,255,255))); Wall.push_back(sf::Shape::Line(125, 425, 125, 475, 5, sf::Color(255,255,255))); Wall.push_back(sf::Shape::Line(125, 475, 175, 475, 5, sf::Color(255,255,255))); // Création du Light_Manager, c'est lui qui va s'occupper de gérer les lumières. Light_Manager *Manager; Manager=Light_Manager::GetInstance(); Manager->m_lightSmooth=2; Manager->m_basicLight=sf::Color(32,32,32); // On ajoute des murs au Light_Manager, ce sont ces murs qui sont pris en compte lors du calcul des lumières // (Position du point 1, Position du point 2). Manager->Add_Wall(sf::Vector2f(450,325),sf::Vector2f(300,200)); Manager->Add_Wall(sf::Vector2f(250,240),sf::Vector2f(400,365)); Manager->Add_Wall(sf::Vector2f(100,100),sf::Vector2f(125,125)); Manager->Add_Wall(sf::Vector2f(500,200),sf::Vector2f(600,300)); Manager->Add_Wall(sf::Vector2f(500,300),sf::Vector2f(600,200)); Manager->Add_Wall(sf::Vector2f(125,425),sf::Vector2f(125,475)); Manager->Add_Wall(sf::Vector2f(125,475),sf::Vector2f(175,475)); // Création des Light_Entity, ce sont elles qui permettent de modifier les lumières par après, comme changer de position, de couleur, etc Light_Entity light,light2,light3; // On ajoute une lumière dynamique au Light_Manager et on dit que c'est "light" qui la représente. light=Manager->Add_Dynamic_Light(); light2=Manager->Add_Dynamic_Light(); // On ajoute une lumière dynamique à la position (600,600), d'intensité 255, de rayon 160, de qualité 16 et de couleur verte. light3=Manager->Add_Dynamic_Light(sf::Vector2f(600,200),255,160,16,sf::Color(0,255,0)); // On ajoute une lumière statique à la position (110,490), d'intensité 160, de rayon 96, de qualité 8 et de couleur blanche. On ne la raccorde pas à une // Light_Entity car c'est une lumière statique et qui n'est donc pas modifiable. Manager->Add_Static_Light(sf::Vector2f(110,490),160,96,32,sf::Color(255,255,255)); // On donne la position (375,275) à la lumière raccordée à "light". Manager->SetPosition(light,sf::Vector2f(375,275)); // On donne une intensité de 255 à la lumière raccordée à "light". Manager->SetIntensity(light,255); // On donne un rayon de 128 à la lumière raccordée à "light". Manager->SetRadius(light,128); // On donne une qualité de 16 à la lumière raccordée à "light". Manager->SetQuality(light,16); // On donne une couleur rouge à la lumière raccordée à "light". Manager->SetColor(light,sf::Color(255,0,0)); // Même chose que juste au dessus, mais avec "light2" Manager->SetPosition(light2,sf::Vector2f(175,50)); Manager->SetIntensity(light2,255); Manager->SetRadius(light2,128); Manager->SetQuality(light2,16); Manager->SetColor(light2,sf::Color(0,0,255)); // Création d'une image qui servira d'image de fond, on charge donc l'image "test.png". sf::Image Image; Image.LoadFromFile("test.png"); sf::Sprite background; background.SetImage(Image); background.Resize(800,600); // Création d'une sf::String pour afficher les FPS sf::Text FPS; // Création d'un buffer pour préparer le texte des FPS char buffer[255]; // Création de variables pour la gestion du temps. float AfficherFPS=0,LightRefresh=0; //Création de bool pour faire rebondir les lumières bool allerX=true,allerY=true; bool allerX2=true,allerY2=true; // Exécution de la boucle principale while (App.IsOpened()) { // Traitement des évènements sf::Event Event; while (App.GetEvent(Event)) { // Fenêtre fermée : on quitte if (Event.Type == sf::Event::Closed) App.Close(); } // On ajoute le temps écoulé AfficherFPS+=Clock.GetElapsedTime(); LightRefresh+=Clock.GetElapsedTime(); //On déplace la "light" en fonction du temps, avec allerX et allerY pour savoir si on monte ou on descend. if(allerX) Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x+100*Clock.GetElapsedTime(),Manager->GetPosition(light).y)); else Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x-100*Clock.GetElapsedTime(),Manager->GetPosition(light).y)); if(allerY) Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x,Manager->GetPosition(light).y+100*Clock.GetElapsedTime())); else Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x,Manager->GetPosition(light).y-100*Clock.GetElapsedTime())); //Si la "light" sort d'une certaine zone, on modifie allerX et/ou allerY pour faire rebondir. if(Manager->GetPosition(light).x>800) allerX=false; if(Manager->GetPosition(light).x<0) allerX=true; if(Manager->GetPosition(light).y>600) allerY=false; if(Manager->GetPosition(light).y<0) allerY=true; // Ce ne sert que pour la démo technique et n'intervient pas dans l'utilisation du moteur de lumières // Idem mais avec light2 if(allerX2) Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x+125*Clock.GetElapsedTime(),Manager->GetPosition(light2).y)); else Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x-125*Clock.GetElapsedTime(),Manager->GetPosition(light2).y)); if(allerY2) Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x,Manager->GetPosition(light2).y+125*Clock.GetElapsedTime())); else Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x,Manager->GetPosition(light2).y-125*Clock.GetElapsedTime())); if(Manager->GetPosition(light2).x>800) allerX2=false; if(Manager->GetPosition(light2).x<0) allerX2=true; if(Manager->GetPosition(light2).y>600) allerY2=false; if(Manager->GetPosition(light2).y<0) allerY2=true; // On récupère la position de la souris const sf::Input& Input = App.GetInput(); // On place light 3 à cette position, avec un tout petit décalage, pour éviter d'avoir une lumière pile sur l'axe d'un mur, ça peut engendrer des problèmes pour le moment. Manager->SetPosition(light3,sf::Vector2f(Input.GetMouseX(),Input.GetMouseY())); Clock.Reset(); //Vous pouvez changer le 0.025 par une autre valeur si vous voulez que les lumières ne se rafraichissent que toutes les x secondes, au lieu de le faire à chaque tour de boucle. if(LightRefresh>0.025) { // On re-calcule les lumières Manager->Generate(); LightRefresh=0; } // Efface l'écran (remplissage avec du noir) App.Clear(); // On affiche le fond App.Draw(background); // On affiches les murs for(int w=0;w<(int)Wall.size();w++) App.Draw(Wall[w]); // On affiche les lumières Manager->Draw(&App); // On affiche les FPS if(AfficherFPS>0.2) { float Framerate = 1.f / App.GetFrameTime(); sprintf(buffer,"%i",(int)Framerate); FPS.SetString(buffer); AfficherFPS=0; } App.Draw(FPS); // Affichage du contenu de la fenêtre à l'écran App.Display(); } Manager->Kill(); return EXIT_SUCCESS; }
#include <iostream> /// Script repris de : http://www.siteduzero.com/tutoriel-3-32923-la-classe-singleton.html /// Ecrit par : Davidbrcz template<typename T> class CSingleton { public: /* Cette fonction retourne l'unique instance de l'objet */ static T* GetInstance(void) { if(singleton==0) { singleton = new T; } return singleton; } /* Cette fonction tue l'unique instance de l'objet */ static void Kill() { if(singleton!=0) { delete singleton ; singleton=0; } } //un couple d'accesseur / mutateur int GetValue() { return value; } void SetValue(int val) { value=val; } protected: int value; CSingleton() : value(0) { std::cout<<"Singleton crée"<<std::endl; } virtual ~CSingleton() { std::cout<<"Singleton détruit"<<std::endl; } static T *singleton; }; template <typename T> T* CSingleton<T>::singleton = 0;