Pobierz kod Wędrowanie w świecie 2D- część 1
WĘDROWANIE W ŚWIECIE 2D (część 1)
Tematem tego artykułu jest poruszanie się bohaterów w świecie gry 2D, konkretnie chciałbym w nim
przedstawić rozwiązanie pewnych problemów jakie można w takim "świecie" napotkać.
Oczywiście kod programu jest w DELPHI z użyciem OMEGI
Jakie to problemy?:
a) jak wyświetlić duszka po drugiej stronie drzewa (za liśćmi) lub budynku ,
b) jak przejść przez las,
c) jak warunek a i b połączyć z testem kolizji,
d) jak uniknąć dzielenia obiektów większych niż rozmiar przyjętej siatki planszy nie tracąc spójności obiektu pod względem wykrywania kolizji i zajmowanego "klocka" pola siatki 2D,
e) jak przyśpieszyć działanie programu pomimo włączonej funkcji OmegaSprite1.Collision (sugestie).
Tu chciałbym nadmienić, że podane rozwiązania są propozycją ugryzienia problemu i na pewno nie są jedynym sposobem. Dają dobry wynik w teście na FPS i mogą być bazą (niewielka zmiana podejścia) do opracowania metody tworzenia gigantycznych światów ale o tym będzie w innym cyklu artykółow.
UWAGA
Omawiane przykłady nie są super szybkim przewijaniem światów 2D. Podstawowym tematem artykułu jest zmiana koloru duszka znajdującego się za obiektem. Program gigant2d.exe napisałem i dołączyłem do artykułu tylko po to aby nie być gołosłownym (nie uwzględniłem w nim omawianej zmiany koloru, utworzyłem w nim precyzyjniejszą metodę wykrywania przeszkody, która bazuje na pomyśle jaki opiszę w części drugiej).
Jeśli ktoś w podanych przykładach chciałby zwiększyć FPS niż przeze mnie ustalony, to powinien w komponencie OmegaScreen1 zmienić na wartość FALSE właściwość OmegaScreen1.VSYNC
CZEŚĆ 1- ZMIANA BARWY BOHATERA DUSZKA
Patrz rysunek A (pod głównym tematem artykułu)
Przed przystąpieniem do analizowania kodu, chciałbym zwrócić uwagę na taki problem:
obiekt umieszczony na planszy gry nie będący na przykład trawą czy też innym gruntem a mogący wytworzyć kolizję z duszkiem gracza wcale nie musi mieć rozmiary kostki pola świta 2D. Przykładowo nasz świat oprzemy na kostkach 64x32 a użyte drzewa będą mieć wymiary: 64x80, 64x90, 48x80, 38x46... A stąd już blisko do takiego problemu : powiedzmy osadzam w świecie karczmę lub inny budynek... I jak tu do niego wejść? A no prosto Tak samo jak w świecie rzeczywistym... otworzyć drzwi. Ale drzwi są (z reguły) jedne i z jednej strony!
I jest poważny problem: Jakie przyjąć rozwiązanie aby to wszystko połączyć? Pewnie wielu z nas stosuje warstwy w świecie 2D. Tylko, że są one o tych samych wymiarach co warstwa podstawowa ( ale na to też mam pomysł)... Mogą być dużo mniejsze niż taki budynek., drzewo (ale do drzew nie wchodzimy, chyba że ma dziuplę:)...Zostaje jedno uniwersalne rozwiązanie... Każda rodzina typu krzak, budynek, to osobna klasa , zaś drzwi, wejścia czy też inne przejścia, to wirtualne dziury w kolejnych warstwach...(i tak powstał temat na kolejny artykuł).
Przyjmując ten model rozwiązania należy liczyć się z tym, że nie możemy wykorzystać komponentu Omegi do tworzenia map, czyli OmegaMap
Przystępujemy do budowy szkieletu klasy przechowującej kostki świata gry i obiektów. Zaczniemy od klasy bazowej dla świata. Tu chciałbym jeszcze raz podkreślić, że nie jest to jeszcze podejście do gigantycznych światów 2D rzędu 250x250 czy też większych do 2000x2000. Jeśli mi ktoś nie wierzy, że można to ugryźć przy pomocy DELPHI ale o tym będzie w Gigantach
procedure Draw; ta procedura odpowiada z sposób rysowania
a ta
procedure Move(const MoveCount:single);override; za ruch mapy świata
gdzie SkokX i SkokY to zmienne zdefiniowane w sekcji var głownego projektu
Musimy ten warunek podać if ImageIndex<0 then exit; jeśli chcemy otrzymać niewypełnione kostki warstwy bez używania dodatkowych tablic. Warto też sobie zapamiętać, ze jeśli byśmy podali do ImageIndex wartość
-1(minus jeden) to zostanie narysowany cały obraz bez wycinani klatek. A ja tu to wykorzystałem do warunku rysowania lub nie jakiegoś obiektu (bez jakiś tam dodatkowych pętli).
Na tej klasie będzie żyć każda pojedyncza kostka warstwy i dodatkowo będzie ona klasą bazową do klasy naszych krzaków i drzew. Dla osób pierwszy raz spotykających się z pojęciem warstwy w świecie 2D przedstawiam poglądowy rysunek traktujący warstwy, że tak powiem klasycznie
Teraz możemy zdefiniować klasę dla krzaków
Klasa TRoslina odziedziczy po rodzicu procedurę Move, którą w dalszej części nieznacznie zmodyfikujemy. TRoslina będzie mieć możliwość wykrywania testu kolizji z duszkiem gracza
Jej zadaniem jest przekazanie informacji w postaci logiczne flagi fKolizja i fPokryty do duszka gracza Na część pierwszą artykułu tyle informacji o tych klasach powinno wystarczyć. Jedynie chciałbym w tym miejscu podkreślić, że tak planujemy kod aby unikać dodatkowych pętli po utworzonych obiektach.. A może być ich znaczna ilość. Te funkcje i tak są wykonywane wystarczy spojrzeć na procedurę zegara aplikacji. Jest tam wywoływana procedura OmegaSprite1.Draw, OmegaSprite1.Move, OmegaSprite1.Collision, OmegaSprite1.Dead. Dowodem tego, że to działa jest chociażby przesuwanie mapy świata. Przecież ten kod
Jest tylko w tym i tylko w tym miejscu zdefiniowany. A o tym czy zmienia się wartość zmiennych SkokX lub SkokY decyduje gracz przyciskając klawisze strzałek....
Teraz bierzemy pod lupę klasę duszka Gracza
A poniżej kilka uwag do jej funkcjonowania
Tę procedurę rozbudujemy w następnych częściach artykułu
Tę również, która odpowiada ona z ruch (choć w tej postaci nic nie testuje, będzie to zrobione w następnej części)
Procedura poniżej zamieszczona zmienia sposób rysowania duszka gracza. Jeśli duszek znajdzie się za drzewem to zostanie wyświetlony w innej barwie. Można popróbować rożnych ustawień ostatnich pięciu parametrów to znaczy składowych R,G,B, Alpha i tej ostatniej, która może przyjąć takie wartości
Stale te zdefiniowane są w źródłach komponentu OMEGI (tu w pliku OmegaScreen.pas)
A co robi to dziwactwo?
Już odpowiadam. Sprawdza czy cały obrazek duszka został przykryty obszarem obrazu drzew czy też budynku
(rezultat jej działania wykorzystuje procedura testu kolizji klasy TRoslina). Jeśli nie, to ma się nam pokazać tylko głowa duszka lub inna część nieprzykryta bez zmiany koloru. Tak jak to pokazuje poniższy rysunek
Jak się przyjrzeć, to można zobaczyć, że gracz jest pod roślinką i po mimo kolizji może pod nią iść...(część 2)
Na zakończenie poniżej przedstawiam, to co powinniśmy uzyskać z kodu 1 części. (pełny w załączniku do artykułu). W części pierwszej duszek nie reaguje na kontakt z pniem drzewa... ale o tym w 2 części.
Koniec części 1