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

1

10.08.2012, 16:34

Snake-Spiel in C++ mit SFML: Problem mit verketteter Liste

Hallo,
Ich habe das Buch "C++ für Spieleprogrammierer" durchgearbeitet und danach auf Youtube einige Tutorials zur Bibliothek "SFML" bearbeitet, und wollte nun mal anfangen, mein erstes kleines Spiel zu programmieren und habe mich für "Snake" entschieden.

Ich speichere die Positionen der einzelnen Segmente der Schlange in einer verketteten Liste, habe mir dafür eine Klasse für Positionen geschrieben und speichere dann Positionsobjekte in der Liste. Die Position des Kopfes der Schlange ist in einer extra Variable gespeichert.
In der update-Funktion der Schlange wird die Position des Kopfes in die aktuelle Richtung um einen Block bewegt, anschließend vorne in die Liste geschoben, und wenn die Größe der Liste größer ist als die Länge der Schlange, dann wird das letzte Element der Liste entfernt.

Dabei tritt jedoch ein seltsames Problem auf, dass ich mir nicht erklären kann. Ich habe mir in der update-Funktion die Koordinate des Schlangenkopfes in der Konsole anzeigen lassen und greife dabei auf das erste Element der Positionsliste zu (mit "front()"), und dabei ist mir aufgefallen, dass zu Beginn der update-Funktion die x-Position der Schlange immer 1 ist, am Ende der update-Funktion jedoch immer den richtigen Wert hat und sich auch verändert.
Dabei habe ich die Schlange nie manuell auf die Position 1 gesetzt (auch nicht beim erstellen über den Konstruktor), und die Startrichtung der Schlange ist auch auf rechts gesetzt, weshalb es merkwürdig ist, dass die Schlange auf einmal weiter links ist als zu Beginn.

Vielleicht tut es auch noch zur Sache, dass die update-Funktion der Schlange nur aufgerufen wird, wenn keine Kollision mit der Wand oder der Schlange selbst auftritt (es wird geprüft, ob der Kopf der Schlange ein anderes Segment der Schlange berührt, Kopf mit Kopf wird dabei aber ausgeschlossen, denn sonst würde ja die ganze Zeit eine Kollision erkannt werden), denn bei einer Kollision soll sich die Schlange ja nicht weiter bewegen. Außerdem wird vorher geprüft, ob der Timer das Zeitlimit erreicht hat, sodass beispielsweise die Schlange sich alle 0.1s um einen Block weiterbewegt. Anschließend wird der Timer wieder zurückgesetzt.
Dies geschieht in der update-Funktion der Game-Klasse, welche bei jedem Schleifendurchgang aufgerufen wird.. Die render-Funktion der Schlange wird ebenfalls bei jedem Schleifendurchgang aufgerufen.

Ich hoffe mir kann jemand helfen, danke schonmal im Voraus.

Hier die Quelltexte:

Positionsklasse Header:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Position
{
    private:
        int m_x;
        int m_y;

    public:
        Position (int x, int y);
        void move (eDirection direction);
        bool operator== (Position &position);
        bool operator!= (Position &position);

        void setX (int x);
        void setY (int y);

        int getX ();
        int getY ();
};


Positionsklasse Konstruktor:

C-/C++-Quelltext

1
2
3
Position::Position (int x, int y)
:   m_x (x), m_y (y)
{}


Positionsklasse move-Funktion:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Position::move (eDirection direction)
{
    switch (direction)
    {
        case RIGHT:
            m_x++;
        break;

        case DOWN:
            m_y++;
        break;

        case LEFT:
            m_x--;
        break;

        case UP:
            m_y--;
        break;
    }
}


Schlange Konstruktor:

C-/C++-Quelltext

1
2
3
4
5
Snake::Snake (Position position, eDirection direction, int length)
:   m_position (position), m_direction (direction), m_length (length)
{
    m_listSegmentPositions.push_front (m_position);
}


Schlange: update-Funktion

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Snake::update ()
{
    // hier ist front() immer 1
    std::cout << "Snake Position: " << m_listSegmentPositions.front().getX() << ", " << m_listSegmentPositions.front().getY() << std::endl;
    std::cout << "Snake Length: " << m_length << std::endl;
    std::cout << "Snake List Size: " << m_listSegmentPositions.size () << std::endl;

    m_position.move (m_direction);
    m_listSegmentPositions.push_front (m_position);
    
    if (m_listSegmentPositions.size () > static_cast<unsigned>(m_length))
        m_listSegmentPositions.pop_back ();

    // hier hat front() den richtigen Wert und verändert sich auch
    std::cout << "Snake Position: " << m_listSegmentPositions.front().getX() << ", " << m_listSegmentPositions.front().getY() << std::endl;
    std::cout << "Snake Length: " << m_length << std::endl;
    std::cout << "Snake List Size: " << m_listSegmentPositions.size () << std::endl;
}


Schlange: render-Funktion:

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
void Snake::render (sf::RenderWindow *pWindow)
{
    sf::Sprite tempSprite;

    for (std::list <Position>::iterator it = m_listSegmentPositions.begin (); it != m_listSegmentPositions.end (); it++)
    {
        // Kopf
        if (*it == m_listSegmentPositions.front ())
            tempSprite.setTexture (m_textureFront);

        // Schwanzspitze
        else if (*it == m_listSegmentPositions.back ())
            tempSprite.setTexture (m_textureBack);

        // Mittelteil
        else
            tempSprite.setTexture (m_textureMiddle);

        tempSprite.setPosition ((float)(it->getX() * BLOCKSIZE), (float)(it->getY() * BLOCKSIZE));
        pWindow->draw (tempSprite); 
    }
}

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »Jack069« (11.08.2012, 13:26)