KOLIZJA W WARSTWIE- IZOMETRIA W ŚWIECIE PROSTOKĄTNYM- CZEŚĆ 4
W tej części zamierzam omówić model wykrywania kolizji w gigantycznych warstwach światach gry 2D. Jest to podejście opierające się na przykładzie kolizji dołączonej do pakietu Omegi. Tak, więc nic nowatorskiego. No może poza jednym pomysłem, który decyduje o prędkości wykonywania kodu gry. I to jest celem tego pomysłu. Ale po kolei. Poniżej fragment miejsca w świecie 2D gdzie dochodzi do kolizji
Tu chciałbym zwrócić uwagę, że można wirujące maczugi potraktować jak obiekty statyczne- bez możliwości ruchu po planszy i problem kolizji rozwiązać inaczej. To znaczy w standardowy sposób. Ja zdecydowałem się na inny pomysł. Pomysł, dzięki, któremu jest znaczy zysk na czasie.
Pytanie: Na czym polega oszczędność czasu?
W zegarze gry są takie linie kodu:
1 2 3 4 5 6 7 8 9 10 11 |
//dotyczy warstwy 1, 2 OmegaSprite1.Collision; OmegaSprite1.Dead; OmegaSprite1.Move(OmegaTimer1.DeltaSecs); OmegaSprite1.Draw; //koniec dotyczy warstw 1 i 2 |
linia OmegaSprite1.Collision, wymusza wykonanie testu kolizji dal wszystkich obiektów klasy TSprite i jego potomków, które mają ustawioną flagę testu kolizji
1 |
DoCollision :=true; |
Oczywiście można wymusić kolizję na pikselach:
1 |
DoPixelCheck :=true; |
Taki test kolizji prawidłowo jest wykonywany tylko w części widocznej świata gry – obszar ekranu. Obiekty mogą być i poza ekranem. Stąd ograniczenie długości listy obiektów TSprite do sprawdzenia przyczyni się do wzrostu FPS. Można, więc przerzucać informację czy w danej klatce warstwy należy wykonać test kolizji. Jest to nadal pomysł „taśmociągu” opisanego u podstawy gigantów świata 2D. Czyli dla przypomnienia przenosimy w ograniczonym obszarze klatek grafikę plus kolizję z ogromnej mapy świata gry.
Wzrokowo można prześledzić przerzucanie flagi kolizji w kaflach warstwy, jeżeli w tej procedurze usuniemy klamry blokujące wykonanie linii if DoCollision then
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
procedure TKostkaMapy.Draw; begin if (ImageIndex=-1)or(fIDKafla=-1)then exit; Animacja; OdswiezKlatke; Image.Draw(Round(x+left),Round(y+top),0,0.5,0.5,1,1,Red,Green,Blue,Alpha,ImageIndex,0); { //test wzrokowy prawidłowowści przerzucania flagi kolizji if DoCollision then Form1.OmegaFont1.Print(Round(X),Round(Y),'Tak') else Form1.OmegaFont1.Print(Round(X),Round(Y),'Nie'); } if (idKlatka2=-1)then exit; fOmegaImageList.ImageList.Items[idObrazka2].Draw(Round(x+left+left2),Round(y+top+top2),0, 0.5,0.5,1,1,Red,Green,Blue,Alpha,idKlatka2,0); end; |
Wówczas warstwa pierwsza będzie informować tekstem czy dany obiekt- obraz w tej warstwie ma być poddany testowi kolizji. Informacja to słowa: „Tak/ Nie”
Tu proszę pamiętać, że w opisywanym modelu świata, kolizja wykonywana też jest na zasadzie zadawania pytania: Czy można wejść żywym obiektem do danej klatki? Opisywałem to w poprzednich częściach- pola drogi, które dla przypomnienia w edytorze gry zaznaczone są kolorem czerwonym.
Takie podejście zapewnia nam prawidłowo wykrywanie przejść itp. w części niewidocznej gry na przykład dla automatów.
Przerzucanie flagi kolizji
Jest zorganizowane w tym samym miejscu, co przerzucanie obrazów. Wystarczy wzbogacić poniższą procedurę o linie zdejmowania/ ustawiania flagi kolizji. Patrz pierwsza i ostatnia linia w poniższej procedurze
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
procedure TKostkaMapy.ZmianaKlatki; begin DoCollision :=false; if (RogX>-1)and(RogY>-1)and (RogX<danemapy.xcount)and(rogy<danemapy.ycount) <br=""> then fIDKafla:=RogX+RogY*DaneMApy.XCount else begin fIDKafla:=-1; exit; end; Image:=DaneMapy.OmegaImageList.ImageList.Items[Pmapa(Lista.Items[idWskMApy])^[fIDKafla].idObrazka]; ImageIndex := PMapa(Lista.Items[idWskMApy])^[fIDKafla].idKlatka; //uswta nowe wartości Red, Green, Blue, Alpha jakie niesie w sobie nowa komórka mapy świata RGBA; DoCollision :=PMapa(Lista.Items[idWskMApy])^[fIDKafla].Animacja.fKolizja; end;</danemapy.xcount)and(rogy<danemapy.ycount)> |
Reakcja duszka na kolizję
Dla potrzeb artykułu jest to najprostsze zdarzenie, jakie sobie można wyobrazić w wyniku wykrycia kolizji. Polega ono na cofnięciu obrazu duszka w kierunku odczytanym na podstawie bieżącej klatki animacji, ale o zwrocie przeciwnym do zwrotu patrzenia duszka. Wykonuję to w tej procedurze
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
procedure TKostkaMapy.onCollision(const Sprite:Tsprite;const colX,colY:integer); begin if (Sprite is TPraduch)then begin with TPraduch(Sprite) do begin skokX:=-dv*2*tabWersor[ord(Kierunek),0]; skokY:=-dv*1.5*tabWersor[ord(Kierunek),1]; end; end; end; |
Klasa TPraduch jest klasą wyjściową – rodzicem dla ruchomej postaci TPierwotny
Procedura nie jest dopracowana, ale ogólny model przerzucania kolizji w klatkach warstwy został przedstawiony.
I to by było na tyle
Pozdrawiam
Adam Lasko (oksal) 25 III 2008 Zbylitowska Góra
PS
Do prawidłowego działania przykładu wymagane są te pliki:
swiat_512x384.mue2D
kasztan.oil
teren_rosliny.oil
swiatynie.oil
zamki.oil
pierwotny001.oil
wiatrak.oil
mlyn.oil
D3DX81AB.DLL
MPPSDK.DLL
Autor: oksal