Forum de la communauté SFML

Aide => Système => Discussion démarrée par: Develog le Septembre 28, 2013, 06:46:12 pm

Titre: Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 28, 2013, 06:46:12 pm
Bonjour

Voilà mon problème je souhaite faire des projectiles donc j'utilise un thread. Mais je n'arrive pas à intégrer un thread dans ma scène principale afin de lier ma classe projectile malgré avoir regardé la doc sur les threads ...

Voici mon code :

#include "Projectile.h"

Projectile::Projectile()
{
    Projectile_Blue.setSize(sf::Vector2f(1, 1));
    Projectile_Blue.setPosition(0, 400);
    Projectile_Blue.setFillColor(sf::Color::Blue);
}

void Projectile::Move(sf::RenderWindow &window)
{
    sf::FloatRect ProjectileBox(Projectile_Blue.getPosition(), Projectile_Blue.getSize());
    bool the_end = true;

    while(the_end)
    {
        if (ProjectileBox.contains(window.getSize().x, Projectile_Blue.getPosition().y))
        the_end = false;
        Projectile_Blue.move(5, 0);
        sf::sleep(sf::milliseconds(25));
    }
}

void Projectile::setPosition(int x, int y)
{
    Projectile_Blue.setPosition(x, y);
}

int Projectile::getPositionX(){ return Projectile_Blue.getPosition().x; }
int Projectile::getPositionY(){ return Projectile_Blue.getPosition().y; }
 

#ifndef PROJECTILE_H
#define PROJECTILE_H

#include <SFML/Graphics.hpp>
#include <iostream>

class Projectile : public sf::Drawable
{
    public:
        Projectile();

        void Move(sf::RenderWindow &window);
        void setPosition(int x, int y);

        int getPositionX();
        int getPositionY();

    private:
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
            target.draw(Projectile_Blue, states);
        }

        sf::RectangleShape Projectile_Blue;
};

#endif // PROJECTILE_H
 


#include "Scene.h"

sf::Clock horloge;
sf::Time tempsFrame;

Scene::Scene()
{
    sf::RenderWindow window(sf::VideoMode(), "Warrior Of Space", sf::Style::Fullscreen);
    window.setKeyRepeatEnabled(true);
    window.setFramerateLimit(60);

    sf::Texture image;
    if(!image.loadFromFile("Ressources/Background.png"))
       std::cout<<"Error"<<std::endl;
    sf::Sprite background(image);

    Spaceship spaceship;
    Projectile projectile;
    Gui gui(&spaceship);

    sf::View camera(sf::FloatRect(0, 0, 800, 600));
    sf::Thread t_projectileMove(std::bind(&Projectile::Move, &projectile, &window));

    float timer;

    while (window.isOpen())
        {
            timer += m_tempsFrame.asSeconds();
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed)
                {
                    window.close();
                    t_projectileMove.terminate();
                }

                if (event.type == sf::Event::Resized)
                {
                    sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
                    window.setView(sf::View(visibleArea));
                }

                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape) )
                {
                    window.close();
                    t_projectileMove.terminate();
                }


                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Right) )
                {
                    spaceship.Move(5, 0);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Left) )
                {
                    spaceship.Move(-5, 0);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Z) )
                {
                    spaceship.addHealth(+5);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::A) )
                {
                    spaceship.addHealth(-5);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space) )
                {
                    t_projectileMove.terminate();
                    t_projectileMove.launch();
                }
            }

            std::cout << spaceship.getHealth() << std::endl;

            window.clear();
            window.draw(background);
            window.draw(spaceship);
            window.draw(projectile);
            window.draw(gui);
            gui.Update(&spaceship);
            m_tempsFrame = m_horloge.restart();
            window.setView(camera);
            window.display();
        }
}
 


#ifndef SCENE_H
#define SCENE_H

#include <SFML/Graphics.hpp>
#include <iostream>
#include <functional>

#include "Spaceship.h"
#include "Projectile.h"
#include "Gui.h"

class Scene
{
    public:
        Scene();

    private:
        sf::Clock m_horloge;
                sf::Time m_tempsFrame;
};

#endif // SCENE_H
 
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Septembre 28, 2013, 07:18:28 pm
Citer
je souhaite faire des projectiles donc j'utilise un thread
Quel rapport ??

La seule bonne réponse à ce "problème", c'est : oublie cette idée saugrenue tout de suite, et fais tout dans ton thread principal ;)

En plus ton utilisation des threads est plus que douteuse (la doc indique bien que la fonction terminate() ne devrait jamais être utilisée).
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 28, 2013, 09:17:52 pm
J'aimerai faire un projectile et j'ai trouvé un tuto qui explique comment faire un projectile avec le thread.
À la base je faisais bouger mon projectile avec le timer de la SFML mais le soucis c'est que j'arrivai à faire qu'un seul projectile et là j'aimerai pouvoir en avoir une centaine en même temps sans avoir de soucis de lag ...

Il faudrait que mon personnage puisse se déplacer en X et Y ainsi que se rotate tout en tirant des projectiles.
Si vous avez une idée moins gourmande et plus efficace je suis vraiment preneur :)
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Septembre 28, 2013, 09:43:36 pm
Si tu as trouvé un tutoriel qui explique comment gérer un projectile avec un thread, banis-le tout de suite de tes favoris. C'est presque un cas d'école.

Quel était le problème de tout gérer dans le thread principal ? Tu t'y prenais sûrement mal.
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 28, 2013, 09:49:04 pm
À la base j'avais une classe projectile donc avec un constructeur où j’initialisais mon rectangle, puis dans la classe principale où se trouvait la boucle principale je faisais avancer mon projectile de n x par rapport au temps.
Mais le soucis c'est que j'étais bloqué à un seul projectile :/ 
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 28, 2013, 09:53:51 pm
Voilà comment je faisais avancer mon projectile :

projectile.Move(0, -0.1*timer);
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Septembre 28, 2013, 10:45:20 pm
Jusque là pas de souci. Pourquoi est-ce que tu étais bloqué à un seul projectile ? Où était la limitation ?
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 28, 2013, 10:57:30 pm
J'apprends le C++ et la SFML sur le tas donc j'ai encore pas mal de soucis :/

Voilà quand j'appuie sur une touche j'aimerai que ça lance un nouveau projectile mais faire appel au constructeur à chaque fois, c'est très lourd non ?
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Septembre 29, 2013, 09:30:15 am
Pourquoi est-ce que ce serait très lourd ?

Au lieu de te poser tout un tas de questions, est-ce que tu as essayé de le faire ? Qu'est-ce qui a bloqué exactement ?

A mon avis tu devrais progresser encore un peu en C++ avant de chercher à faire des trucs compliqués. Là tu te crées des problèmes tout seul.
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 29, 2013, 12:29:56 pm
J'ai un peu repris le projectile.
Alors dès que j'appuie sur ma touche Espace le projectile repart de sa position initiale ce qui est normal car dans ma fonction update il y a un setPosition.
J'aimerai savoir comment faire pour qu'à chaque fois que j'appuie sur Espace un nouveau projectile soit créé et que ce ne soit pas le même à chaque fois qui revient à sa place ...

Le code :
Projectile projectile;

//gestion des events

if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space) )
                {
                    projectile.Update();
                }

            }

// Fin de gestion des events
            projectile.Move(0, -0.1*timer);


void Projectile::Update()
{
    Projectile_Blue.setSize(sf::Vector2f(1, 1));
    Projectile_Blue.setPosition(0, 400);
    Projectile_Blue.setFillColor(sf::Color::Blue);
}
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Septembre 29, 2013, 01:03:09 pm
Il te faut un tableau dynamique de projectiles, dans lequel tu vas ajouter un nouvel élément à chaque fois que tu appuyes sur espace. Ensuite tu vas mettre à jour tous les projectiles en cours (ceux qui sont dans le tableau) -- et ne pas oublier de supprimer ceux qui sont arrivés en fin de vie.

Jette un oeil à la classe std::vector pour ton tableau dynamique.
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Septembre 29, 2013, 06:18:10 pm
J'ai fais ce que vous m'avez dit de faire.
Bon je suis confronté à un nouveau problème ...
Mon projectile n'avance pas ...

J'ai fais plusieurs tests comme récupérer la position de mon projectile mais le soucis c'est que cela ne correspond pas du tout à ce qui est affiché sur l'écran ...
Et mon projectile est bien affiché mais il reste fixe :/

Voici le code :

#include "ProjectileManager.h"

ProjectileManager::ProjectileManager()
{
    //ctor
}

ProjectileManager::~ProjectileManager()
{
    //dtor
}

void ProjectileManager::addProjectile()
{
    m_projectiles.push_back(Projectile());
}

void ProjectileManager::deleteProjectile()
{
    for (unsigned int i = 0; i < m_projectiles.size(); i++)
    if (m_projectiles[i].getPosition().y > 500)
        m_projectiles.erase(m_projectiles.begin() + i);
}

void ProjectileManager::moveProjectile(float &timer)
{
    for (unsigned int i = 0; i < m_projectiles.size(); ++i)
    {
        m_projectiles[i].move(10, 5 *timer);
        int y = m_projectiles[i].getPosition().y;
        int x = m_projectiles[i].getPosition().x;
        std::cout << x << " | " << y << std::endl;
    }
}

void ProjectileManager::displayProjectile(sf::RenderWindow& window)
{
    for (unsigned int i = 0; i < m_projectiles.size(); ++i)
        window.draw(m_projectiles[i]);
}
 

#ifndef PROJECTILEMANAGER_H
#define PROJECTILEMANAGER_H

#include <SFML/Graphics.hpp>
#include <iostream>
#include "Projectile.h"

class ProjectileManager
{
    public:
        ProjectileManager();
        ~ProjectileManager();

        void addProjectile();
        void deleteProjectile();
        void moveProjectile(float &timer);
        void displayProjectile(sf::RenderWindow& window);
    private:
        std::vector<Projectile> m_projectiles;
};

#endif // PROJECTILEMANAGER_H
 

#include "Scene.h"

sf::Clock horloge;
sf::Time tempsFrame;

Scene::Scene()
{
    sf::RenderWindow window(sf::VideoMode(), "Warrior Of Space", sf::Style::Fullscreen);
    window.setKeyRepeatEnabled(true);
    window.setFramerateLimit(60);

    sf::Texture image;
    if(!image.loadFromFile("Ressources/Background.png"))
       std::cout<<"Error"<<std::endl;
    sf::Sprite background(image);

    Spaceship spaceship;
    Gui gui(&spaceship);

    sf::View camera(sf::FloatRect(0, 0, 800, 600));
    ProjectileManager projectile;

    float timer;


    while (window.isOpen())
        {
            timer += m_tempsFrame.asSeconds();
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed)
                window.close();

                if (event.type == sf::Event::Resized)
                {
                    sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
                    window.setView(sf::View(visibleArea));
                }

                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape) )
                {
                    window.close();
                }


                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Right) )
                {
                    spaceship.Move(5, 0);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Left) )
                {
                    spaceship.Move(-5, 0);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Z) )
                {
                    spaceship.addHealth(+5);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::A) )
                {
                    spaceship.addHealth(-5);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space) )
                {
                    projectile.addProjectile();
                    projectile.moveProjectile(timer);
                }

            }



            window.clear();

            window.draw(background);
            window.draw(spaceship);
            projectile.displayProjectile(window);
            window.draw(gui);
            gui.Update(&spaceship);
            m_tempsFrame = m_horloge.restart();
            window.setView(camera);
            window.display();
        }
}
 
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Septembre 29, 2013, 08:40:37 pm
Comment ton projectile est-il censé avancer puisque tu n'appelles jamais moveProjectile après sa création ? ;)

Il faut l'appeler tout le temps, dans ta boucle principale avant de dessiner. Et avec le temps de la dernière frame, pas le temps cumulé, sinon ton projectile va aller de plus en plus vite et tu ne le verras pas longtemps. Donc, ta variable timer ne sert à rien.

Sinon, ta fonction deleteProjectile est mal implémentée. La boucle de suppression typique pour un std::vector est la suivante :

for (std::vector<T>::iterator it = v.begin(); it != v.end(); )
{
    if (...)
        it = v.erase(it);
    else
        ++it;
}

Comme ça l'itération n'est pas choucroutée lorsque tu supprimes un élement (avec ton code, l'élément suivant celui supprimé était sauté).
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Octobre 05, 2013, 09:56:22 pm
Bonsoir,


Après un peu de recherche j'ai réussi à faire bouger mes projectiles mais le soucis c'est que ça reste du virtuel.
Mon projectile avance d'après mon getPosition mais sur l'écran il reste à sa place ...

Le code :

void ProjectileManager::moveProjectile(float &timer, sf::RenderWindow& window)
{
    for (unsigned int i = 0; i < m_projectiles.size(); ++i)
    {
        m_projectiles[i].move(0, 1);
        int y = m_projectiles[i].getPosition().y;
        int x = m_projectiles[i].getPosition().x;
        std::cout << x << " | " << y << std::endl;
        window.draw(m_projectiles[i]);
       
    }
}

if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space) )
                {
                    projectile.addProjectile();
                }
            }
            window.clear();
            window.draw(background);
            window.draw(rectangle);
            window.draw(spaceship);
            projectile.moveProjectile(timer, window);
            window.draw(gui);
            gui.Update(&spaceship);
            m_tempsFrame = m_horloge.restart();
            window.setView(camera);
            window.display();
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Octobre 15, 2013, 11:09:31 pm
Bonsoir,

Je me permet de faire un up car je n'arrive vraiment pas à avancer avec ce problème :/
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Octobre 15, 2013, 11:14:02 pm
Si tu arrivais à reproduire le problème dans un code complet minimal, ça nous aiderait à t'aider. Avec des morceaux, incomplets, de ton code original, ça va être compliqué.
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Octobre 16, 2013, 09:12:24 pm
Je n'ai pas fait ça dans un code minimal mais complet seulement ;)

#include "Scene.h"

sf::Clock horloge;
sf::Time tempsFrame;

Scene::Scene()
{
    sf::RenderWindow window(sf::VideoMode(), "Warrior Of Space", sf::Style::Fullscreen);
    window.setKeyRepeatEnabled(true);
    window.setFramerateLimit(60);

    sf::Texture image;
    if(!image.loadFromFile("Ressources/Background.png"))
       std::cout<<"Error"<<std::endl;
    sf::Sprite background(image);

    Spaceship spaceship;
    Gui gui(&spaceship);

    sf::View camera(sf::FloatRect(0, 0, 800, 600));
    ProjectileManager projectile;

    sf::RectangleShape rectangle;
    rectangle.setSize(100, 100);
    rectangle.setFillColor(sf::Color::Red);
    rectangle.setPosition(200, 300);

    float timer;


    while (window.isOpen())
        {
            timer += m_tempsFrame.asSeconds();
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed)
                window.close();

                if (event.type == sf::Event::Resized)
                {
                    sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
                    window.setView(sf::View(visibleArea));
                }

                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape) )
                {
                    window.close();
                }

                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Right) )
                {
                    spaceship.Move(5, 0);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Left) )
                {
                    spaceship.Move(-5, 0);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Z) )
                {
                    spaceship.addHealth(+5);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::A) )
                {
                    spaceship.addHealth(-5);
                }
                if ( (event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space) )
                {
                    projectile.addProjectile();
                }

            }

            window.clear();
            window.draw(rectangle);
            window.draw(spaceship);
            projectile.displayProjectile(window);
            window.draw(gui);
            gui.Update(&spaceship);
            m_tempsFrame = m_horloge.restart();
            projectile.moveProjectile(timer);
            window.setView(camera);
            window.display();
        }
}
 

#ifndef SCENE_H
#define SCENE_H

#include <SFML/Graphics.hpp>
#include <iostream>


#include "Spaceship.h"
#include "Projectile.h"
#include "Gui.h"
#include "ProjectileManager.h"

class Scene
{
    public:
        Scene();

    private:
        sf::Clock m_horloge;
                sf::Time m_tempsFrame;
};

#endif // SCENE_H
 


#include "Projectile.h"

Projectile::Projectile() : sf::Sprite()
{
    Projectile_Blue.setSize(sf::Vector2f(10, 10));
    Projectile_Blue.setPosition(300, 400);
    Projectile_Blue.setFillColor(sf::Color::Blue);
}

 


#ifndef PROJECTILE_H
#define PROJECTILE_H

#include <SFML/Graphics.hpp>
#include <iostream>

class Projectile : public sf::Sprite
{
    public:
        Projectile();

    private:
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
            target.draw(Projectile_Blue, states);
        }

        sf::RectangleShape Projectile_Blue;
};

#endif // PROJECTILE_H
 



#include "ProjectileManager.h"

ProjectileManager::ProjectileManager()
{
    //ctor
}

ProjectileManager::~ProjectileManager()
{
    //dtor
}

void ProjectileManager::addProjectile()
{
    m_projectiles.push_back(Projectile());
}

void ProjectileManager::deleteProjectile()
{
    for (unsigned int i = 0; i < m_projectiles.size(); i++)
    if (m_projectiles[i].getPosition().y > 500)
        m_projectiles.erase(m_projectiles.begin() + i);
}

void ProjectileManager::moveProjectile(float &timer)
{
    for (unsigned int i = 0; i < m_projectiles.size(); ++i)
    {
        m_projectiles[i].move(10, 5 *timer);
        int y = m_projectiles[i].getPosition().y;
        int x = m_projectiles[i].getPosition().x;
        std::cout << x << " | " << y << std::endl;
    }
}

void ProjectileManager::displayProjectile(sf::RenderWindow& window)
{
    for (unsigned int i = 0; i < m_projectiles.size(); ++i)
        window.draw(m_projectiles[i]);
}
 


#ifndef PROJECTILEMANAGER_H
#define PROJECTILEMANAGER_H

#include <SFML/Graphics.hpp>
#include <iostream>
#include "Projectile.h"

class ProjectileManager
{
    public:
        ProjectileManager();
        ~ProjectileManager();

        void addProjectile();
        void deleteProjectile();
        void moveProjectile(float &timer);
        void displayProjectile(sf::RenderWindow& window);
    private:
        std::vector<Projectile> m_projectiles;
};

#endif // PROJECTILEMANAGER_H
 
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Laurent le Octobre 16, 2013, 10:16:07 pm
Bien, mais c'est à toi de perdre du temps à éliminer les morceaux de code inutiles, pas à nous. Il faut que lorsque tu arrives sur le forum tu aies déjà déblayé le terrain, c'est pas à nous d'en chier sur tes problèmes ;)
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Octobre 17, 2013, 09:29:42 pm
Oui pardon, je manque de temps donc je cherchais pas trop à régler mon problème mais plus à me le faire régler ^^
Les vacances arrivent donc je vais me remettre dedans et revenir avec un code épuré ;)
Je suis encore désolé
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: Develog le Octobre 20, 2013, 01:00:47 am
Bonsoir,

Après analyse je viens de voir où j'ai un soucis ...
Mon projectile avance bien enfin sur ça il n'y a pas de soucis. Il s'affiche bien aussi.
Mais il ne s'actualise pas, c'est à dire qu'il bouge virtuellement car sur l'écran il reste au même endroit

Voici le code :

void ProjectileManager::moveProjectile(sf::RenderWindow& window)
{
    for (unsigned int i = 0; i < m_projectiles.size(); ++i)
    {
        m_projectiles[i].move(0, 1);
        int y = m_projectiles[i].getPosition().y;
        int x = m_projectiles[i].getPosition().x;
        std::cout << x << " | " << y << std::endl; // Me permet de récupérer la position du projectile et ça évolue normalement mais rien ne se passe à l'écran ...

        window.draw(m_projectiles[i]);
    }
}
 

Et voici ce que la console affiche :

(http://image.noelshack.com/fichiers/2013/42/1382223630-sans-titre.png)
Titre: Re : Problème d'intégration d'un thread dans une classe
Posté par: cdcl le Janvier 03, 2014, 01:14:49 pm
Le problème, ben c'est que tu fait avancer ton objet sf::Sprite et non ton Objet Rectangle...  ;)
Bonjour,

Et puis je pense que tu te trompe au niveau implémentation... pourquoi pas simplement hériter de sf::RectangleShape  ?

class Projectile : public sf::RectangleShape
{
    public:
        Projectile();

};