Du bist nicht angemeldet.

Werbeanzeige

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 524

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

1

14.10.2015, 15:31

[C++ | SFML] Problem bei dem Zeichnen von Objekten in einer Liste

Hallo Leute,

zurzeit entwickle ich (mal wieder) ein Spiel. Bei diesem Spiel steuert man ein Raumschiff, welches vor Asteroiden ausweichen muss. Diese Asteroiden manage ich in einer Liste. Jede halbe Sekunde wird ein neuer Asteroid erstellt. Im PlayState werde alle Asteroiden geupdatet, Kollisionen geprüft und gerendert. Hier erstmal der Code:

PlayState.hpp:

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
#pragma once

// andere includes

#include <memory>
#include <list>

class Game;
class Player;

class PlayState : public GameState
{
public:
    PlayState();

    void Update(Game &game) override;
    void ProcessEvents(Game &game) override;
    void Render(sf::RenderWindow &App) override;

    void loadPlayassets();

private:
    void SpawnAsteroid();

private:
    sf::Font mFont;

    sf::Text txtLive;
    sf::Text txtPoints;

    sf::Clock clock;

    int m_iLive;
    int m_iPoints;
    const float m_fAsteroidSpawnTime = 0.5f;

    std::list<Asteroid*> mAsteroidList;

    std::unique_ptr<Player> mPlayer;
};


PlayState.cpp:

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "include\PlayState.hpp"

#include "player\include\Player.hpp"

PlayState::PlayState()
    : m_iLive(3)
    , m_iPoints(0)
{
    clock.restart().Zero;

    loadPlayassets();
}


void PlayState::Update(Game &game)
{
// Hier werden die Texte geupdatet

    mPlayer->Update();

    // Jeden Asteroiden updaten
    for (auto it : mAsteroidList)
    {
        it->Update();
    }

    // Wenn der Asteroid nicht am Leben ist, dann von der Liste entfernen
    for (auto it = mAsteroidList.begin(); it != mAsteroidList.end(); it++)
    {
        if (!(*it)->getAlive())
        {
            delete (*it);
            (*it) = nullptr;

            it = mAsteroidList.erase(it);
        }
    }

    // Neue Asteroiden erstellen
    SpawnAsteroid();

    std::cout << mAsteroidList.size() << std::endl;

}

void PlayState::ProcessEvents(Game &game)
{
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
    {
        mAsteroidList.clear();

        game.changeState(Game::gameState::MAINMENU);
    }

    mPlayer->ProcessEvents();

}


void PlayState::Render(sf::RenderWindow &App)
{
    mPlayer->Render(App);

    // Alle Asteroiden darstellen
    for (auto it : mAsteroidList)
    {
        std::cout << "Render" << std::endl;
        it->Render(App);
    }

    App.draw(txtLive);
    App.draw(txtPoints);
}


void PlayState::loadPlayassets()
{
// Texte werdn hier geladen

    mPlayer = std::make_unique<Player>();
    mPlayer->loadPlayerAssets();

}


void PlayState::SpawnAsteroid()
{
    // Alle halbe Sekunde einen neuen Asteroiden erzeugen
    if (clock.getElapsedTime().asSeconds() >= 0.5f)
    {
        // Neuer Asteroid
        Asteroid asteroid;

        asteroid.Init();

        mAsteroidList.push_back(&asteroid);

        clock.restart().Zero;
    }

}


Asteroid.hpp:

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
#pragma once

#include "core\include\Game.hpp"

#include <Windows.h>

#pragma comment (lib, "winmm.lib")

class Asteroid
{
public:
    Asteroid();

    void Init();

    void Update();
    void CheckCollision(sf::Sprite sprite);
    void Render(sf::RenderWindow &App);

    // getter
    bool getAlive() { return m_bAlive; };

private:
    void loadAsteroid();

    float randXPos();

private:
    sf::Texture mTexture;
    sf::Sprite  mSprite;

    bool m_bAlive;

    float m_fCurrentXPos;
    float m_fCurrentYPos;

    const float m_fSpeed = 0.1f;
};


Asteroid.cpp:

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
#include "include\Asteroid.hpp"

Asteroid::Asteroid()
    : m_bAlive(true)
    , m_fCurrentXPos(0.f)
    , m_fCurrentYPos(0.f)
{
    loadAsteroid();
}


void Asteroid::Init()
{
    // Generator initialisieren
    srand(timeGetTime());

}


void Asteroid::Update()
{
    mSprite.move(0.f, m_fSpeed);
}


void Asteroid::CheckCollision(sf::Sprite sprite)
{
    // Überschneiden sich der Asteroid mit dem angegbenen Sprite?
    if (sprite.getGlobalBounds().intersects(mSprite.getGlobalBounds()))
    {
        // Kollision!
        m_bAlive = false;
    }

}


void Asteroid::Render(sf::RenderWindow &App)
{
    App.draw(mSprite);
}


void Asteroid::loadAsteroid()
{
    if (!mTexture.loadFromFile("assets/textures/asteroid/Asteroid.png"))
        throw std::runtime_error("Konnte den Asteroiden nicht laden - Asteroid.cpp");

    mSprite.setTexture(mTexture);
    mSprite.setOrigin(mTexture.getSize().x / 2, mTexture.getSize().y / 2);  // Mittelpunkt ist genau in der Mitte der Textur
    mSprite.setOrigin(mTexture.getSize().x / 2, mTexture.getSize().y / 2);

    mSprite.setPosition(randXPos(), 1.f);

}


float Asteroid::randXPos()
{
    float xPos = rand() % 930 + 30;

    return xPos;
}


Das Problem: Sobald die Asteroiden in der Rendermethode in PlayState.cpp gerendert werden, bekomme ich eine Fehlermeldung (Anhang) und er verweist auf das "App.draw(mSprite);" in Asteroid.cpp.
Was ist mein Fehler?

Vielen Dank im Voraus :)
»cojo2015« hat folgendes Bild angehängt:
  • Unbenannt.PNG

Tobiking

1x Rätselkönig

  • Private Nachricht senden

2

14.10.2015, 15:53

Ich seh zwar gerade auf Anhieb nicht wo du auf falschen Speicher zugreifst, aber beim Löschen von Elementen während des Iterieren wirst du mit einer For-Schleife keinen Spaß haben. Wenn ein Element gelöscht wird, bekommst du den Iterator auf das nachfolgende Objekt. Den verwendest du nicht, sondern holst dir im Schleifenkopf erneut den Nachfolger. Du überspringst somit nach jeden Löschen das nachfolgende Element.

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 524

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

3

14.10.2015, 16:01

Ich seh zwar gerade auf Anhieb nicht wo du auf falschen Speicher zugreifst, aber beim Löschen von Elementen während des Iterieren wirst du mit einer For-Schleife keinen Spaß haben. Wenn ein Element gelöscht wird, bekommst du den Iterator auf das nachfolgende Objekt. Den verwendest du nicht, sondern holst dir im Schleifenkopf erneut den Nachfolger. Du überspringst somit nach jeden Löschen das nachfolgende Element.
Geht es um Zeile 28 in PlayState.cpp? Und müsste ich dann zuerst eine hile-Schleife machen und darin eine for-Schleife verschachteln, oder wie wäre die optimale Lösung?

4

14.10.2015, 16:08

Du inkrementierst nur, wenn du es nicht entfernst, ansonsten gibt vector::erase den nachfolgenden iterator zurück.

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 524

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

5

14.10.2015, 16:13

Du inkrementierst nur, wenn du es nicht entfernst, ansonsten gibt vector::erase den nachfolgenden iterator zurück.

Gibt list::erase auch den nachfolgenden iterator zurück?
PS: Muss ich Zeile 32/33 mit Zeile 35 vertauschen (PlayState.cpp)?

6

14.10.2015, 16:24

Gucken wir doch mal: http://lmgtfy.com/?q=std+list+erase
Ein Zugriff auf einen invaliden Iterator (wie er nach erase entsteht) ist doof.
Den Wert auf den der Iterator zeigt auf nullptr zu setzen, wenn du ihn danach eh entfernst ist auch nicht ganz sinnbehaftet ;)

7

14.10.2015, 16:27

PS: Muss ich Zeile 32/33 mit Zeile 35 vertauschen (PlayState.cpp)?


  • was macht delete it?
  • Was macht std::list::erease(it)?
  • Was macht std::list::erease(it) wenn it nullptr ist?
  • Warum werden die Asterioden in 2 Schleifen durchlaufen?
  • Wie würden die for-Schleifen als While-Schleife aussehen?

Ich hoffe die Fragen regen dich an, selber mal nachzudenken!
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 524

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

8

14.10.2015, 16:54

Wie würden die for-Schleifen als While-Schleife aussehen?
Ich hab das so gelöst: (it = std::list<Asteroid>::iterator it)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
    it = mAsteroidList.begin();
    while (it != mAsteroidList.end())
    {
        bool isAlive = (*it)->getAlive();
        if (!isAlive)
        {
            mAsteroidList.erase(it++);
        }
        else
            ++it;
    }


Ist das sinngemäß richtig?

9

14.10.2015, 17:22

Ist das sinngemäß richtig?

Nein!

Wenn ein Element gelöscht wird, bekommst du den Iterator auf das nachfolgende Objekt.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

cojo2015

Alter Hase

  • »cojo2015« ist der Autor dieses Themas

Beiträge: 524

Wohnort: bei mir zu Hause

Beruf: Schüler

  • Private Nachricht senden

10

14.10.2015, 17:32

nachfolgende

Muss ich anstatt it++, it-- schreiben, oder das ++ bzw. das -- weg lassen? Tut mir leid, aber ich weiss es wirklich nicht. Hab mal hier nachgeschaut: http://stackoverflow.com/questions/59616…ting-through-it

Werbeanzeige