Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

gra snake - problem z przekazaniem informacji o zakończeniu gry

Ostatnio zmodyfikowano 2024-06-17 17:12
Autor Wiadomość
phalange
Temat założony przez niniejszego użytkownika
gra snake - problem z przekazaniem informacji o zakończeniu gry
» 2024-06-17 00:53:22
Cześć wszystkim,

Mam napisany program do podstawowej wersji snake'a używając SFMLa. Cała logika działa, problem jest jedynie przy zakończeniu gry - okno z napisem game over i ilościa uzyskanych punktów wyświetla się już na początku gry, pomimo że getter statusu gry jest wszędzie ustawiony według mnie poprawnie. Wiąże się z tym również problem, że okno się nie zamyka po kolizji węża ze ścianą czy przeszkodą. Byłabym bardzo wdzięczna za wszelkie rady, gdzie mam źle ustawione. Poniżej pliki, które wpływają na stan gry, dziekuję za pomoc

C/C++
Controller:
#include "controller.h"
#include <cstdlib>
#include <ctime>

GameManager::GameManager( Board & board, snake_figure & snakeFigure, unsigned obstacles, int speed, Ranking & ranking, Menu & menu, sfmlview & view )
    :
board( board )
   
, figura( snakeFigure )
   
, numObstacles( obstacles )
   
, snakeSpeed( speed )
   
, ranking( ranking )
   
, menu( menu )
   
, view( view )
   
, czy_trwa( true )
   
, scoreSaved( false )
{ }

void GameManager::update_game() {
   
// Aktualizowanie pozycji węża na planszy
   
for( int i = 0; i < figura.get_fig_size(); i++ ) {
       
board.spawn_snake( figura.get_coords( i ).first, figura.get_coords( i ).second );
   
}
   
std::pair < int, int > oldHeadCoords = figura.get_last_coords().koordy();
   
figura.move();
   
board.delete_snake( oldHeadCoords.first, oldHeadCoords.second );
   
   
// Sprawdzenie, czy wąż zjadł jabłko
   
if( figura.get_head().koordy().first == appleX && figura.get_head().koordy().second == appleY ) {
       
figura.add_score();
       
snake_blocks end;
       
end.x = figura.get_last_coords().koordy().first;
       
end.y = figura.get_last_coords().koordy().second;
       
figura.change_figure( end );
       
       
board.delete_apple( appleX, appleY );
       
       
unsigned newAppleX, newAppleY;
       
do {
           
newAppleX = rand() % board.get_size();
           
newAppleY = rand() % board.get_size();
       
} while( board.has_snake( newAppleX, newAppleY ) || board.has_obstacle( newAppleX, newAppleY ) );
       
       
appleX = newAppleX;
       
appleY = newAppleY;
       
       
board.spawn_apple( appleX, appleY );
   
}
   
   
// Sprawdzenie kolizji z ciałem węża
   
figura.kolizja();
   
   
// Sprawdzenie kolizji z granicą planszy lub przeszkodą
   
int headX = figura.get_head().koordy().first;
   
int headY = figura.get_head().koordy().second;
   
   
if( headX >= board.get_size() || headY >= board.get_size() || headX < 0 || headY < 0 ) {
       
czy_trwa = false;
       
if( !scoreSaved ) {
           
ranking.addScore( menu.getPlayerName(), figura.get_score() );
           
scoreSaved = true;
       
}
       
return;
   
}
   
   
if( figura.czy_kolizja() || board.has_obstacle( headX, headY ) ) {
       
czy_trwa = false;
       
if( !scoreSaved ) {
           
ranking.addScore( menu.getPlayerName(), figura.get_score() );
           
scoreSaved = true;
       
}
       
return;
   
}
}


void GameManager::play( sf::RenderWindow & window ) {
   
srand( time( 0 ) );
   
board.add_obstacles( numObstacles );
   
unsigned a = rand() % board.get_size();
   
unsigned b = rand() % board.get_size();
   
appleX = a;
   
appleY = b;
   
board.spawn_apple( a, b );
   
   
sf::Clock clock;
   
snakeSpeed = menu.getSnakeSpeed();
   
if( menu.gameStarted ) {
       
czy_trwa = true;
   
}
   
while( window.isOpen() ) {
       
if( clock.getElapsedTime().asMilliseconds() > snakeSpeed && czy_trwa ) {
           
update_game();
           
clock.restart();
       
}
       
       
sf::Event event;
       
while( window.pollEvent( event ) ) {
           
if( event.type == sf::Event::Closed ) {
               
window.close();
           
}
           
if( event.type == sf::Event::KeyPressed ) {
               
handle_input( event );
           
}
        }
       
       
window.clear();
       
view.draw( window, board, figura );
       
       
if( !czy_trwa ) {
           
window.draw( gameOverText );
           
scoreText.setString( "Score: " + std::to_string( figura.get_score() ) );
           
window.draw( scoreText );
       
}
       
       
window.display();
   
}
   
   
sf::Clock delayClock;
   
while( delayClock.getElapsedTime().asSeconds() < 3 ) {
       
sf::Event event;
       
while( window.pollEvent( event ) ) {
           
if( event.type == sf::Event::Closed ) {
               
window.close();
           
}
        }
    }
}



void GameManager::handle_input( sf::Event event ) {
   
if( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) ) {
       
figura.turn( A_CLOCKWISE );
   
} else if( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) ) {
       
figura.turn( CLOCKWISE );
   
}
}
C/C++
Menu:
#include "menu.h"
#include <iostream>

Menu::Menu()
    :
numObstacles( 0 )
   
, snakeSpeed( 0 )
   
, gameStarted( true )
{
   
if( !font.loadFromFile( "/home/marta/git/snake/snake_ak_wt15_281312/Montserrat-Regular.ttf" ) ) {
       
std::cout << "Failed to load font" << std::endl;
   
}
   
   
initializeText( title, "Snake Game", 40, 180, 50 );
   
initializeText( username, "Enter your name: ", 24, 180, 150 );
   
initializeText( game_level, "Select difficulty:", 24, 120, 250 );
   
initializeText( easy, "1. Easy (4 obstacles, 0,8 s)", 24, 150, 300 );
   
initializeText( medium, "2. Medium (6 obstacles, 0,25 s)", 24, 150, 350 );
   
initializeText( hard, "3. Hard (12 obstacles, 0,1 s)", 24, 150, 400 );
   
initializeText( playPrompt, "Press Enter to start", 24, 150, 500 );
   
initializeText( inputName, "", 24, 400, 150 );
}

void Menu::initializeText( sf::Text & text, const sf::String & str, int size, float x, float y ) {
   
text.setFont( font );
   
text.setString( str );
   
text.setCharacterSize( size );
   
text.setPosition( x, y );
}

void Menu::show_menu( sf::RenderWindow & window ) {
   
playerName = "";
   
sf::Event event;
   
while( window.isOpen() ) {
       
while( window.pollEvent( event ) ) {
           
if( event.type == sf::Event::Closed ) {
               
window.close();
           
}
           
else if( event.type == sf::Event::TextEntered ) {
               
if( event.text.unicode < 128 && event.text.unicode != 13 ) { // Exclude Enter key
                   
char typedChar = static_cast < char >( event.text.unicode );
                   
if( std::isalpha( typedChar ) ) {
                       
playerName += typedChar;
                       
inputName.setString( playerName );
                   
}
                }
            }
           
else if( event.type == sf::Event::KeyPressed ) {
               
if( event.key.code == sf::Keyboard::Num1 ) {
                   
numObstacles = 4;
                   
snakeSpeed = 800;
                   
easy.setFillColor( sf::Color::Red );
                   
medium.setFillColor( sf::Color::White );
                   
hard.setFillColor( sf::Color::White );
               
}
               
else if( event.key.code == sf::Keyboard::Num2 ) {
                   
numObstacles = 6;
                   
snakeSpeed = 250;
                   
easy.setFillColor( sf::Color::White );
                   
medium.setFillColor( sf::Color::Red );
                   
hard.setFillColor( sf::Color::White );
               
}
               
else if( event.key.code == sf::Keyboard::Num3 ) {
                   
numObstacles = 12;
                   
snakeSpeed = 100;
                   
easy.setFillColor( sf::Color::White );
                   
medium.setFillColor( sf::Color::White );
                   
hard.setFillColor( sf::Color::Red );
               
}
               
else if( event.key.code == sf::Keyboard::Enter ) {
                   
if( !playerName.empty() && numObstacles > 0 && snakeSpeed > 0 ) {
                       
gameStarted = true;
                       
return;
                   
} else {
                       
std::cout << "Please enter your name and select a difficulty level." << std::endl;
                   
}
                }
            }
        }
       
       
window.clear();
       
window.draw( title );
       
window.draw( game_level );
       
window.draw( easy );
       
window.draw( medium );
       
window.draw( hard );
       
window.draw( username );
       
window.draw( inputName );
       
window.draw( playPrompt );
       
window.display();
       
       
   
}
}


std::string Menu::getPlayerName() const {
   
return playerName;
}

unsigned Menu::getNumObstacles() const {
   
return numObstacles;
}

int Menu::getSnakeSpeed() const {
   
return snakeSpeed;
}

bool Menu::startGame() {
   
return gameStarted;
}
C/C++
SnakeMove:
#include "snake_move.h"
#include "board.h"

void snake_figure::change_figure( snake_blocks & a ) {
   
waz.push_back( a );
}

snake_figure::snake_figure() {
   
for( int i = 0; i < 3; i++ ) {
       
snake_blocks a;
       
a.x = Board::get_size() / 2;
       
a.y = Board::get_size() / 2 - i;
       
change_figure( a );
   
}
}

snake_figure::snake_figure( Board & board ) {
   
for( int i = 0; i < 3; i++ ) {
       
snake_blocks blocks;
       
blocks.x = board.get_size() / 2;
       
blocks.y = board.get_size() / 2 - i;
       
change_figure( blocks );
   
}
}

void snake_figure::change_direction( direction newDirection ) {
   
switch( newDirection ) {
   
case UP:
       
if( kierunek != DOWN )
           
 kierunek = UP;
       
       
break;
   
case DOWN:
       
if( kierunek != UP )
           
 kierunek = DOWN;
       
       
break;
   
case LEFT:
       
if( kierunek != RIGHT )
           
 kierunek = LEFT;
       
       
break;
   
case RIGHT:
       
if( kierunek != LEFT )
           
 kierunek = RIGHT;
       
       
break;
   
}
}

void snake_figure::move() {
   
std::vector < std::pair < int, int >> wspolrzedne;
   
for( auto blocks: waz ) {
       
std::pair < int, int > o = std::make_pair( blocks.x, blocks.y );
       
wspolrzedne.push_back( o );
   
}
   
   
if( get_direction() == UP ) {
       
waz[ 0 ].x -= 1;
   
} else if( get_direction() == DOWN ) {
       
waz[ 0 ].x += 1;
   
} else if( get_direction() == LEFT ) {
       
waz[ 0 ].y -= 1;
   
} else if( get_direction() == RIGHT ) {
       
waz[ 0 ].y += 1;
   
}
   
   
if( waz[ 0 ].x < 0 || waz[ 0 ].x >= Board::get_size() || waz[ 0 ].y < 0 || waz[ 0 ].y >= Board::get_size() ) {
       
collision = true;
   
}
   
   
for( int i = 1; i < waz.size(); i++ ) {
       
waz[ i ].x = wspolrzedne[ i - 1 ].first;
       
waz[ i ].y = wspolrzedne[ i - 1 ].second;
   
}
}

void snake_figure::kolizja() {
   
collision = false;
   
for( int i = 1; i < get_fig_size(); i++ ) {
       
if( get_head().koordy().first == get_coords( i ).first && get_head().koordy().second == get_coords( i ).second ) {
           
collision = true;
           
break;
       
}
    }
}

void snake_figure::turn( turn_direction turn ) {
   
direction currentDirection = get_direction();
   
   
switch( currentDirection ) {
   
case UP:
       
if( turn == CLOCKWISE ) {
           
change_direction( RIGHT );
       
} else {
           
change_direction( LEFT );
       
}
       
break;
   
case RIGHT:
       
if( turn == CLOCKWISE ) {
           
change_direction( DOWN );
       
} else {
           
change_direction( UP );
       
}
       
break;
   
case DOWN:
       
if( turn == CLOCKWISE ) {
           
change_direction( LEFT );
       
} else {
           
change_direction( RIGHT );
       
}
       
break;
   
case LEFT:
       
if( turn == CLOCKWISE ) {
           
change_direction( UP );
       
} else {
           
change_direction( DOWN );
       
}
       
break;
       
default:
       
break;
   
}
}


bool snake_figure::czy_kolizja() {
   
// Check self-collision
   
kolizja();
   
if( collision ) return true;
   
   
// Check wall collision
   
int headX = get_head().koordy().first;
   
int headY = get_head().koordy().second;
   
if( headX < 0 || headX >= Board::get_size() || headY < 0 || headY >= Board::get_size() ) {
       
return true;
       
   
}
   
   
return false;
}
bool snake_figure::get_gamestate() const {
   
return czy_trwa;
}
C/C++
View:
#include "view.h"

sfmlview::sfmlview( snake_figure & snakeFigure, Board & board )
    :
board( board )
   
, fig( snakeFigure )
{
   
if( !appleTexture.loadFromFile( "/home/marta/git/snake/snake_ak_wt15_281312/apple.jpg" ) ) {
       
std::cerr << "Failed to load apple.jpg" << std::endl;
   
} else {
       
appleSprite.setTexture( appleTexture );
       
appleSprite.setScale( static_cast < float >( TILE_SIZE ) / appleTexture.getSize().x, static_cast < float >( TILE_SIZE ) / appleTexture.getSize().y );
   
}
   
   
if( !hammerTexture.loadFromFile( "/home/marta/git/snake/snake_ak_wt15_281312/hammer.png" ) ) {
       
std::cerr << "Failed to load hammer.png" << std::endl;
   
} else {
       
hammerSprite.setTexture( hammerTexture );
       
hammerSprite.setScale( static_cast < float >( TILE_SIZE ) / hammerTexture.getSize().x, static_cast < float >( TILE_SIZE ) / hammerTexture.getSize().y );
   
}
   
   
if( !font.loadFromFile( "/home/marta/git/snake/snake_ak_wt15_281312/Montserrat-Regular.ttf" ) ) {
       
std::cerr << "Failed to load font" << std::endl;
   
} else {
       
gameOverText.setFont( font );
       
gameOverText.setString( "Game Over!" );
       
gameOverText.setCharacterSize( 50 );
       
gameOverText.setFillColor( sf::Color::Red );
       
gameOverText.setPosition( 150, 300 );
       
scoreText.setFont( font );
       
scoreText.setCharacterSize( 30 );
       
scoreText.setFillColor( sf::Color::Red );
       
scoreText.setPosition( 150, 250 );
   
}
}

void sfmlview::draw( sf::RenderWindow & win, Board & board, snake_figure & figura ) {
   
for( int i = 0; i < board.get_size(); i++ ) {
       
for( int j = 0; j < board.get_size(); j++ ) {
           
if( board.get_field( i, j ).has_snake ) {
               
sf::RectangleShape s( sf::Vector2f( TILE_SIZE, TILE_SIZE ) );
               
s.setFillColor( sf::Color::Green );
               
s.setPosition( TILE_SIZE * j, TILE_SIZE * i );
               
win.draw( s );
           
}
           
if( board.get_field( i, j ).has_apple ) {
               
appleSprite.setPosition( TILE_SIZE * j, TILE_SIZE * i );
               
win.draw( appleSprite );
           
}
           
if( board.get_field( i, j ).has_obstacle ) {
               
hammerSprite.setPosition( TILE_SIZE * j, TILE_SIZE * i );
               
win.draw( hammerSprite );
           
}
        }
    }
   
   
if( !figura.get_gamestate() ) {
       
win.draw( gameOverText );
       
       
scoreText.setString( "Score: " + std::to_string( figura.get_score() ) );
       
win.draw( scoreText );
   
}
}
P-181243
pekfos
» 2024-06-17 16:35:01
Nie ma definicji klas, ale wyraźnie czy_trwa jest polem klasy GameManager, więc to co czytasz w snake_figure::get_gamestate() wygląda jak niezainicjalizowana zmienna.
C/C++
bool snake_figure::get_gamestate() const {
   
return czy_trwa;
}

P-181244
phalange
Temat założony przez niniejszego użytkownika
» 2024-06-17 16:42:35
Faktycznie powinno to być w controllerze, ale na chwilę obecną to jest zaincijalizowane w snake_figure. Czy mimo że jest w innym pliku nie powinno to działać?
C/C++
#ifndef SNAKE_MOVE_H
#define SNAKE_MOVE_H

#include <iostream>
#include <vector>
#include <utility>
#include "common.h"
#include "board.h"


/// Pojedynczy blok węża
struct snake_blocks {
   
/// Współrzędne bloku
   
int x, y;
   
/// \return współrzędne bloczku węża jako  parę
   
std::pair < int, int > koordy() { return std::make_pair( x, y ); }
}
;


class snake_figure {
   
/// Licznik zebranych jabłek
   
int apple_count = 0;
protected:
   
/// Wektor bloków węża
   
std::vector < snake_blocks > waz;
   
/// Kierunek poruszania się węża
   
direction kierunek = RIGHT;
   
/// Flaga kolizji węża z samym sobą
   
bool collision = false;
   
bool czy_trwa = true;
   
public:
   
   
snake_figure();
   
/// Konstruktor inicjujący węża na planszy
   
snake_figure( Board & );
   
   
/// \return rozmiar węża
   
int get_fig_size() { return waz.size(); }
   
   
/// \param a
    /// \return współrzędne bloku węża o danym indeksie
   
std::pair < int, int > get_coords( int a ) { return waz[ a ].koordy(); }
   
   
/// \return aktualny kierunek poruszania się węża
   
direction get_direction() { return kierunek; }
   
   
/// Metoda zmieniająca kierunek poruszania się węża
    /// \param newDirection
   
void change_direction( direction newDirection );
   
   
/// Funkcja sterującą obrotem węża zgodnie z ruchem wskazówek zegara lub odwrotnie
    /// \param turn
   
void turn( turn_direction turn );
   
   
/// Metoda wykonująca ruch węża, sprawdza czy jeszcze jest na planszy i aktualizaująca położenie bloczkóœ węża
   
void move();
   
   
/// Metoda zmieniająca figurę węża
   
void change_figure( snake_blocks & );
   
   
/// \return współrzędne ostatniego bloku węża
   
snake_blocks get_last_coords() { return waz[ waz.size() - 1 ]; }
   
   
/// \return współrzędne głowy węża
   
snake_blocks get_head() { return waz[ 0 ]; }
   
   
/// Metoda sprawdzająca kolizję węża z samym sobą
   
void kolizja();
   
   
/// sprawdza, czy wąż miał kolizję ze swoim ciałem
    /// \return true jeśli miał kolizję, false jesli nie miał
   
bool czy_kolizja();
   
   
/// Metoda dodająca punkty za zebrane jabłka
   
void add_score() { apple_count += 100; }
   
   
/// \return aktualny wynik w grze
   
int get_score() { return apple_count; }
   
   
/// Stan gry
    /// \return czy_trwa
   
bool get_gamestate() const;
   
};

#endif  // SNAKE_MOVE_H
P-181245
pekfos
» 2024-06-17 17:12:00
To jest nie tylko w innym pliku, ale w zupełnie innej klasie. To są niezwiązane ze sobą zmienne.
P-181246
« 1 »
  Strona 1 z 1