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

[C++] Problem przy tworzeniu mapy w grze Snake

Ostatnio zmodyfikowano 2013-05-24 15:42
Autor Wiadomość
XardassLord
Temat założony przez niniejszego użytkownika
[C++] Problem przy tworzeniu mapy w grze Snake
» 2013-05-20 23:10:32
Witam,
 
Zaznaczę na początku iż dopiero jakoś od ponad miesiąca przyłożyłem się do nauki c++. Wcześniej na pierwszym roku studiów uczyliśmy się C, potem javy, więc nie jestem w tym temacie aż taki zielony. Programowanie mnie interesuje, dlatego chcę rozwijać swoje zainteresowania i kształcić się w tym kierunku.
 
Zakupiłem do tego celu książkę Jerzego Grębosza - Symfonia C++ standard. Uczę się z niej na bieżąco, razem z przykładami i próbuję pisać swoje własne programy, które przyjdą mi do głowy. Jestem osobą, która lubi uczyć się na własnych błędach, lecz problemu z którym próbuję się uporać nie mogę rozwikłać.
 
Domyślam się, że przyczyna tego jest banalna, lecz na dzień dzisiejszy nie mogę pojąć dlaczego... Dlatego mam nadzieję, że mi pomożecie i wyjaśnicie dlaczego to jest źle.


Problem, a dokładniej rzecz mówiąc, bardziej taka ciekawostka, której nie mogę zrozumieć pojawia się podczas rysowania mapy (a dokładniej głowy węża). Ale o tym bliżej za chwilę.

Moja mapa jest tablicą dwuwymiarową obiektów typu char.

Posiadam dwie funkcje, jedna która rysuje mapę (tj. obramowanie i ustawia każdy z elementów tej tablicy jako znak ASCII o kodzie 255 (czyli spacja). Oraz druga, która powinna rysować głowę węża o podanych wartościach tej tablicy. Lecz niestety nie rysuje. Natomiast, gdy rysowanie węża uwzględnie w funkcji, która rysuje mapę to głowa węża zostaje na tej mapie narysowana.

Dlaczego tak się dzieje? I dlaczego głowa węża nie chce się narysować za pomocą oddzielnej funkcji?

Byłbym niezmiernie wdzięczny, gdyby ktoś mógł mi tę sytuację wytłumaczyć :)

Oto kod programu:

C/C++
#include <iostream>
#include <conio.h>
#include <cstdlib>

using namespace std;

void rysuj_mape( char mapa[ 20 ][ 60 ] );
void wstaw_weza( char mapa[ 20 ][ 60 ] );

int main()
{
    char mapa[ 20 ][ 60 ];
   
    rysuj_mape( mapa );
    wstaw_weza( mapa );
   
    getch();
    return 0;
}

//FUNKCJA RYSUJĄCA MAPĘ DO GRY
void rysuj_mape( char mapa[ 20 ][ 60 ] )
{
    cout << " ------------------------------------------------------------" << endl;
   
    for( int i = 0; i < 20; i++ )
    {
        cout << "|"; // ramka od lewej strony
       
        for( int j = 0; j < 60; j++ )
        {
            mapa[ i ][ j ] = 255;
            cout << mapa[ i ][ j ];
        }
        cout << "|"; // ramka od prawej strony
        cout << endl;
    }
   
    cout << " ------------------------------------------------------------" << endl;
}

//FUNKCJA USTAWIAJĄCA WĘŻA NA MAPIE
void wstaw_weza( char mapa[ 20 ][ 60 ] )
{
    mapa[ 10 ][ 30 ] = 'O'; // wstawienie węża do gry
}
P-83461
f651144
» 2013-05-21 08:59:46
1. Nie wiem z dlaczego spacja u Ciebie to 255. Odsyłam do: Wikipedia, artykuł o ASCII.
Spacja to 32 (0x20), więc Twój kod powinie wyglądać mniej więcej tak:
C/C++
for( int j = 0; j < 60; j++ )
{
    mapa[ i ][ j ] =( char ) 32; // Jawne rzutowanie, żeby było wyraźnie widać :P
    cout << mapa[ i ][ j ];
}

2. Twój problem wynika z tego, że NAJPIERW rysujesz mapę, a PÓŹNIEJ wstawiasz węża. Jeśli tylko zmienisz kolejność będzie problem z rysowaniem. Możesz dodać funkcje czyszczącą tablice i lekko zmodyfikować funkcje rysuj_mape. Będzie to wyglądało jakoś tak:
C/C++
#include <iostream>
#include <conio.h>
#include <cstdlib>

using namespace std;

void zeruj_mape( char mapa[ 20 ][ 60 ] );
void wstaw_weza( char mapa[ 20 ][ 60 ] );
void rysuj_mape( char mapa[ 20 ][ 60 ] );

int main()
{
    char mapa[ 20 ][ 60 ];
   
    zeruj_mape( mapa );
    wstaw_weza( mapa );
    rysuj_mape( mapa );
   
    getch();
    return 0;
}

//FUNKCJA ZERUJĄCA MAPĘ DO GRY
void zeruj_mape( char mapa[ 20 ][ 60 ] )
{
    for( int i = 0; i < 20; i++ )
    for( int j = 0; j < 60; j++ )
         mapa[ i ][ j ] =( char ) 0;
   
}

//FUNKCJA RYSUJĄCA MAPĘ DO GRY
void rysuj_mape( char mapa[ 20 ][ 60 ] )
{
    cout << " ------------------------------------------------------------" << endl;
   
    for( int i = 0; i < 20; i++ )
    {
        cout << "|"; // ramka od lewej strony
       
        for( int j = 0; j < 60; j++ )
        {
            if( mapa[ i ][ j ] != 'O' ) // Jeżeli to nie wąż, to wstaw spacje
                 mapa[ i ][ j ] =( char ) 32;
           
            cout << mapa[ i ][ j ];
        }
        cout << "|"; // ramka od prawej strony
        cout << endl;
    }
   
    cout << " ------------------------------------------------------------" << endl;
}

//FUNKCJA USTAWIAJĄCA WĘŻA NA MAPIE
void wstaw_weza( char mapa[ 20 ][ 60 ] )
{
    mapa[ 10 ][ 30 ] = 'O'; // wstawienie węża do gry
}
P-83479
XardassLord
Temat założony przez niniejszego użytkownika
» 2013-05-21 11:24:10
Rzeczywiście, można to rozwiązać w taki sposób. Dzięki bardzo za odpowiedź.
Lecz teraz kwestia taka, gdybym chciał dodać jabłko do mapy ( odpowiadałaby za to funkcja losująca dwie liczby, które wstawiłbym jako elementy tablicy, czyli przykładowo mapa[y][x]) to sytuacja wyglądałaby podobnie jak ze wstawieniem węża do mapy...

Po prostu po narysowaniu mapy, nie mógłbym tak jak to było wcześniej z głową węża - narysować jej. A przecież funkcja losująca mapę będzie co jakiś czas musiała losować te liczby i wstawiać w dane miejsce w tablicy jabłko. Czy w takim razie w funkcji tej będę musiał jeszcze raz uwzględnić rysowanie mapy i tam wtedy podać, że pierw zeruje tablice, potem dodaje węża i jabłko i następnie całą resztę tablicy wypełnia spacjami?

EDIT: Okej ogarnąłem troche ten kod i już wiem o co chodzi w tym wszystkim.

Zmodyfikowałem nieco funkcję rysuj_mape, uwzględniając w niej pozycję węża. Napisałem również pozostałe funkcje, tj. poruszanie węża, oraz sprawdzanie czy wąż nie uderzył w ścianę (czy nie jest przekroczony zakres tablicy).

Poniżej przesyłam kod i chciałbym, abyście mi podpowiedzieli w jaki sposób mógłbym ten kod zoptymalizować, by był nieco krótszy i prostrzy. Jestem w tej dziedzinie słaby, także chętnie wysłucham wszystkich Waszych porad :) Wiem też, że używałem tam często polecenia na czyszczenie ekranu (system("cls")) i wiem też, że na pewno można co zrobić inaczej, lepiej.

C/C++
#include <iostream>
#include <conio.h>
#include <cstdlib>

using namespace std;

void zeruj_mape( char mapa[ 20 ][ 60 ] );
void rysuj_mape( char mapa[ 20 ][ 60 ] );
void wstaw_weza( char mapa[ 20 ][ 60 ], int & x, int & y );
void ruch( char mapa[ 20 ][ 60 ], int & x, int & y );
bool koniec( char mapa[ 20 ][ 60 ], int & x, int & y );

int main()
{
    char mapa[ 20 ][ 60 ];
    int x = 30; // współrzędna na osi X, czyli [j]. Przypisane są tylko początkowe wartości
    int y = 10; // współrzędna na osi Y, czyli [i]
    do
    {
        system( "cls" );
        zeruj_mape( mapa );
        wstaw_weza( mapa, x, y );
        rysuj_mape( mapa );
        ruch( mapa, x, y );
        koniec( mapa, x, y );
       
    } while( !koniec( mapa, x, y ) );
   
    getch();
    return 0;
}

// FUNKCJA ZERUJĄCA MAPĘ DO GRY
void zeruj_mape( char mapa[ 20 ][ 60 ] )
{
    for( int i = 0; i < 20; i++ )
    for( int j = 0; j < 60; j++ )
         mapa[ i ][ j ] = 0;
   
}

// FUNKCJA RYSUJĄCA MAPĘ DO GRY
void rysuj_mape( char mapa[ 20 ][ 60 ] )
{
    cout << " ------------------------------------------------------------" << endl;
   
    for( int i = 0; i < 20; i++ )
    {
        cout << "|"; // ramka od lewej strony
       
        for( int j = 0; j < 60; j++ )
        {
            if( mapa[ i ][ j ] != 'O' )
                 mapa[ i ][ j ] = 32;
           
            cout << mapa[ i ][ j ];
        }
        cout << "|"; // ramka od prawej strony
        cout << endl;
    }
   
    cout << " ------------------------------------------------------------" << endl;
}

// FUNKCJA USTAWIAJĄCA WĘŻA NA MAPIE
void wstaw_weza( char mapa[ 20 ][ 60 ], int & x, int & y )
{
    mapa[ y ][ x ] = 'O'; // wstawienie węża do gry
}

// FUNKCJA PORUSZAJĄCA WĘŻA PO MAPIE
void ruch( char mapa[ 20 ][ 60 ], int & x, int & y )
{
    char ruch = getch();
   
    if( ruch == 'w' )
    {
        y--;
        system( "cls" );
        zeruj_mape( mapa );
        wstaw_weza( mapa, x, y );
        rysuj_mape( mapa );
       
    }
   
    if( ruch == 's' )
    {
        y++;
        system( "cls" );
        zeruj_mape( mapa );
        wstaw_weza( mapa, x, y );
        rysuj_mape( mapa );
       
    }
   
    if( ruch == 'a' )
    {
        x--;
        system( "cls" );
        zeruj_mape( mapa );
        wstaw_weza( mapa, x, y );
        rysuj_mape( mapa );
       
    }
   
    if( ruch == 'd' )
    {
        x++;
        system( "cls" );
        zeruj_mape( mapa );
        wstaw_weza( mapa, x, y );
        rysuj_mape( mapa );
       
    }
}

// FUNKCJA SPRAWDZAJĄCA CZY WĄŻ UDERZYŁ W ŚCIANĘ
bool koniec( char mapa[ 20 ][ 60 ], int & x, int & y )
{
    bool test = false;
   
    if( x < 0 || x > 59 )
    {
        test = true;
        system( "cls" );
        cout << "\n\n KONIEC GRY!";
        return test;
    }
   
    if( y < 0 || y > 19 )
    {
        test = true;
        system( "cls" );
        cout << "\n\n KONIEC GRY!";
        return test;
    }
   
    return test;
}
P-83486
pekfos
» 2013-05-21 19:02:25
1. Nie wiem z dlaczego spacja u Ciebie to 255.
A u Ciebie nie (o ile masz extended ASCII)?
P-83535
XardassLord
Temat założony przez niniejszego użytkownika
» 2013-05-21 22:05:33
Program udało mi się skrócić do takiej postaci jak w kodzie poniżej. Dodałem dodatkowo funkcję losującą i wstawiającą na mapę jabłka :)

C/C++
#include <iostream>
#include <conio.h>
#include <cstdlib>
#include <ctime>


using namespace std;


void zeruj_mape( char mapa[ 20 ][ 60 ] );
void rysuj_mape( char mapa[ 20 ][ 60 ] );
void wstaw_weza( char mapa[ 20 ][ 60 ], int & x, int & y );
void ruch( char mapa[ 20 ][ 60 ], int & x, int & y );
bool koniec( char mapa[ 20 ][ 60 ], int & x, int & y );
void losuj_jablko( char mapa[ 20 ][ 60 ], int & x, int & y, int & jx, int & jy );



int main()
{
    srand( time( NULL ) );
   
    char mapa[ 20 ][ 60 ];
    int x = 30; // współrzędna na osi X, czyli [j]. Przypisane są tylko początkowe wartości
    int y = 10; // współrzędna na osi Y, czyli [i]
    int jx = rand() % 59; // współrzędne pierwszego jabłka
    int jy = rand() % 19; // ------------||---------------
   
   
   
   
    do
    {
        system( "cls" );
        zeruj_mape( mapa );
        wstaw_weza( mapa, x, y );
        losuj_jablko( mapa, x, y, jx, jy );
        rysuj_mape( mapa );
        ruch( mapa, x, y );
        koniec( mapa, x, y );
       
    } while( !koniec( mapa, x, y ) );
   
   
   
   
    getch();
    return 0;
}






//////////////////// FUNKCJA ZERUJĄCA MAPĘ DO GRY ////////////////////
void zeruj_mape( char mapa[ 20 ][ 60 ] )
{
    for( int i = 0; i < 20; i++ )
    for( int j = 0; j < 60; j++ )
         mapa[ i ][ j ] = 0;
   
}







//////////////////// FUNKCJA RYSUJĄCA MAPĘ DO GRY ////////////////////
void rysuj_mape( char mapa[ 20 ][ 60 ] )
{
    cout << " ------------------------------------------------------------" << endl;
   
    for( int i = 0; i < 20; i++ )
    {
        cout << "|"; // ramka od lewej strony
       
        for( int j = 0; j < 60; j++ )
        {
            if( mapa[ i ][ j ] == 0 )
                 mapa[ i ][ j ] = 32;
           
            cout << mapa[ i ][ j ];
        }
        cout << "|"; // ramka od prawej strony
        cout << endl;
    }
   
    cout << " ------------------------------------------------------------" << endl;
}







//////////////////// FUNKCJA USTAWIAJĄCA WĘŻA NA MAPIE ////////////////////
void wstaw_weza( char mapa[ 20 ][ 60 ], int & x, int & y )
{
    mapa[ y ][ x ] = 'O'; // wstawienie węża do gry
}








//////////////////// FUNKCJA PORUSZAJĄCA WĘŻA PO MAPIE ////////////////////
void ruch( char mapa[ 20 ][ 60 ], int & x, int & y )
{
    char ruch = getch();
   
    if( ruch == 'w' )
         y--;
   
   
    if( ruch == 's' )
         y++;
   
   
    if( ruch == 'a' )
         x--;
   
   
    if( ruch == 'd' )
         x++;
   
}





//////////////////// FUNKCJA SPRAWDZAJĄCA CZY WĄŻ UDERZYŁ W ŚCIANĘ ////////////////////
bool koniec( char mapa[ 20 ][ 60 ], int & x, int & y )
{
    bool test = false;
   
    if( x < 0 || x > 59 )
    {
        test = true;
        system( "cls" );
        cout << "\n\n KONIEC GRY!";
        return test;
    }
   
    if( y < 0 || y > 19 )
    {
        test = true;
        system( "cls" );
        cout << "\n\n KONIEC GRY!";
        return test;
    }
   
    return test;
   
}







//////////////////// FUNKCJA LOSUJĄCA JABŁKO NA MAPIE ////////////////////
void losuj_jablko( char mapa[ 20 ][ 60 ], int & x, int & y, int & jx, int & jy )
{
    if( x == jx && y == jy )
    {
        jx = rand() % 59;
        jy = rand() % 19;
    }
   
    mapa[ jy ][ jx ] = '*';
}


Jest jeszcze jeden problem, ponieważ teraz snake jest praktycznie o zerowym poziomie trudności. Chciałbym dodać, aby wraz z czasem snake się sam poruszał w ostatnim wybranym kierunku, lecz nie mam pojęcia jak taki efekt uzyskać.

 

Może miałby ktoś jakieś porady ? :)
P-83561
pekfos
» 2013-05-22 14:58:51
Nie zatrzymuj programu na wczytywaniu.
P-83595
XardassLord
Temat założony przez niniejszego użytkownika
» 2013-05-22 22:51:05
Jeśli chodzi o zatrzymywanie programu przy ruchu to wiem, że te zatrzymanie ogarnicza funkcja getch. Lecz nie wiem, bo nie znam innej, którą mógłbym ją zastąpić ;/
P-83642
pekfos
» 2013-05-23 15:48:30
kbhit() z conio.h sprawdza, czy getch() ma co pobrać (i tym samym, czy nie zatrzyma programu).
P-83704
« 1 » 2
  Strona 1 z 2 Następna strona