Forum dyskusyjne  |  Kanał IRC | Użytkownicy | Hosting
Wędrowanie w świecie 2D - część 6
załącznik
2006-06-14 14:55:01, wyświetleń: 3819 [ edycja ] | [ historia ]


WĘDROWANIE W ŚWIECIE 2D (część 6)

MAPA ŚWIATA 2D

1406153923Image18.gif

Ponownie witam wszystkich sympatyków OMEGI, ortodoksyjnych DELPHI-arzy jaki i tych co mają uraz do C. Czyli swoistego tłumaczenia wielu rozwiązań zapisanych w C na Pascala...

O czym będzie mowa w tej części?

Ano... o bardzo prostym pomyśle utworzenia pomniejszonego widoku świat 2D tak jak jest to widoczne na powyższym rysunku. Na mapie widoczny jest:

  1. świat 2D (bardzo odkrywcze :)
  2. żółty punkt odpowiadający położeniu gracza (związany jest z ruchem gracza)
  3. biały prostokąt odpowiadający obszarowi widocznej części świata (związany jest z ruchem żółtego punktu)
  4. czerwony prostokąt rysowany wokół punktu wskazanego lewym przyciskiem mychy (prawy go niszczy)

Cały kod omawiane klasy mapy(nie licząc deklaracji jej typu) zajmuje około 40 linijek i jest zapisany w pliku: OmegaMap.pas. Podaną klasę można oczywiście sobie rozbudować lub przerobić ją w komponent...

Uwagi związane z tworzeniem widoków mapy

Nasza mapa będzie potomkiem klasy TOmegaSurface. Oczywiści można to sobie zrobić przy pomocy wyświetlania rysunku bezpośrednio z OmegaImageList lub w inny sposób. Ja wybrałem takie rozwiązanie bo:

  • tworząc odrębną klasę ma się większy porządek w głównym kodzie programu
  • wprowadzenie ewentualnych poprawek odbywa się w pliku klasy a nie w głównym kodzie
  • można łatwo utworzyć kilka potomków (pamiętajcie grozi nam niż demograficzny...)


Ponadto mapę wyświetlam w całości. Oczywiście wcześniej trzeba sobie ją jakimś innym własnym programikiem utworzyć, przeskalować i zapisać do pliku. Chyba ze ktoś się uprze i w czasie rzeczywistym będzie rysować kolejno kafle świata 2D w odpowiednim pomniejszeniu. Ale należ pamiętać, że trzeba to zrobić co najmniej dla 2 warstw. Z prostego rachunku wnika, że będzie tego znaczna ilość. Przykład świat ma rozmiar 125x75 co dla dwóch warstw da 2x125x75=18750 operacji skalowania i 18750 operacji rysowania kafli. Chyba, że przeskalujemy sobie kafle wcześniej i załadujemy je do OmegImageLis to zostanie nam tylko 18750 operacji rysowania....Tak czy siak zawsze to pochłonie trochę czasu.

Nasza klas będzie sobie gotową mapkę pobierać z zasobu

1406153928Image19.gif

Co zyskujemy z takiego rozwiązania?

Możemy bardzo szybko zmieniać mapę świata poprzez zmianę indeksu wycinanej klatki lub zmianę indeksu całego obrazu mapy. Kiedy tak zmiana może wystąpić? W tedy gdy przechodzimy do innego poziomu gry lub na przykład w obrębie jednego poziomu istnieje kilka równoległych światów. Moje obrazy map świata 2D zgadzają się tylko co do układu dróg i położenia karczmy. A to tylko da tego, że za każdym uruchomieniem programu pozycje drzew są losowane. Wniosek: najlepiej cały świat jest budować sobie w edytorze.

Jakie zadania wykonuje nasz klasa naszej mapy?

  • na bieżąco rysuje położenie gracza
  • rysuje prostokąt widocznego obszaru świata 2D
  • reaguje na kliknięcie lewym/ prawym przyciskiem myszki
  • mapa nie jest rysowana gdy gracz jest w karczmie


Co można dodać do klasy?

  • położenia innych żywych obiektów
  • przesuwanie świata 2D do wskazanego punktu kliknięcja w mapie (podobnie jak to zrobiłem w swoim edytorze światów 2D patrz www.delphi.ilion.pl lub jak to jest zrobione w profesjonalnych grach)
  • ukrycie miejsc w których nie było jeszcze duszka gracza
  • i wiele, wiele innych pomysłów

Jak utworzyć i wywołać naszą mapę w projekcie gry?

Tu omówię tylko nagłówki procedur i miejsce ich wywołania. Analizę kodu pozostawiam czytelnikowi.

  1. Miejsce i sposób tworzenia mapy

Kod:
procedure TForm1.FormCreate(Sender: TObject);
begin
  //***CZĘŚĆ 6*********
  Mapa:=TMapa.Create(self,self.handle); //utwórz obiekt
  Mapa.UstawOmegaImageList(OmegaImageList1);//przypisz zasoby grafiki
  // ustaw skalę mapy w stosunku do oryginalnego rozmiaru swiata
  //umnie to 15,625 % czyli 0.15625 w obu osiach
  Mapa.UstawSkale(0.15625,0.15625);//procedura UstawSkale ma byc przed procedurą UstawParametry
  //ustaw parametry
  Mapa.UstawParametry(11,3,0,OmegaScreen1.Height-OmegaImageList1.ImageList.Items[11].TileHeight,12,18,64,32);
  Mapa.IdPunkt:=12;//INDEKS OBRAZU ZOLTEJ PLAMKI
  //********************
end;


Jak widać w 5 liniach mamy utworzoną naszą mapę. Tu chciałbym zwrócić uwagę na prametry podawane do procedury Mapa.UstawParametr:

  • 11 (parametr AIdObraz) to indeks obrazu map przechowywanych w OmegaImageList1
  • 3 (parametr AidKlatka)to indeks wycinanej klatki mapy
  • 0 (parametr ALeft) to współrzędna X lewego górnego rogu zaczepienia mapy
  • OmegaScreen1.Height-OmegaImageList1.ImageList.Items[11].TileHeight (parametr ATop) to współrzędna Y lewego górnego rogu zaczepienia mapy
  • 12 (parametr ARectCol) to liczba klatek widocznego świata w osi X , tu odpowiada wartości 800 div 64
  • 18 (parametr ARectRow) to liczba klatek widocznego świata w osi Y , tu odpowiada wartości 600 div 32
  • 64 (parametr AKlakaMapyWidth) to szerokość kafla siatki mapy
  • 32 (parametr AKlakaMapyHeight) to wysokość kafla siatki mapy

Deklaracja nagłówka tej procedury:

Kod:
procedure UstawParametry(const AIdObraz,AIdKlatka,ALeft,ATop,ARectCol,ARectRow,AKlatkaMapyWidth,AKlatkaMapyHeight:integer);


Skoro już utworzyliśmy mapę to należy ją wyświetlić i śledzić ruch gracza. I zrobimy to w procedurze zegara gry. Czyli tak:

Kod:
procedure TForm1.OmegaTimer1Timer(Sender: TObject);
begin
  ....
  .....
  //***CZĘŚĆ 6*********
  //śledż gracza
  Mapa.Ruch(8+(-Warstwa0[0,0].x+gracz.X)*Mapa.SkalaX,8+(-Warstwa0[0,0].y+Gracz.Y)*Mapa.SkalaY);
  //pokaż mapę gdy gracz jest poza karczmą
  if not Gracz.fWBudynku then  Mapa.Draw;
  //********************
  ....
  ....
end;


W procedurze Mapa.Ruch pojawia się liczba 8. Ta liczba jest wynikiem umiejscowienia rogu mapy w obrazie klatki mapy (brzmi jak masło maślane...) Zobrazuję to tym rysunkiem:

1406153934Image20.gif

Ciała procedury Mapa.Draw nie będę tu przytaczać. Jest ona bardzo prosta. Jej zadanie polega na rysowaniu obrazu wycinanej klatki mapy, rysowaniu żółtego prostokąta pozycji gracza jak i białego. W celach poglądowych umieściłem również zaznaczenie czerwoną ramkę obszaru klikniecia myszki w mapie. Procedura Mapa.MauseDawn jest wywołana w procedurze formatki TForm1.FormMouseDown.

No cóż prawdopodobnie jest to ostatni art z cyklu wędrówek w świecie 2D...Na pewno nie wyczerpuje to problemów i pomysłów na stworzenie gry 2D w oparciu o komponent OMEGI, ale dalsze ciągnięcie tematu w kolejnych częściach mija się z celem.

Pytanie dlaczego?

Dlatego gdyż nie potrzebnie rozbudowuje się kod z każdą nową częścią. A to utrudnia jego analizę. Lepiej jest rozważać modele rozwiązań w mniejszych, niezależnych partiach. Poza tym chcąc napisać dobry silnik 2D , należy przebudować sposób wyświetlania warstw. Jak ktoś z czytelników widział mój programik Gigant2D ( www.delphi.ilion.pl dział narzędzia ) to na pewno zwrócił uwagę, że FPS osiąga wartości rzędu 190- 260 i to nie zależnie od wielkości świata czy to 30x30 czy tez 2000x2000 klatek dla trzech warstw. Moje rozwiązanie użyte w Gigancie tak samo będzie działać w izometrycznym świecie.... Model w omawianych części przyjąłem najprostszy bo nie jest on głównym tematem tych sześciu części.

Mam nadzieję, że te 6 części przyczynią się do popularyzacji OMEGI jak i DELPHI....

Czas kończyć bo zaczynam już wywyższać DELPHI:-)

Pozdrawiam oksal

5.06.2006 Zbylitowska Góra

Pobierz załącznik załącznik

Autor: oksal

Komentarze
Artykuły mogą być komentowane wyłącznie przez zarejestrowanych użytkowników.

Zaloguj się | Załóż nowe konto

2009-12-27 20:17:10

Jak najszybciej.
2009-12-09 10:11:34

Mam na imię Kacper mieszkam w Gdańsku mam 9 lat i nie wiem jak włączyć grę, ale pobrałem już załącznik.A więc jak?
Redakcja zastrzega sobie prawo do skracania, usuwania komentarzy o treściach wulgarnych, obraźliwych oraz niezgodnych z polskim i miedzynarodowym prawem. Unit1.pl Team nie ponosi odpowiedzialności za treść komentarza.