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

[SFML]Snake - szybkie wciśnięcie klawiszy psuje ruch

Ostatnio zmodyfikowano 2015-07-17 13:31
Autor Wiadomość
bingo009
Temat założony przez niniejszego użytkownika
[SFML]Snake - szybkie wciśnięcie klawiszy psuje ruch
» 2015-07-17 00:20:40
Witam was serdecznie, piszę klasycznego Snake w C++ i jest już niemalże ukończony, ale nie daje mi żyć pewna błachostka. Mianowicie, snake porusza się w kierunku, na który wskazuje enum. Sam Snake jest klasą. Wciśnięcie np. strzałki w dół wywołuje metodę z argumentem typu enum, a metoda ta zamienia kierunek, z tym, że nie zmienia kierunku na przeciwny, czyli jak Snake porusza się w górę, to metoda nie zmieni kierunku jego poruszania w dół. Problem polega na tym, że jak np. Snake porusza się do góry, a ja szybko wcisnę strzałkę w prawo lub w lewo, a potem szybko strzałkę w dół, to Snake zmienia kierunek na przeciwny i tym samym jest Game Over, bo wpada na swoje ciało. Dość mocno utrudnia to gwałtowne manewry, więc szukam rozwiązania tego problemu. Przeniosłem sprawdzanie wejścia do osobnej metody, oraz po każdej zmianie kierunku dałem return, żeby nie sprawdzało innych klawiszy, dzięki czemu sprawdzanie odbywa się podczas jednego obiegu pętli(w każdym obiegu jest też poruszanie się węża, więc teoretycznie powinienem mieć pewność, że Snake poruszy się, zanim znowu zmienię kierunek), jednak nic to nie dało. Wrzucam kod metod, może ktoś się dopatrzy błędu:
C/C++
void CSnake::setDirection( CSnake::DIRECTION dir )
{
    if( direction == UP && dir == DOWN )
         return;
   
    if( direction == DOWN && dir == UP )
         return;
   
    if( direction == LEFT && dir == RIGHT )
         return;
   
    if( direction == RIGHT && dir == LEFT )
         return;
   
    direction = dir;
}

C/C++
void CGame::CheckInput()
{
    if( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) ) {
        snake.setDirection( CSnake::UP );
        return;
    }
   
    if( sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) ) {
        snake.setDirection( CSnake::DOWN );
        return;
    }
   
    if( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) ) {
        snake.setDirection( CSnake::LEFT );
        return;
    }
   
    if( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) ) {
        snake.setDirection( CSnake::RIGHT );
        return;
    }
   
    if( sf::Keyboard::isKeyPressed( sf::Keyboard::Escape ) ) {
        game_state = GAME_MENU;
        return;
    }
   
    if( sf::Keyboard::isKeyPressed( sf::Keyboard::P ) ) {
        game_state = GAME_PAUSED;
        return;
    }
}

Wrzucam też część kodu z głównej pętli:
C/C++
CheckInput();

if( snake.getHeadX() == apple.getFoodX() && snake.getHeadY() == apple.getFoodY() ) {
    apple.makeFood();
    snake.addBody();
}

time = clock.restart();
TimeFromActualisation += time;

while( TimeFromActualisation > TimeStep ) {
   
    if( !snake.moveSnake() )
         game_state = GAME_OVER;
   
    TimeFromActualisation -= TimeStep;
}
P-134803
Quirinnos
» 2015-07-17 01:22:15
1)Jeżeli przekazany kierunek to UP i aktualny kierunek != od DOWN, aktualizuj kierunek.
itp

PS. A tak po za tym, wiesz że istnieje konstrukcja
if else
? :D
P-134804
1aam2am1
» 2015-07-17 01:34:44
Możesz dodać boola ustaw go na jeden przy obiegu fizyki.
Ustaw na zero przy zmianie kierunku.
Jeżeli jest równy zero nie mozesz zmienić kierunku.
Zagwarantuje ci to że się poruszy przynajmniej o jedną kratkę przed następną zmiana kierunku.
P-134806
bingo009
Temat założony przez niniejszego użytkownika
» 2015-07-17 02:03:32
@1aam2am1
W tym kodzie, który wysłałem też mam zagwarantowane, że poruszy się przed wykonaniem kolejnego kierunku metoda po wykonaniu zmiany się kończy i jest wywoływana raz na obieg pętli przed poruszaniem węża. Ale spróbowałem twojego sposobu i nic on nie pomógł.

@Quirinnos Zgodnie z tym co napisałeś zmodyfikowałem metodę, która teraz prezentuje się tak:
C/C++
void CSnake::setDirection( CSnake::DIRECTION dir )
{
    if( direction == UP && dir == DOWN )
         return;
   
    if( direction == DOWN && dir == UP )
         return;
   
    if( direction == LEFT && dir == RIGHT )
         return;
   
    if( direction == RIGHT && dir == LEFT )
         return;
   
    if( dir == UP && direction != DOWN )
         direction = dir;
   
    if( dir == DOWN && direction != UP )
         direction = dir;
   
    if( dir == LEFT && direction != RIGHT )
         direction = dir;
   
    if( dir == RIGHT && direction != LEFT )
         direction = dir;
   
}

Oczywiście bez zmian. A co do if else, to wiem, że istnieje, nawet próbowałem tego użyć, ale nie pomogło, więc szukałem innych sposobów.

Nie mam pomysłu czemu to może nie działać, przecież metoda jest wywoływana raz na obieg pętli, przed rysowaniem Snake'a, więc mam pewność, że po jednokrotnej zmianie kierunku wąż się poruszy? Może to problem w metodzie poruszania, ale tam nie ma nic, co mogłoby zawieść - zwykły std::vector przechowujący klasę, zawierająca współrzędne punktu w przestrzeni 2D, poprostu głowa węża(zerowy element) się porusza w wybranym kierunku, a każdy następny "człon" wskakuje na miejsce poprzedniego. Nie myślałem, że taka prosta gra może mi sprawić problem, nad którym będę się głowił dłuższy czas. Teraz chyba pójdę się przespać, może coś się przyśni.
P-134808
Quirinnos
» 2015-07-17 02:29:54
zrób w metodzie od input'ów
C/C++
if( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) && aktualny_kierunek != CSnake::DOWN )
{
    aktualny_kierunek = CSnake::UP;
}
else if //... analogicznie
}
P-134809
michal11
» 2015-07-17 11:37:27
A to nie lepiej już skorzystać ze switcha ?
Debuguj, może to coś pomoże.
P-134814
bingo009
Temat założony przez niniejszego użytkownika
» 2015-07-17 13:14:00
Niestety, to też nic nie dało. Ja już nie wiem, o co to może chodzić. michal11, skoro sposób z funkcją, boolem i if_else nic nie dał, to switch tym bardziej nic mi nie pomoże.

Edit: Chyba mam całkiem sensowną teorię. Ruch węża jest w pętli stałokrokowej, może poprostu pętla ta się wcale nie uruchamia? Aktualizacja pozycji węża jest robiona około 2 razy na sekundę, może poprostu pętla główna wykonuje się tak szybko, że stałokrokowa wcale się nie uruchamia, bo nie minął jeszcze odpowiedni czas?
P-134821
michal11
» 2015-07-17 13:19:58
Akurat switch nie był na naprawę błędu tylko na ładniejszy, czytelniejszy kod (chociaż mógłby pomóc).
P-134823
« 1 » 2
  Strona 1 z 2 Następna strona