Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Wirago

Alter Hase

  • »Wirago« ist der Autor dieses Themas

Beiträge: 1 193

Wohnort: Stockerau

Beruf: CRM Application Manager

  • Private Nachricht senden

1

08.05.2015, 17:19

SFML Sprite bleibt weiß

Ich arbeite mich gerade in die SFML ein und habe das Problem, das mein Sprite weiß bleibt. Ich lade die Textur über eine RessourceHolder-Klasse die es ermöglichen soll, allerlei Typen zu laden (Texture, Sprite, Font etc.)
Lade ich diese direkt auf mein Sprite funktioniert es, über die Holder-Klasse bleibt das Spieler-Sprite aber weiß.

Ich denke, dass es irgendwo an der Übergabe scheitert, denn die Texturen werden eigentlich korrekt geladen.

Die Implementation sieht so aus (nur relevanten Code kopiert)

Game.h

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
namespace Textures
{
    enum ID { Landscape, Airplane, Missile };
}


class Game
{
public:
    Game();
    void run();

private:
    void processEvents();
    void update(sf::Time deltaTime);
    void render();
    void Game::handlePlayerInput(sf::Keyboard::Key key, bool isPressed);
    void updateStatistics(sf::Time elapsedTime);

    sf::RenderWindow mWindow;
    bool mIsMovingUp;
    bool mIsMovingDown;
    bool mIsMovingLeft;
    bool mIsMovingRight;

    static const float PlayerSpeed;
    static const sf::Time TimePerFrame;

    sf::Texture mTexture;
    sf::Sprite mPlayer;
    sf::Text mStatisticsText;
    sf::Time mStatisticsUpdateTime;
    sf::Font mFont;

    std::size_t mStatisticsNumFrames;
}


RessourceHolder.h

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename Ressource, typename Identifier>
class RessourceHolder
{
public:
    void load(Identifier id, const std::string& filename);

    template <typename Parameter>
    void load(Identifier id, const std::string& filename, const Parameter& secondParam);

    Ressource& get(Identifier id);
    const Ressource& get(Identifier id) const;

private:
    std::map<Identifier, std::unique_ptr<Ressource>> mRessourceMap;
};


Implementierung von load()

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <typename Ressource, typename Identifier>
void RessourceHolder<Ressource, Identifier>::load(Identifier id, const std::string& filename)
{
    std::unique_ptr<Ressource> ressource(new Ressource());
    if (!ressource->loadFromFile(filename))
        throw std::runtime_error("RessourceHolder::load - Failed to load" + filename);

        //Nachfolgendes gibt die passende Consolenausgabe "xy loaded" aus
    if (ressource->loadFromFile(filename))
    {
        std::cout << filename << " loaded" << std::endl;
    }

    auto inserted = mRessourceMap.insert(std::make_pair(id, std::move(ressource)));
    assert(inserted.second);
}


Implementierung von get()

C-/C++-Quelltext

1
2
3
4
5
6
7
8
template <typename Ressource, typename Identifier>
Ressource& RessourceHolder<Ressource, Identifier>::get(Identifier id)
{
    auto found = mRessourceMap.find(id);
    assert(found != mRessourceMap.end());

    return *found->second;
}


Und zu guter letzt die Game.cpp ( Game::Game() )

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
{
    mTexture.loadFromFile("Media/Textures/Eagle.png"); 
    mPlayer.setTexture(mTexture); // So funktioniert es

    
    RessourceHolder<sf::Texture, Textures::ID> textures;
    textures.load(Textures::Airplane, "Media/Textures/Eagle.png");
    mPlayer.setTexture(textures.get(Textures::Airplane)); // so funktionert es nicht!
    
}


Eigentlich liefert ja textures.get (letzte Zeile) korrekt eine Texture zurück, womit ich mir erwartet hätte, dass ich die dann mPlayer zuweisen kann. Aber irgendwie kommt da nur weiß an.
Jemand eine Idee?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

08.05.2015, 17:44

Ändere mal das return *found->second in return *(found->second.get());
Einen ähnlichen Fall hatten wir letzten schon im Chat. Es sollte identisch sein, aber * tat irgendwie nicht das, was man erwartet hätte laut Spezifikation (weder in VC, noch in ideone).
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

3

08.05.2015, 17:47

Deine Textur wird irgendwo ungültig. Oft geschieht das dadurch, dass die Texture zum Zeitpunkt des Draw-Befehls nicht mehr existiert. Ein Blick auf deine Resource-Klasse wäre noch schön.
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

Wirago

Alter Hase

  • »Wirago« ist der Autor dieses Themas

Beiträge: 1 193

Wohnort: Stockerau

Beruf: CRM Application Manager

  • Private Nachricht senden

4

08.05.2015, 17:47

Ändere mal das return *found->second in return *(found->second.get());

sf::Texture hat keine get-Methode, was sich auch in der Fehlermeldung zeigt:

Quellcode

1
error C2039: 'get' : is not a member of 'sf::Texture'

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

08.05.2015, 17:50

Wieso sf::Texture? Sollte da nicht ein unique_ptr rauskommen? "found" ist der Iterator, "found->second()" der unique_ptr, "found->second().get()" der sf:Texture*. Oder was übersehe ich?
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Wirago

Alter Hase

  • »Wirago« ist der Autor dieses Themas

Beiträge: 1 193

Wohnort: Stockerau

Beruf: CRM Application Manager

  • Private Nachricht senden

6

08.05.2015, 17:50

Deine Textur wird irgendwo ungültig. Oft geschieht das dadurch, dass die Texture zum Zeitpunkt des Draw-Befehls nicht mehr existiert. Ein Blick auf deine Resource-Klasse wäre noch schön.


Ja, an das habe ich auch schon gedacht, nur wüsste ich nicht a) warum die an der Stelle schon ungültig sein sollte und b) wie ich das in dem Fall verhindern könnte.

Die komplette RessourceHolder-Klasse sieht so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
template <typename Ressource, typename Identifier>
class RessourceHolder
{
public:
    void load(Identifier id, const std::string& filename);

    template <typename Parameter>
    void load(Identifier id, const std::string& filename, const Parameter& secondParam);

    Ressource& get(Identifier id);
    const Ressource& get(Identifier id) const;

private:
    std::map<Identifier, std::unique_ptr<Ressource>> mRessourceMap;
};


//Template Implementation

template <typename Ressource, typename Identifier>
void RessourceHolder<Ressource, Identifier>::load(Identifier id, const std::string& filename)
{
    std::unique_ptr<Ressource> ressource(new Ressource());
    if (!ressource->loadFromFile(filename))
        throw std::runtime_error("RessourceHolder::load - Failed to load" + filename);

    if (ressource->loadFromFile(filename))
    {
        std::cout << filename << " loaded" << std::endl;
    }

    auto inserted = mRessourceMap.insert(std::make_pair(id, std::move(ressource)));
    assert(inserted.second);
}

template <typename Ressource, typename Identifier>
template <typename Parameter>
void RessourceHolder<Ressource, Identifier>::load(Identifier id, const std::string& filename, const Parameter& secondParam)
{
    std::unique_ptr<Ressource> ressource(new Ressource());
    if (!ressource->loadFromFile(filename, secondParam))
        throw std::runtime_error("RessourceHolder::load - Failed to load " + filename);

    auto inserted = mRessourceMap.insert(std::make_pair(id, std::move(ressource)));
    assert(inserted.second);
}


template <typename Ressource, typename Identifier>
Ressource& RessourceHolder<Ressource, Identifier>::get(Identifier id)
{
    auto found = mRessourceMap.find(id);
    assert(found != mRessourceMap.end());

    return *found->second;
}

template <typename Ressource, typename Identifier>
const Ressource& RessourceHolder<Ressource, Identifier>::get(Identifier id) const
{
    auto found = mRessourceMap.find(id);
    assert(found != mRessourceMap.end());

    return *found->second;
}


Wieso sf::Texture? Sollte da nicht ein unique_ptr rauskommen?


Naja, ein unique_ptr auf eine Texture was durch dereference zu sf::Texture wird. Nein?
Daher auch der Gedanke, dass die Texture aus dem Rückgabewert direkt verwendet werden kann.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

08.05.2015, 17:55

Ja, aber woher kommt dann der Compile-Fehler? Du willst einen sf::Texture& zurückgeben und .get() sollte den sf::Texture* liefern.
"found" ist der Iterator, "found->second()" der unique_ptr, "found->second().get()" der sf:Texture*. Oder was übersehe ich?
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Wirago

Alter Hase

  • »Wirago« ist der Autor dieses Themas

Beiträge: 1 193

Wohnort: Stockerau

Beruf: CRM Application Manager

  • Private Nachricht senden

8

08.05.2015, 18:08

Ja, aber woher kommt dann der Compile-Fehler? Du willst einen sf::Texture& zurückgeben und .get() sollte den sf::Texture* liefern.
"found" ist der Iterator, "found->second()" der unique_ptr, "found->second().get()" der sf:Texture*. Oder was übersehe ich?


Nicht ganz. std::map::find() liefert den Iterator, ja. Der Iterator zeigt auf ein std::pair<Identifier, std::unique_ptr<Ressource>> . Und Ressource beinhaltet meine Texture. Daher kann ich per dereference auf found->second die Texture abfragen.
So zumindest der Plan.

Wirago

Alter Hase

  • »Wirago« ist der Autor dieses Themas

Beiträge: 1 193

Wohnort: Stockerau

Beruf: CRM Application Manager

  • Private Nachricht senden

9

08.05.2015, 18:19

Habs noch weiter eingeschränkt:

Geht:

C-/C++-Quelltext

1
2
mTexture = textures.get(Textures::Airplane);
mPlayer.setTexture(mTexture);


Geht nicht:

C-/C++-Quelltext

1
mPlayer.setTexture(textures.get(Textures::Airplane));


?( ?(
Wo zum Teufel ist da der Unterschied?

10

08.05.2015, 18:44

Mal ganz Laienhaft, da ich noch nie SmartPointer oder UniquePointer verwendet habe und deswegen nicht weiß ob das da anders ist. Du speicherst doch Pointer in der RescourcenMap, ein Pointer muss aber doch irgendwo hinzeigen oder werden bei UniquePointer die auf dem Heap erstellt? Wie gesagt kenn ich mich mit denen garnicht aus.

Weil dann würd ich sagen, bei dem wo es geht, verweist dein Pointer halt auf mTexture und findet dort die Daten und beim zweiten mal wo es nicht geht, übergibst du zwar halt die Werte und deren Adresse wird abgespeichert, aber die werden dann nach der Funktion doch gleich gelöscht und dein Zeiger zeigt auf nichts.

Falls ich mist rede, einfach ignorieren. :D

Werbeanzeige