Partage
  • Partager sur Facebook
  • Partager sur Twitter

SFML synchronisation de sprite animés

    16 juillet 2019 à 15:18:57

    Bonjour. Récemment j'ai appris comment créer une classe AnimatedSprite(), et j'arrive à m'en servir. Cependant je fais face à un problème : j'utilise cette classe pour animer plusieurs tiles d'une tilemap, et ils s'animent correctement, mais de façon non-synchronisée. Je me suis dis que c'est surement à cause d'un décalage entre les horloges de chaque tile qui se joue à la microseconde, j'ai donc essayé un autre méthode comme par exemple utiliser une seule horloge qui serait crée soit dans la classe qui contient mon tableau de tiles soit dans la classe tile() en static, et calculer quelle animation utiliser dans le update() en se basant sur le moment où à eu lieu le dernier changement de texture, mais cela revient à donner le même résultat.

    Y a t'il une technique pour synchroniser plusieurs AnimatedSprite() ?

    • Partager sur Facebook
    • Partager sur Twitter
      16 juillet 2019 à 19:14:08

      Bonjour,

      Tu peux déléguer la mesure d'un délai à une classe de cette manière (je te donne l'header à toi de faire des recherches pour implémenter le cpp :

      #include <chrono>
      
      class AccurateTimeDelay
      {
      private:
      	std::chrono::steady_clock::time_point current;
      	std::chrono::steady_clock::time_point precedent;
      	std::chrono::duration<double, std::milli> duration;
      	
      public:
      	explicit AccurateTimeDelay();
      	bool hasTimeElapsed(double passedTime);
      	bool hasTimeNotElapsed(double delay);
      	bool isTimeBetweenBoundaries(double min, double max);
      	void joinTimePoints();
      	void setPrecedentTimePoint();
      };

      Après tu peux l'utiliser comme ceci:

      AccurateTimeDelay delay;
      
      if( delay.hasTimeElapsed( 120 ) ) //Si 120 mis se sont écoulées
      {
          //Faire des actions ici;
      
      
          //Puis on synchronise les délais avec :
          //(seulement si le temps s'est écoulé, donc si on est rentré dans le if ci-dessus)
          delay.joinTimePoints();
      }


      Si vraiment tu ne trouve pas pour le fichier 'cpp' , demande des explications et je t'aiderai plus que ça.

      -
      Edité par Warren79 16 juillet 2019 à 19:26:08

      • Partager sur Facebook
      • Partager sur Twitter

      Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

        16 juillet 2019 à 23:25:51

        Je dois avouer que je ne comprend pas trop en quoi cette classe pourrait aider a synchroniser les AnimatedSprite de mes tiles...

        Et est-ce que ça fonctionne avec des sf::Time et des sf::Clock ?

        • Partager sur Facebook
        • Partager sur Twitter
          16 juillet 2019 à 23:51:27

          La solution que tu as essayé est la bonne : n'avoir qu'une seule horloge. 

          Tes sprites auraient ensuite une méthode update(float) qui prend en paramètre le temps écoulé depuis la dernière mise à jour. 

          Tu peux aussi utiliser une fixed time step pour que ça sout plus stable. 

          • Partager sur Facebook
          • Partager sur Twitter
            17 juillet 2019 à 0:32:43

            Comment je peux faire pour calculer le temps écoulé depuis la dernière mise a jour alors que je ne suis pas dans l'objet AnimatedSprite() lors du calcul puisque le résultat va en paramètre de la méthode update ?

            Je crois que je vais m'arrêter là pour aujourd'hui mais je vais surement réessayer demain.

            Je vais poster du code si ça peut servir. Je sais bien que mon organisation est loin d'être au point pour le moment donc n'hésitez pas à faire des remarque !

            Niveau.h

            #pragma once
            #include "SFML/Graphics.hpp"
            #include <vector>
            #include "Tiles/Tile.h"
            #include "Tiles/Terre.h"
            #include "Tiles/CroixMultiCouleur.h"
            
            class Niveau
            {
            public:
            	Niveau();
            	void update();
            	void draw(sf::RenderWindow &fenetre);
            	~Niveau();
            
            private:
            	std::vector<std::vector<int>> carte;
            	std::vector<std::vector<Tile*>> TileMap;
            	sf::Clock horlogeGénérale;
            };
            
            

            Niveau.cpp

            #include "Niveau.h"
            
            
            
            Niveau::Niveau()
            {
            	carte = {
            		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0},
            		{0,1,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0},
            		{0,1,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,0,0,0},
            		{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0},
            		{0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
            		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            		{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}
            	};
            	for (int i = 0; i != carte.size(); i++)
            	{
            		TileMap.push_back(std::vector<Tile*>());
            		for (int j = 0; j != carte[i].size(); j++)
            		{
            			TilesAutour tilesAutour; //C'est pour un autre type de tiles dont le sprite change si des tiles du même type sont autour.
            			int x;
            			int y;
            
            			//haut
            			x = j;
            			y = i - 1;
            			if (y < 0) { y = 0; };
            			tilesAutour.haut = carte[y][x];
            
            			//bas
            			x = j;
            			y = i + 1;
            			if (y > carte.size() - 1) { y = (int)carte.size() -1; };
            			tilesAutour.bas = carte[y][x];
            
            			//gauche
            			x = j - 1;
            			y = i;
            			if (x < 0) { x = 0; };
            			tilesAutour.gauche = carte[y][x];
            
            			//droite
            			x = j + 1;
            			y = i;
            			if (x > carte[i].size() - 1) { x = (int)carte[i].size() - 1; };
            			tilesAutour.droite = carte[y][x];
            
            			switch (carte[i][j])
            			{
            			case 0:
            				TileMap[i].push_back(new CroixMultiCouleur(j, i, tilesAutour));
            				break;
            			case 1:
            				TileMap[i].push_back(new Terre(j, i, tilesAutour));
            				break;
            			default:
            				break;
            			}
            		}
            	}
            	std::cout << "Taille X : " << TileMap[0].size() << " || Taille Y : " << TileMap.size() << std::endl;
            }
            
            
            void Niveau::update()
            {
            	for (int i = 0; i != TileMap.size(); i++)
            	{
            		for (int j = 0; j != TileMap[i].size(); j++)
            		{
            			TileMap[i][j]->update();
            		}
            	}
            
            }
            
            void Niveau::draw(sf::RenderWindow &fenetre)
            {
            	for (int i = 0; i != TileMap.size(); i++)
            	{
            		for (int j = 0; j != TileMap[i].size(); j++)
            		{
            			TileMap[i][j]->draw(fenetre);
            		}
            	}
            }
            
            
            Niveau::~Niveau()
            {
            	for (int i = 0; i != TileMap.size(); i++)
            	{
            		for (int j = 0; j != TileMap[i].size(); j++)
            		{
            			delete TileMap[i][j];
            			TileMap[i][j] = 0;
            		}
            	}
            }
            
            

            Tile.h

            #pragma once
            #include "SFML/Graphics.hpp"
            #include "../../Objet.h"
            
            struct TilesAutour
            {
            	int haut;
            	int bas;
            	int gauche;
            	int droite;
            };
            
            class Tile
            	: public Objet
            {
            public:
            	Tile(int nbX, int nbY, TilesAutour tilesAutour);
            	virtual void update();
            	virtual void draw(sf::RenderWindow &fenetre);
            	~Tile();
            
            	sf::Vector2i getNbTile();
            	
            protected:
            	sf::Vector2i nbTile;
            };
            
            

            Tile.cpp

            #include "Tile.h"
            
            
            
            Tile::Tile(int nbX, int nbY, TilesAutour tilesAutour)
            {
            	nbTile.x = nbX;
            	nbTile.y = nbY;
            	position.x = nbTile.x * 30;
            	position.y = nbTile.y * 30;
            	sprite.setPosition(position);
            	if (!texture.loadFromFile("Tile.png"))
            	{
            		std::cout << "Erreur Chargement Image" << std::endl;
            	}
            	sprite.setTexture(texture);
            }
            
            
            void Tile::update()
            {
            	
            }
            
            void Tile::draw(sf::RenderWindow &fenetre)
            {
            	fenetre.draw(sprite);
            }
            
            
            Tile::~Tile()
            {
            }
            
            
            sf::Vector2i Tile::getNbTile()
            {
            	int x = nbTile.x;
            	int y = nbTile.y;
            
            	return nbTile;
            }

            CroixMultiCouleur.h // Ce tile contient un AnimatedSprite() qui représente des croix de différentes couleur avec une intervalle de 200 milliseconde (par défaut dans AnimatedSprite.h).

            #pragma once
            #include "Tile.h"
            class CroixMultiCouleur :
            	public Tile
            {
            public:
            	CroixMultiCouleur(int nbX, int nbY, TilesAutour tilesAutour);
            	void update();
            	void draw(sf::RenderWindow &fenetre);
            	~CroixMultiCouleur();
            
            private:
            	AnimatedSprite sprite;
            };
            
            

            CroixMultiCouleur.cpp

            #include "CroixMultiCouleur.h"
            
            
            
            CroixMultiCouleur::CroixMultiCouleur(int nbX, int nbY, TilesAutour tilesAutour) : Tile(nbX, nbY, tilesAutour)
            {
            	sprite.setTexture(texture);
            	sprite.AjouterTextureRect(sf::IntRect(0, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(30, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(60, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(90, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(120, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(150, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(180, 0, 30, 30));
            	sprite.AjouterTextureRect(sf::IntRect(210, 0, 30, 30));
            
            	sprite.setPosition(position);
            }
            
            
            void CroixMultiCouleur::update()
            {
            	sprite.update(sf::Time(/*valeur en sf::millisecond qui corespond au temps passé depuis la dernière MAJ*/));
            }
            
            void CroixMultiCouleur::draw(sf::RenderWindow &fenetre)
            {
            	fenetre.draw(sprite);
            }
            
            
            CroixMultiCouleur::~CroixMultiCouleur()
            {
            }
            

            Objet.h

            #pragma once
            #include "SFML/Graphics.hpp"
            #include "AnimatedSprite.h"
            
            class Objet
            {
            public:
            	Objet();
            	~Objet();
            
            protected:
            	sf::Vector2f position;
            	sf::Texture texture;
            	sf::Sprite sprite;
            	
            };
            
            

            Objet.cpp

            #include "Objet.h"
            
            
            
            Objet::Objet()
            {
            }
            
            
            Objet::~Objet()
            {
            }
            

            AnimatedSprite.h

            #pragma once
            #include "SFML/Graphics.hpp"
            #include <vector>
            #include <iostream>
            
            class AnimatedSprite :
            	public sf::Sprite
            {
            public:
            	AnimatedSprite(sf::Time tempsEntreChaqueFrame = sf::milliseconds(200));
            	AnimatedSprite(sf::Texture &texture, sf::Time tempsEntreChaqueFrame = sf::milliseconds(200));
            	void AjouterTextureRect(sf::IntRect RectAajouter);
            	void setTempsEntreChaqueFrame(sf::Time tempsEntreChaqueFrame);
            	void update(sf::Time tempDepuisDernièreFrame);
            	~AnimatedSprite();
            
            private:
            	std::vector<sf::IntRect> m_TableauTextureRect;
            	int frameActuelle;
            	sf::Time m_tempsEntreChaqueFrame;
            };

            AnimatedSprite.cpp

            #include "AnimatedSprite.h"
            
            
            AnimatedSprite::AnimatedSprite(sf::Time tempsEntreChaqueFrame)
            {
            	m_tempsEntreChaqueFrame = tempsEntreChaqueFrame;
            	frameActuelle = 0;
            }
            
            AnimatedSprite::AnimatedSprite(sf::Texture &texture, sf::Time tempsEntreChaqueFrame) : sf::Sprite(texture)
            {
            	m_tempsEntreChaqueFrame = tempsEntreChaqueFrame;
            	frameActuelle = 0;
            	setTexture(texture);
            }
            
            
            void AnimatedSprite::AjouterTextureRect(sf::IntRect RectAajouter)
            {
            	m_TableauTextureRect.push_back(RectAajouter);
            }
            
            void AnimatedSprite::setTempsEntreChaqueFrame(sf::Time tempsEntreChaqueFrame)
            {
            	m_tempsEntreChaqueFrame = tempsEntreChaqueFrame;
            }
            
            void AnimatedSprite::update(sf::Time tempDepuisDernièreFrame)
            {
            	if (m_TableauTextureRect.size() != 0 && tempDepuisDernièreFrame >= m_tempsEntreChaqueFrame)
            	{
            		frameActuelle++;
            		if (frameActuelle >= m_TableauTextureRect.size())
            		{
            			frameActuelle = 0;
            		}
            		setTextureRect(m_TableauTextureRect[frameActuelle]);
            	}
            }
            
            AnimatedSprite::~AnimatedSprite()
            {
            }
            

            Voilà ! Désolé pour le long post mais j'ai préféré en poster trop que pas assez. Je n'ai pas vraiment réussi à implémenter ce que vous me proposez mais je reviendrai vite sur cette page pour savoir si mon code ressemble a quelque chose selon vos avis !

            A plus !



            -
            Edité par ChiarenzaMattéo 17 juillet 2019 à 0:56:17

            • Partager sur Facebook
            • Partager sur Twitter
              17 juillet 2019 à 10:49:05

              Comme l'a dit Raynobrak, tu utilise une classe qui mesure le temps pour à la fois tes tiles de maps et tes animated sprites (pour cela il faut que tu sorte ce qui mesure le temps des tes classes Tiles et Animated Sprites. Avec un code proche de :
              if( delayMesure.hasTimeElapsed( 100 ) ) //Si tu veux 100 ms par exemple
              {
                  Tile.update();
                  AnimatedSprite.update();
              
                  delayMesure.joinTimePoints();
              }
              Tu peux implémenter la classe de mesure du temps avec l'header <chrono> ( c++11 requis ) ou bien avec sf::Time et sf::Clock.
              • Partager sur Facebook
              • Partager sur Twitter

              Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

              SFML synchronisation de sprite animés

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown