Szukaj na tym blogu

czwartek, 17 grudnia 2009

Implementacja mapy kafelkowej

                            Dziś z racji tego że ostatnio paru znajomych pytało mnie o to jak stworzyć mapę do gry (wiem że proste, ale początkującym może się przydać) przedstawię moją implementację popularnego kafelkowego systemu mapy. Zapewne już było takowych kilka tutoriali, ale podobno większa liczba nie zaszkodzi ;)

A więc zaczynamy od stworzenia enuma który będzie posiadał info o rodzajach kafli:

enum KAFLE {TRAWA, KAMIEN, WODA, etc, etc ... };

Następnie tworzymy tablicę naszego nowego typu:

KAFLE mapa[x][y] = {{WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA,  KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}
                                    {WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}, {WODA, WODA, TRAWA, KAMIEN, TRAWA}
                                     etc, etc};


Teraz potrzebujemy jakichś powierzchni po których będziemy rysować (np. w allegro odpowiednie Bitmapy, albo SDL_SURFACE w SDL'u).

I jak już będziemy mieli takową powierzchnię, a właściwie potrzebujemy ich dwóch (jedna to grafika kafli, a druga dla mapy kolizji) to musimy odpowiednio wyrysować:

for(int i = 0; i<(szerokosc_planszy/szerokość_kafla); i++)
      {
       for(int j = 0; j<(wysokosc_planszy/wysokosc_kafla); j++)
            {                                                                     
               if(map[i][j] == TRAWA)draw(target_grafic_surface, grass, i*szerokosc_kafla,               j*wysokosc_kafla, grass->w, grass->h);
              if(map[i][j] == KAMIEN)draw(target_grafic_surface, stone, i*szerokosc_kafla, j*wysokosc_kafla, stone->w, stone->h);
              if(map[i][j] == WODA)draw(target_grafic_surface, water, i*szerokosc_kafla, j*wysokosc_kafla, water->w, water->h);
              }
       }


Ten kod ma za zadanie narysować graficzną część mapy, przydałoby się jeszcze dorobić fragment odpowiedzialny za kolizje.Nie jest to skomplikowane, jak zresztą cały ten krótki tutek, acz postaram się to w miarę zrozumiale opisać. Musimy mieć kolejną powierzchnię, która będzie reprezentować mapę kolizji. Nazwę ją target_col_surface. A więc, mam nadzieję że przykład będzie zrozumiały. Załóżmy że chcemy narysować mapę kolizji tylko dla kamienia dla skrócenia kodu. Dla innych rodzaji kafli działa to oczywiście analogicznie.


for(int i = 0; i<(szerokosc_planszy/szerokość_kafla); i++)
      {
       for(int j = 0; j<(wysokosc_planszy/wysokosc_kafla); j++)
            {                                                                     
               if(map[i][j] == TRAWA)draw(target_grafic_surface, grass, i*szerokosc_kafla,               j*wysokosc_kafla, grass->w, grass->h);
              if(map[i][j] == KAMIEN)
{
draw(target_grafic_surface, stone, i*szerokosc_kafla, j*wysokosc_kafla, stone->w, stone->h);
draw(target_col_surface, stone_mask, i*szerokosc_kafla, j*wysokosc_kafla, stone_mask->w, stone_mask->h);
}
              if(map[i][j] == WODA)draw(target_grafic_surface, water, i*szerokosc_kafla, j*wysokosc_kafla, water->w, water->h);
              }
       }


Kod wyszczególniony na czerwono powoduje narysowanie na powierzchni będącej mapą kolizji maski kamienia, czyli wypełnionego jednolitym kolorem, który posłuży do implementacji kolizji per pixel  odwzorowania konturów naszej bitmapy kamienia. Omówieniem kolizji zajmę się za moment.

Okej, mamy już kod rysujący mapę z tablicy, oczywiście aby było to widoczne na ekranie, musimy co każdy obrót pętli głównej kopiować zawartość powierzchni target_grafic_surface na ekran. Teraz przejdziemy do omówienia implementacji kolizji, na podstawie wygenerowanej przed chwilą mapy kolizji. Po raz kolejny uprzedzę, że użyte tu nazwy funkcji są wymyślone przeze mnie i prawdopodobnie nie mają one takich nazw ani dokładnie takich parametrów jak tutaj pokazuję. Ewentualne podobieństwo można zauważyć do biblioteki Allegro, którą się zazwyczaj posługuję w tworzeniu gier 2D. W tym podpunkcie będę korzystał z funkcji pobierających wartość pixela o podanych współrzędnych, która także jest inna w zależności od biblioteki. A więc nie zwlekając biorę się za wyjaśnienia.

Najpierw trochę kodu:

//Jakiś tam plik nagłówkowy
bool Kolizja(SURFACE col_map, pos_x, pos_y)  //col_map - powierzchnia mapy kolizji, pos_x, pos_y - //                                                                              współrzędne gracza.
{
COLOR color_pix;                                       //Zmienna przechowująca wartość koloru
 color_pix = getpixelred(pos_x, pos_y);        //pobranie wartości koloru z pixela pos_x, pos_y
if(color_pix == color_col_map)return true;   //jeżeli pobrany kolor = kolor mapy kolizji return true;
else return false;                                          
}

//plik main.cpp zazwyczaj
while(GAME = =TRUE)  //main loop gry
{
 int pos_x, pos_y, pos_x_old, pos_y_old;

pos_x_old = pos_x;
pos_y_old = pos_y;

draw_map();        //rysujemy mapę i mapę kolizji;

RuchPostacia();Funkcja zmieniająca wartość pos_x i pos_y w odpowiedzi na klawisze, czyli ruch postaci.
if(Kolizja == true){pos_x = pos_x_old; pos_y = pos_y_old;}

DrawPlayer(pos_x, pos_y);
}


I oto mamy kod obsługujący już całość rysowania planszy, oraz kolizji. Nic tylko pisać ogromy świat i super grę ;) 

Jak znajdę chwilę to dołączę  program przykładowy wraz z kodem.

Brak komentarzy:

Prześlij komentarz