Partage
  • Partager sur Facebook
  • Partager sur Twitter

Pointeur Unique avec SFML

    22 septembre 2022 à 17:41:39

    Bonjour, voici ma bouteille à la mer pour avoir de l'aide en CPP :)

    J'apprends le C++ tout seul (donc je m'excuse d'avance si je n'utilise pas les bons termes) pour faire de la programmation de jeux avec SFML, j'ai trouvé un PDF assez bien fait mais qui part en live lors de la création d'une classe pour charger les textures.

    J'ai réussi tant bien que mal à comprendre le concept de créer un espace de noms, et d'utiliser un pointeur unique, mais c'est encore un peu complexe pour moi.
    La particularité du PDF, c'est qu'il a l'air de tout mettre dans un fichier, là où je souhaiterai fragmenter en plusieurs fichiers (donc ça arrive que je me plante - mais je ne crois pas que ce soit le cas ici).

    Du coup mon soucis:

    En voulant faire la classe de chargement des textures, j'ai créé un fichier textureHolder.h avec la classe TextureHolder:

    #include <SFML/Graphics.hpp>
    
    namespace Textures
    {
    	enum ID { Landscape, Airplane, Missile };
    }
    
    class TextureHolder
    {
    public:
    	void Load(Textures::ID id, const std::string& filename);
    	sf::Texture& GetTexture(Textures::ID id);
    	const sf::Texture& GetTexture(Textures::ID id) const;
    
    private:
    	std::map<Textures::ID, 
    		std::unique_ptr<sf::Texture>> mTextureMap;
    };
    

    Le but est de charger et référencer des textures pour pouvoir les utiliser.

    Il vient avec le fichier textureHolder.cpp qui a une fonction load, pour charger la texture, et une autre pour trouver la texture:

    #include "textureHolder.h"
    
    void TextureHolder::Load(Textures::ID id, const std::string& filename)
    {
    	std::unique_ptr<sf::Texture> texture(new sf::Texture());
    	texture->loadFromFile(filename);
    
    	mTextureMap.insert(std::make_pair(id, std::move(texture)));
    }
    
    sf::Texture& TextureHolder::GetTexture(Textures::ID id)
    {
    	auto found = mTextureMap.find(id);
    	return *found->second;
    }
    
    const sf::Texture& TextureHolder::GetTexture(Textures::ID id) const
    {
    	auto found = mTextureMap.find(id);
    	return *found->second;
    }
    

    La classe est utilisée dans une autre classe qui s'appelle player.h et player.cpp, dans le constructeur Player()

    #include "player.h"
    
    Player::Player()
    	: mPlayer(), mTexture(), mSpeed(100.f)
    {
    	TextureHolder textures;
    	textures.Load(Textures::Airplane, "Flight.png");
    
    	mPlayer.setTexture(textures.GetTexture(Textures::Airplane));
    	mPlayer.setPosition(100.f, 100.f);
    }


    Quand j'exécute le code, j'obtiens cette erreur que je ne comprends pas trop, qui parle de fonction supprimée.

    Erreur	C2280	'std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>>::pair(const std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>> &)' : tentative de référencement d'une fonction supprimée	goSfml	C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\xmemory	682	
    
    1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\xmemory(682,47): error C2280: 'std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>>::pair(const std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>> &)' : tentative de référencement d'une fonction supprimée
    1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\utility(210): message : voir la déclaration de 'std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>>::pair'
    1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\utility(210,5): message : 'std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>>::pair(const std::pair<const Textures::ID,std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>> &)' : la fonction a été supprimée implicitement, car un données membres appelle une fonction supprimée ou inaccessible 'std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>::unique_ptr(const std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>> &)'
    1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\memory(3291,5): message : 'std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>>::unique_ptr(const std::unique_ptr<sf::Texture,std::default_delete<sf::Texture>> &)' : la fonction a été supprimée explicitement
    1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\xtree(354): message : voir la référence à l'instanciation de la fonction modèle 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,_Ty&>(_Alloc &,_Objty *const ,_Ty &)' en cours de compilation

    Avec d'autres erreurs qui viennent ensuite.

    En fouillant un peu, j'ai isolé la ligne qui provoquait l'erreur, qui est "std::unique_ptr", dans textureHolder.h :

    private:
    	std::map<Textures::ID, 
    		std::unique_ptr<sf::Texture>> mTextureMap;


    Là comme ça, j'ai l'impression que mon mTextureMap n'est pas initialisé et qu'il aime pas ça, mais je trouve pas la solution.
    Du coup je serai content d'avoir quelques explications sur ce qui ne va pas, quelles sont les bonnes pratiques, comment je peux pratiquer les pointeurs uniques pour que je puisse maitriser un peu + le sujet :)
    Le c++ tout seul c'est pas facile ..

    Je suis très novice, je saurai difficilement répondre à 'pourquoi j'ai fait ça' plutôt qu'autre chose, mais je suis à l'écoute de tout conseil !

    Merci beaucoup !

    -
    Edité par Hibiscae 22 septembre 2022 à 17:44:53

    • Partager sur Facebook
    • Partager sur Twitter
      22 septembre 2022 à 17:50:45

      Vous êtes sûr que ce n'est pas plutôt :

      mTextureMap.insert(std::make_pair(id, std::move(texture)));

      ???

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        22 septembre 2022 à 18:19:09

        Champ' a écrit:

        Le c++ tout seul c'est pas facile ..

        N'importe quel sujet, tout seul, c'est pas facile quand on débute de 0.

        Quel PDF ? Tu as regardé le cours C++ de Zeste de Savoir ?

        enum class ID { Landscape, Airplane, Missile }; // ajoute "class". Et c'est étrange d'utiliser un enum pour un ID
        auto texture { std::make_unique<sf::Texture>() }; 
        // utilise make_unique au lieu de new. Et si tu veux, "auto"
        sf::Texture& GetTexture(Textures::ID id); 
        // et si la texture n'existe pas ? Et pourquoi une ref non const, c'est modifiable ?
        TextureHolder textures;
        // Player qui est propriétaire de TextureHolder, c'est tres louche
        mTextureMap.emplace(id, std::move(texture));
        // utilise emplace a la place de insert

        Mais pour ton erreur de compilation, c'est étrange. Ton code semble valide. Tu es sur d'avoir montré correctement ton code ? Et que l'erreur correspond bien a cette ligne de code ?

        Il faut que tu montres le message d'erreur correspond a ton code, pas au code interne de Visual Studio.

        • Partager sur Facebook
        • Partager sur Twitter
          22 septembre 2022 à 22:55:45

          Hello,

          L'un des soucis est que tu déclares un TextureHolder dans ton constructeur de Player, puis tu tentes de récupérer une texture chargée que tu assignes à mTextures, puis vient la fin du constructeur... et donc la fin de TextureHolder!

          Donc les prochains appels à ta ressource ne se passeront pas bien, puisqu'elle sera détruite...

          Tu as plusieurs solutions mais pour moi tu dois externaliser ton TextureHolder, et donner en paramètre du constructeur de Player la texture que tu veux utiliser.

          Attention également, là tu copies une texture dans ton Player, et ça peut devenir très vite gourmand en ressources!

          Penses donc à ne garder q'une référence vers cette texture (par exemple, Textures::ID).

          Si c'est bien le livre auquel je pense (SFML Game Development), cette classe deviendra ensuite un template générique permettant de charger des Textures, mais également les autrzs ressources se basant sur le même schéma que sf::Texture.

          -
          Edité par nours59 22 septembre 2022 à 23:08:55

          • Partager sur Facebook
          • Partager sur Twitter
            23 septembre 2022 à 17:28:13

             Merci pour toutes vos suggestions ! Je vais essayer de répondre à tout le monde.

            bacelar a écrit:

            Vous êtes sûr que ce n'est pas plutôt :

            mTextureMap.insert(std::make_pair(id, std::move(texture)));

            ???

            Non je suis sûr de rien, mais ça a été à force de commenter et de remplacer les éléments de mon code pour "remonter" son exécution. Je n'ai visiblement plus d'erreurs une fois std::unique_ptr<sf::Texture>> mTextureMap, et plus particulièrement std::unique_ptr<sf::Texture> mais c'est très possible que je me trompe.

            gbdivers a écrit:

            Champ' a écrit:

            Le c++ tout seul c'est pas facile ..

            N'importe quel sujet, tout seul, c'est pas facile quand on débute de 0.

            Quel PDF ? Tu as regardé le cours C++ de Zeste de Savoir ?

            enum class ID { Landscape, Airplane, Missile }; // ajoute "class". Et c'est étrange d'utiliser un enum pour un ID
            auto texture { std::make_unique<sf::Texture>() }; 
            // utilise make_unique au lieu de new. Et si tu veux, "auto"
            sf::Texture& GetTexture(Textures::ID id); 
            // et si la texture n'existe pas ? Et pourquoi une ref non const, c'est modifiable ?
            TextureHolder textures;
            // Player qui est propriétaire de TextureHolder, c'est tres louche
            mTextureMap.emplace(id, std::move(texture));
            // utilise emplace a la place de insert

            Mais pour ton erreur de compilation, c'est étrange. Ton code semble valide. Tu es sur d'avoir montré correctement ton code ? Et que l'erreur correspond bien a cette ligne de code ?

            Il faut que tu montres le message d'erreur correspond a ton code, pas au code interne de Visual Studio.


            Je vais essayer de reprendre avec tes modifications ! J'ai montré le code qui me paraissait pertinent mais je peux mettre l'ensemble de mon projet en ligne. Mon code fonctionnait quand je faisais un chargement de texture sans classe, et a commencé à générer des erreurs après la création de la classe et des fichiers TextureHolder.

            Qu'est-ce que tu entends par le message d'erreur du code ? C'est les seuls que j'ai, et visualStudio ne me souligne pas de problèmes dans mon code :(

            Concernant les PDF, j'ai suivi 'Programmez avec le langage CPP' du site/livre du zéro, qui est un peu obsolète aujourd'hui, et 'SFML Game Developement' qu'à mentionné nours59. Je connaissais pas du tout Zeste de Savoir, je vais reprendre avec ce site. J'ai conscience que je manque de base un peu + solide et à jour mais je ne trouvais pas mieux jusqu'à présent.

            Dans tous les cas je vais reprendre avec tous ces éléments et réessayer :)

            nours59 a écrit:

            Hello,

            L'un des soucis est que tu déclares un TextureHolder dans ton constructeur de Player, puis tu tentes de récupérer une texture chargée que tu assignes à mTextures, puis vient la fin du constructeur... et donc la fin de TextureHolder!

            Donc les prochains appels à ta ressource ne se passeront pas bien, puisqu'elle sera détruite...

            Tu as plusieurs solutions mais pour moi tu dois externaliser ton TextureHolder, et donner en paramètre du constructeur de Player la texture que tu veux utiliser.

            Attention également, là tu copies une texture dans ton Player, et ça peut devenir très vite gourmand en ressources!

            Penses donc à ne garder q'une référence vers cette texture (par exemple, Textures::ID).

            Si c'est bien le livre auquel je pense (SFML Game Development), cette classe deviendra ensuite un template générique permettant de charger des Textures, mais également les autrzs ressources se basant sur le même schéma que sf::Texture.

            -
            Edité par nours59 il y a environ 17 heures



            Par rapport au constructeur, comme tu le dis ça me fait sens.. Je l'ai mis dans le constructeur parce que, avant d'en faire une classe, mon code fonctionnait en appelant la texture sans TextureHolder.h/cpp et de cette manière (dans player.cpp) :

            Player::Player()
            	: mPlayer(), mTexture(), mSpeed(100.f)
            {
            	if (!mTexture.loadFromFile("Flight.png")) {
            		// Loading Error
            	}
            	mPlayer.setTexture(mTexture);
            	mPlayer.setPosition(100.f, 100.f);
            }


            Avec le prototype mPlayer dans player.h

            private:
            	sf::Texture mTexture;
            	sf::Sprite mPlayer;
            	float mSpeed{};

            Appelé dans game.h

            Player mPlayer;

            Pour être window.draw dans game.cpp (avec une méthode publique GetPlayer qui fait juste un return de mPlayer)

            void Game::Render(Player object)
            {
            	mWindow.clear();
            	mWindow.draw(object.GetPlayer());
            	mWindow.display();
            }

            Comme il s'agissait de remplacer cette configuration par une classe TextureHolder, je l'ai mise dans le constructeur.

            Je ne sais pas trop ce que tu entends par 'externaliser TextureHolder', mais je vais creuser dans ce sens avant de remettre à jour le poste, et reprendre avec le zestedusavoir (merci pour le lien dans ta signature d'ailleurs).

            Merci encore :)




            • Partager sur Facebook
            • Partager sur Twitter
              5 octobre 2022 à 16:12:10

              J'ai utilisé ce livre, il n'est pas parfait ni récent (au mieux, C++11), c'est l'un des plus correcte que j'ai lu jusqu'à présent.

              Champ' a écrit:

              Je ne sais pas trop ce que tu entends par 'externaliser TextureHolder', mais je vais creuser dans ce sens avant de remettre à jour le poste, et reprendre avec le zestedusavoir (merci pour le lien dans ta signature d'ailleurs).

              Si on definit les rôles de chaque classe:
              TextureHolder: Un conteneur de textures où les classes représentant les différents elements graphiques pourrons "pêcher" la ou les textures qui les intéressent. Idéalement, une seule et unique instance suffit.
              Player: Un élément graphique (parmi tant d'autres) représentant un avatar identifiable pour le joueur.

              Le problème, est que si la classe Player instancie en interne la classe TextureHolder, comment ses voisins (classe Ennemy, classe Sprite ect ...) feront-elles pour avoir accès à ce même TextureHolder sans violer la classe Player ?
              Clairement, cela indique qu'il n'est pas de la responsabilité de la classe Player d'instancier la classe TextureHolder (cela doit être fait ailleurs, d'où "Externaliser"). Elle peut en revanche, détenir une référence sur cette dernière.
              Quand à la façon d'implémenter ce comportement, je te laisse y réfléchir.

              • Partager sur Facebook
              • Partager sur Twitter

              Pointeur Unique avec SFML

              × 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