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

Auteur Sujet: [SFML 2.0] Vitesse de déplacement variable au lieu de constante...  (Lu 3362 fois)

0 Membres et 1 Invité sur ce sujet

Artexflow

  • Newbie
  • *
  • Messages: 10
    • Voir le profil
    • E-mail
Bien le bonjour à tous !

Voilà, bon je culpabilise un peu de poster encore une question idiote, mais sincèrement je ne sais pas ce qu'il se passe !

J'ai un sprite que j'anime et déplace en utilisant les touches du clavier. Pour garantir la vitesse de ce sprite, j'ai suivi tout bêtement une méthode trouvée sur le net, simplement il arrive que mon personnage ralentisse (très fortement) pendant quelques secondes, avant de reprendre sa vitesse normale.
Je me demande donc ce que j'ai fait de mal !

Comme du code vaut mieux qu'un long discours, je vous recopie les parties en question.

Moteur.cpp où la classe Personnage est instanciée et où les touches du clavier sont récupérées :

#include "Moteur.h"

Moteur::Moteur() {
    m_fenetre = new sf::RenderWindow;
}

Moteur::~Moteur() {
    delete m_fenetre; // m_fenetre est alloué dynamiquement, on le détruit ici.
}

void Moteur::init()
{
    m_fenetre->create(sf::VideoMode(800, 600), "La fenetre");
}

void Moteur::boucleJeu()
{
    Personnage Personnage;
   
    while (m_fenetre->isOpen()) // Boucle de jeu
    {
        sf::Event event; // La variable event reçoit tous les événements utilisateur
        while (m_fenetre->pollEvent(event)) { // Tous les événements sont traités à la suite
            switch (event.type) {
                case sf::Event::Closed:
                    m_fenetre->close();
                    break;
                default:
                    break;
            }
        }
       
        clavierDetect(Personnage);
       
        m_fenetre->draw(Personnage.getSprite()); // On affiche le sprite à l'écran
        m_fenetre->display();
        m_fenetre->clear();
    }
}


void Moteur::clavierDetect(Personnage & PersonnageADeplacer) {
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
    {
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            PersonnageADeplacer.animPerso(1, -1, Droite);
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            PersonnageADeplacer.animPerso(-1, -1, Gauche);
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            PersonnageADeplacer.animPerso(0, 1, Bas);
        else
            PersonnageADeplacer.animPerso(0, -1, Haut);
    }
   
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
    {
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            PersonnageADeplacer.animPerso(1, 1, Droite);
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            PersonnageADeplacer.animPerso(-1, 1, Gauche);
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            PersonnageADeplacer.animPerso(0, -1, Haut);  
        else
            PersonnageADeplacer.animPerso(0, 1, Bas);
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
    {
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            PersonnageADeplacer.animPerso(1, 0, Droite);
        else
            PersonnageADeplacer.animPerso(-1, 0, Gauche);
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
    {
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            PersonnageADeplacer.animPerso(-1, 0, Gauche);
        else
            PersonnageADeplacer.animPerso(1, 0, Droite);
    }
}

Et enfin Personnage.cpp (qui contient donc la fameuse méthode "animPerso()"

#include "Personnage.h"

Personnage::Personnage() : m_nom("John Malkovitch"), m_spritePersonnage(), m_frameCounter(0), m_frameSpeed(500), m_frameSwitch(100), m_frameClock(), m_frameUpdate(true), m_mvtClock(), m_mvtCounter(0), m_mvtSpeed(10000), m_mvtSwitch(10), m_mvtUpdate(true)
{
    if (!m_texturePersonnage.loadFromFile("texturePersonnage.png")) {
        std::cout << "Erreur : texturePersonnage ne s'est pas chargé." << std::endl;
    }
    /* On charge du fichier, l'instruction sf::IntRect permet de découper à la volée dans notre texture celle qui nous intéresse */
    m_spritePersonnage.setTexture(m_texturePersonnage); // On charge la texture dans le sprite
   
    m_source.x = 1;
    m_source.y = Bas;
}



void Personnage::animPerso(short x, short y, short dir) {
   
    m_source.y = dir;
   
    m_mvtCounter = (m_mvtUpdate) ? m_mvtCounter + m_mvtSpeed * m_mvtClock.restart().asSeconds() : 0;
    if (m_mvtCounter >= m_mvtSwitch) {
        m_mvtCounter = 0;
        m_spritePersonnage.move(x, y);
    }
   
    m_frameCounter = (m_frameUpdate) ? m_frameCounter + m_frameSpeed * m_frameClock.restart().asSeconds() : 0;
    if (m_frameCounter >= m_frameSwitch) {
        m_frameCounter = 0;
        m_source.x++;
        if (m_source.x * 32 >= m_texturePersonnage.getSize().x) {
            m_source.x = 0;
        }
    }
   
}

sf::Sprite Personnage::getSprite()
{
    m_spritePersonnage.setTextureRect(sf::IntRect(m_source.x * 32, m_source.y * 32, 32, 32));
    return m_spritePersonnage;
}

En me relisant j'ai l'impression que ce que je raconte est incompréhensible. N'hésitez pas à me le dire ! Je préciserai !

Bon et une fois de plus désolé pour la question pas intelligent, promis, promis avec le temps j'en poserai moins.

Et merci d'avance !

Hypnéos

  • Newbie
  • *
  • Messages: 30
    • Voir le profil
Re : [SFML 2.0] Vitesse de déplacement variable au lieu de constante...
« Réponse #1 le: Mars 25, 2013, 05:57:17 pm »
Ta méthode Moteur::boucleJeu() ne gère pas le temps dans le while.

rajouter un sf::sleep devrait régler le problème.
(et soulager ton processeur  :) )

Voici un lien vers le tutoriel correspondant : Tutoriel - Système - Gérer le temps.
Jette aussi un coup d'œil à sf::Clock.


EDIT :

Pour être plus précis :

while(m_fenetre->isOpen()){

//stuff

}

s’exécutera le plus vite possible.

sf::sleep() fait une pause dans l'exécution du programme :
/!\ Attention/!\
sf::sleep() prends un sf::Time en argument avec la SFML2.

while(m_fenetre->isOpen()){

//stuff

sf::sleep(sf::seconds(1.f/60.f))

}

Avec le code ci-dessus tes FPS seront légèrement inférieures à 60 du à la durée d’exécution de //stuff
pour corriger ça je te propose de chronométrer la durée de ta boucle et de l'ôter à sf::sleep() :

sf::Clock chrono;

while(m_fenetre->isOpen()){

//stuff

sf::sleep(sf::seconds(1.f/60.f - chrono.getElapsedTime().asSeconds()));
chrono.restart();

}

Tu peux désormais considérer qu'il se passe toujours la même durée entre deux frames;

/!\ Attention /!\
Si ton code met plus de 1/60ème de seconde à s’exécuter sf::sleep() ne servira à rien;
tu devras considérer un FPS plus bas. (1/20ème est encore correct pour un jeu ;) )

Protip  8)

const sf::Time FRAME__TIME = sf::seconds(1.f/60.f);

float time_delta; //temps écoulé durant la dernière frame (en secondes)

while(m_fenetre->isOpen()){

//stuff

time_delta = chrono.getElapsedTime().asSeconds();
sf::sleep(FRAME_TIME - chrono.restart());

}

sf::Time possède un opérateur - ;
sf::Clock::restart() retourne un sf::Time ;
utilise les pour simplifier ton code;

Et time_delta permet d'obtenir des mouvements "parfaitement" chronométrés quelque-soit les FPS :

déplacement en 1 seconde * fraction de seconde = déplacement durant une fraction de seconde


PS : J'en ai peut-être fait un peu trop.
J’espère avoir été utile.
et bonne journée. :)
« Modifié: Mars 26, 2013, 01:06:20 pm par Hypnéos »

christophedlr

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
    • E-mail
Re : [SFML 2.0] Vitesse de déplacement variable au lieu de constante...
« Réponse #2 le: Mars 27, 2013, 09:02:27 am »
Je pense que le soucis est ailleurs, en effet tu te sers d'un timer (sf::clock) dans ta condition. Tu n'en n'as pas besoin.
Normalement, dans ta condition tu regardes si la touche est pressée, si oui alors tu appels ta méthode de "déplacement" du sprite. Là aucune condition, tu te contentes de faire un move sur les nouvelles coordonnées.

Là ton erreur c'est que ton move dépend du temps, en clair plus ta machine est rapide plus ça va vite au niveau de l'animation.

Là je suis au boulot, ce soir je te fais un petit exemple.

Artexflow

  • Newbie
  • *
  • Messages: 10
    • Voir le profil
    • E-mail
Re : [SFML 2.0] Vitesse de déplacement variable au lieu de constante...
« Réponse #3 le: Mars 27, 2013, 11:24:28 am »
@ Hypnéos :

Ola, non, t'en as pas fait trop, au contraire, plus, j'en veux plus toujours plus !
Grand merci pour tes excellentes explications. J'ai d'ores et déjà implémenté ta suggestion dans mon code, et dès que je comprendrai mieux ce qu'il se passe, j'essaierai d'implémenter la même technique pour l'animation des sprites (qui ne vont évidemment pas à la même "vitesse" que mon personnage).

@ christophedlr

Tes conseils sont retenus. Envoie ton exemple, comme dit plus haut, plus j'apprends mieux c'est (et plus ça me fait plaisir) !

Merci à vous deux, bonne journée ;)

christophedlr

  • Full Member
  • ***
  • Messages: 151
    • Voir le profil
    • E-mail
Re : [SFML 2.0] Vitesse de déplacement variable au lieu de constante...
« Réponse #4 le: Mars 28, 2013, 10:28:34 am »
Coucou,

J'ai hélas pas eu le temps hier soir de concocter mon exemple. Cependant sur mon compte google drive j'ai retrouvé un exemple que j'avais fait : http://www.mirorii.com/x98ldwcxvbbu/sprites-2013-03-28_Mirorii.com.zip (prend n'importe quel lien de téléchargement proposé par mirorii).

L'exemple est complet : code source, DLL et exécutable pour tester.