Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Problème pour ma première utilisation de thread avec SFML 2.0  (Lu 2650 fois)

0 Membres et 1 Invité sur ce sujet

Mehfak

  • Newbie
  • *
  • Messages: 3
    • Voir le profil
    • E-mail
Problème pour ma première utilisation de thread avec SFML 2.0
« le: Novembre 19, 2012, 08:41:47 pm »
Bien le bonsoir,
Pour m'entraîner au C++/SFML, j'ai eu comme idée de porter le mario sokoban du cours sur le C du site du zéro en C++.
Pour commencer j'avais pensé entamer mon projet par l'éditeur de niveau. J'ai pensé le faire sous forme de deux fenêtres: la grande pour construire le niveau et la petite avec les différents tiles que l'on peut sélectionner en cliquant dessus. Pour l'instant l'éditeur est juste censé permettre de créer un nouveau niveau sans pouvoir encore le sauvegarder.

Problème: En SFML, on ne peut avoir qu'une seule fenêtre active par thread  :'(
Solution: Qu'à cela ne tienne, je vais faire un deuxième thread   :P

Re-problème: Étant donné que c'est la première fois que je fais un programme qui utilise plusieurs threads, je suis très mauvais (et le compilo ne se gêne pas pour me le faire comprendre avec ses mots doux  ;D ): le programme compile mais crash au moment de démarrer l'éditeur.

J'aimerais donc savoir si vous pouviez m'aider à trouver d'où vient l'erreur. Sans plus tarder le moment que vous attendez tous: LE CODE!!!  8)

main.cpp:
#include <iostream>
#include <SFML\Graphics.hpp>

#include "Constantes.hpp"
#include "Editeur.hpp"

using namespace std;
using namespace sf;

int main()
{
        Event event;

        //Création de la fenêtre
        RenderWindow window(VideoMode(LARGEUR_FENETRE,HAUTEUR_FENETRE),"Mario Sokoban (by Mehfak)",Style::Close);
        window.setFramerateLimit(60);
       
        //Icone
        Image icone;
        if(!icone.loadFromFile("sprites/caisse.jpg"))
        {
                cout<<"Erreur lors du chargement de l'icone"<<endl;
                system("pause>nul");
                return EXIT_FAILURE;
        }
        window.setIcon(icone.getSize().x,icone.getSize().y,icone.getPixelsPtr());

        //Menu
        Texture menuTexture;
        if(!menuTexture.loadFromFile("sprites/menu.jpg"))
        {
                cout<<"Erreur lors du chargement du menu"<<endl;
                system("pause>nul");
                return EXIT_FAILURE;
        }
        Sprite menu(menuTexture);

        //Boucle Principale
        while(window.isOpen())
        {
                while(window.pollEvent(event))
                        if(event.type == Event::Closed || event.key.code == Keyboard::Escape)
                                window.close();
                if(Keyboard::isKeyPressed(Keyboard::Numpad2) || Keyboard::isKeyPressed(Keyboard::Num2))
                {
                        Editeur* editeur = new Editeur(&window);
                        editeur->Launch();
                        delete(editeur);
                }

                window.clear();
                window.draw(menu);
                window.display();
        }

        return EXIT_SUCCESS;
}

Constantes.hpp:
#ifndef CONSTANTES_HPP
#define CONSTANTES_HPP

#define TAILLE_TILE 34
#define NB_TILES_X 12
#define NB_TILES_Y 12
#define NB_TILES 5

#define LARGEUR_FENETRE TAILLE_TILE*NB_TILES_X
#define HAUTEUR_FENETRE TAILLE_TILE*NB_TILES_Y

enum Direction{HAUT,BAS,GAUCHE,DROITE};
enum Tile{VIDE, MUR, CAISSE, OBJECTIF, MARIO, CAISSE_OK};

#endif //CONSTANTES_HPP

Editeur.hpp, la classe qui me pose problème:
#ifndef EDITEUR_HPP
#define EDITEUR_HPP

#include <iostream>
#include <fstream>
#include <string>
#include <SFML\Graphics.hpp>
#include "Constantes.hpp"

class Editeur
{
public:
        Editeur(sf::RenderWindow* pointeur);
        void Launch();

private:
        //Fonctions de l'éditeur
        void CreateLvl();
        void ModifyLvl();

        //Fonction d'affichage
        void Afficher();

        //Fonctions de lancement
        void CreateSprite();
        void LaunchTileWindow();

        sf::Thread threadTileWindow;
        sf::RenderWindow *window, tileWindow;
       
        char tileActuel;

        sf::Sprite sprites[NB_TILES];
        sf::Texture textures[NB_TILES];
        char niveau[NB_TILES_X][NB_TILES_Y];
};

#endif //EDITEUR_HPP

Editeur.cpp, les erreurs sont sûrement là dedans:
#include "Editeur.hpp"

using namespace std;
using namespace sf;

Editeur::Editeur(RenderWindow* pointeur) : window(pointeur), threadTileWindow(&Editeur::LaunchTileWindow, this)
{
        //Initialisation du tableau de sprites
        CreateSprite();
}

void Editeur::CreateSprite()
{
        if(!textures[VIDE].loadFromFile("sprites/vide.jpg"))
        {
                cout<<"Erreur lors du chargement du sprite vide"<<endl;
                system("pause>nul");
                exit(-1);
        }

        if(!textures[MUR].loadFromFile("sprites/mur.jpg"))
        {
                cout<<"Erreur lors du chargement du sprite mur"<<endl;
                system("pause>nul");
                exit(-1);
        }

        if(!textures[CAISSE].loadFromFile("sprites/caisse.jpg"))
        {
                cout<<"Erreur lors du chargement du sprite caisse"<<endl;
                system("pause>nul");
                exit(-1);
        }

        if(!textures[OBJECTIF].loadFromFile("sprites/objectif.png"))
        {
                cout<<"Erreur lors du chargement du sprite objectif"<<endl;
                system("pause>nul");
                exit(-1);
        }

        if(!textures[MARIO].loadFromFile("sprites/mario_bas.gif"))
        {
                cout<<"Erreur lors du chargement du sprite mario"<<endl;
                system("pause>nul");
                exit(-1);
        }

        for(int i = 0; i<NB_TILES; i++)
                sprites[i].setTexture(textures[i]);
}

void Editeur::LaunchTileWindow()
{
        //Création fenêtre
        tileWindow.create(VideoMode(NB_TILES*TAILLE_TILE,TAILLE_TILE,32),"Sélectionner un bloc",Style::Close);
        tileWindow.setFramerateLimit(1);

        Image icone;
        if(!icone.loadFromFile("sprites/caisse.jpg"))
        {
                cout<<"Erreur lors du chargement de l'icone"<<endl;
                system("pause>nul");
                exit(-1);
        }
        tileWindow.setIcon(icone.getSize().x,icone.getSize().y,icone.getPixelsPtr());
       
        for(int i=0; i < 5; i++)
        {
                sprites[i].setPosition(i*TAILLE_TILE,0);
                tileWindow.draw(sprites[i]);
        }

        Event event;
        while(tileWindow.isOpen())
        {
                while(tileWindow.waitEvent(event))
                        switch(event.type)
                        {
                                case Event::Closed:
                                        tileWindow.close();
                                        break;
                                case Event::MouseButtonPressed:
                                        if(event.mouseButton.button == Mouse::Left)
                                                tileActuel = event.mouseButton.x/TAILLE_TILE;
                                        break;
                        }
        }
}

void Editeur::Launch()
{
        int choix(0);

        while(choix != 1 && choix != 2 && choix != 3)
        {
                cout<<"Que souhaitez-vous faire?"<<endl;
                cout<<"1) Creer un niveau"<<endl;
                cout<<"2) Modifier un niveau"<<endl;
                cout<<"3) Quitter l'editeur de niveau"<<endl;
                cin>>choix;
                system("cls");
        }

        cout<<"Fermez la fenetre de tiles pour quitter l'editeur."<<endl;

        switch(choix)
        {
                case 1:
                        CreateLvl();
                        break;
                case 2:
                        break;
                case 3:
                        break;
        }
}

void Editeur::CreateLvl()
{
        Event event;
        //Affichage
        window->clear();
        window->setMouseCursorVisible(false);
        threadTileWindow.launch();

        while(tileWindow.isOpen())
        {
                while(window->pollEvent(event))
                        if(event.type == Event::Closed || event.key.code == Keyboard::Escape)
                                tileWindow.close();

                if(Mouse::isButtonPressed(Mouse::Left))
                        niveau[Mouse::getPosition(*window).x/TAILLE_TILE][Mouse::getPosition(*window).y/TAILLE_TILE]= tileActuel;

                Afficher();
        }
}

void Editeur::Afficher()
{
        Sprite curseur(sprites[tileActuel]);
        curseur.setPosition(Mouse::getPosition(*window).x,Mouse::getPosition(*window).y);

        window->clear();

        for(unsigned int x = 0; x < NB_TILES_X; x++)
        {
                for(unsigned int y = 0; y < NB_TILES_Y; y++)
                {
                        sprites[niveau[x][y]].setPosition(x*TAILLE_TILE,y*TAILLE_TILE);
                        window->draw(sprites[niveau[x][y]]);
                }
        }

        window->draw(curseur);
        window->display();
}

Merci de me faire part de mes erreurs, j'ai envie de progresser et surtout de faire fonctionner ce %#@!$* d'éditeur  :P

EDIT: Oups! Petite précision qui a certainement son importance, quand je debug le programme j'ai un message d'erreur qui me dit R6025 - pure virtual function call et qaund je cherche de quelle fonction virtuelle il parle, il semblerait que ce soit une fonction qui soit dans une des .dll de SFML =/
« Modifié: Novembre 20, 2012, 06:23:48 pm par Mehfak »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Problème pour ma première utilisation de thread avec SFML 2.0
« Réponse #1 le: Novembre 19, 2012, 08:56:31 pm »
Citer
En SFML, on ne peut avoir qu'une seule fenêtre active par thread
C'est faux, tu peux gérer autant de fenêtres que tu veux dans le même thread. Du coup ne t'embête pas avec les threads, c'est bien trop tôt si tu veux mon avis. Là il y aurait trop de choses à corriger par rapport aux threads, tu es parti complètement de travers ;)

Sinon, si tu veux une aide efficace, essaye de nous proposer un code épuré, qui ne contienne que ce qui est nécessaire pour reproduire le bug (mais qui soit toujours complet pour qu'on puisse le tester et qu'on ne loupe rien !).
Laurent Gomila - SFML developer

Mehfak

  • Newbie
  • *
  • Messages: 3
    • Voir le profil
    • E-mail
Re : Problème pour ma première utilisation de thread avec SFML 2.0
« Réponse #2 le: Novembre 20, 2012, 06:19:56 pm »
Merci beaucoup de la réponse rapide  :)

Si on peut gérer autant de fenêtre active pourquoi est-ce qu'on peut lire ça dans la doc (Fonction setActivate() de la classe RenderWindow)  :-\:
Citer
A window is active only on the current thread, if you want to make it active on another thread you have to deactivate it on the previous thread first if it was active. Only one window can be active on a thread at a time, thus the window previously active (if any) automatically gets deactivated.

EDIT: Pour faciliter les choses, vu que j'ai eu le temps aujourd'hui, j'ai uploadé mon projet (je suis sous Visual Studio C++ Express 2010): http://www.mediafire.com/download.php?1xgm66s9em5njac
« Modifié: Novembre 20, 2012, 06:29:49 pm par Mehfak »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Problème pour ma première utilisation de thread avec SFML 2.0
« Réponse #3 le: Novembre 20, 2012, 06:44:30 pm »
Citer
Si on peut gérer autant de fenêtre active pourquoi est-ce qu'on peut lire ça dans la doc
Ca parle d'activation de contexte OpenGL, uniquement ;)
Laurent Gomila - SFML developer

Mehfak

  • Newbie
  • *
  • Messages: 3
    • Voir le profil
    • E-mail
Re : Problème pour ma première utilisation de thread avec SFML 2.0
« Réponse #4 le: Novembre 20, 2012, 08:32:15 pm »
Ah ok je réessaye sans le thread =)