luq techblog

o tworzeniu słów kilka…

Tetris 2 kwietnia 2009

Filed under: GameDev,Pascal,Programowanie — Łukasz @ 12:43
Tags: , ,

game Ostatnimi czasy dostałem jako prace dodatkową na zajęcia z programowania w moim technikum zadanie napisania gry ;] Jak najbardziej mogła być to bardzo prosta gra, typu tekstowy kółko krzyżyk etc. Jako, że kółko krzyżyk nie stanowi dla mnie wyzwania, postanowiłem napisać coś bardziej zaawansowanego. Wybór padł na tetris, szczerze, nie wiem dlaczego ;) Niestety językiem, który musiał zostać użyty był, aktualnie przerabiany, Pascal – język do którego nie darze sympatią, a co za tym idzie, znam go raczej miernie. Chodź był to mój pierwszy język, w którym tak naprawdę uczyłem się programowania. Jakbym mógł, pisałbym w C++ z wykorzystaniem SDL`a, no ale cóż, nie ja decydowałem. Jak się potem okazało Pascal (ze standardową biblioteka graph) przysporzył mi sporego kłopotu, jeśli nie kilku, który/które w C++ byłyby łatwiejsze do rozwiązania.

 

Warto na początek, wspomnieć o historii i zasadach gry.

Tetris to gra wymyślona i stworzona przez Rosjanina Aleksieja Pażytnowa w 1985 roku. Sprzedaż gry sięgała milionów sztuk, z czego twórca nie dostał nic (gdyby Aleksiej nie żył w Związku Radzieckim…) . Odbiegając lekko od tematu, kiedyś udało mi się w czasie przełączania kanałów w telewizji napotkać na film dokumentalny opisujący losy właśnie tej gry, przyznam ciekawy, ale nie pamiętam go dokładnie, dość dawno to był ;> W grze układamy na planszy – zwanej tetrionem, (lub inaczej studnią) spadające klocki – tetramino, tak aby zapełnić poszczególne wiersze bez luk, w ten sposób wiersze te znikają. Przegrywamy, kiedy wysokość naszych klocków sięgnie góry tetrionu. Każdy grał w tetrisa więc nie ma co za dużo tłumaczyć. Dodam tylko, że mamy do dyspozycji (w standardowej wersji bo o niej mowa) 7 rodzajów tetramino, nazwanych od ich wyglądu, literami: I, T, O, L, J, S oraz Z.

 

Pisząc, oczywiście nie obyło się od błędów, poczynionych już na etapie planowania. Ma to też związek z moim zwyczajem odkrywania koła na nowo. Pierwszym błędem było złe zdefiniowanie tetramino. Naturalnym jest, że każdy klocek, a dokładnie jego kształt jest zasypywany w macierzy a podczas jego obracania, zmienia się kształt w tej macierzy. Zastosowałem w tym wypadku macierz boolowską, chodź nie ma to tutaj znaczenia. Później przeglądając internet w poszukiwaniu czegoś na temat tetrisa, tak w formie relaksu, natrafiłem na:

tetramino-position

Jest to rysunek oryginalnego zestawienia pozycji poszczególnych tetramino. Natomiast ja, zdefiniowałem każdy klocek maksymalnie w lewym górnym rogu macierzy. Dla przykładu, tak wyglądają tetramino I oraz S w mojej macierzy:

my-position

Nie jest to jakiś błąd, tyle, że zestawienie oryginalne jest o wiele lepsze. Dlaczego? Załóżmy że aktualnie spadające tetramino to I w pozycji pionowej, które przenieśliśmy maksymalnie do prawej strony, tak, że dotyka ona prawej krawędzi naszej mapy. Teraz chcemy obrócić klocek do pozycji poziomej. W tej sytuacji, naciskając klawisz zmiany pozycji nie powoduje on jej zmiany. Klocek nie może zostać obrócony bo wyjechałby poza mapę. Należy przesunąć go w lewo. I tutaj pojawia się różnica mojej wersji w stosunku do wersji oryginalnej. U mnie klocek musi mieć odstęp w tej sytuacji 3 pola od krawędzi, w oryginale jest to 1 pole. Analogiczna sytuacja w lewej stronie mapy, u mnie nie wymaga wolnego pola między klockiem a krawędzią, w oryginale są to 2 pola. Wydaje mi się, że definicja pozycji tetramina zastosowane w pierwotnej wersji tej gry jest o wiele lepsze. U mnie kręcenie klockiem przysparza dość dużo problemów i nie zawszę odbywa się wokół swojego środka.

 

Drugi poważny błąd wynikał z nieprzewidzenia pewnej sytuacji. Spadające klocki w większości przypadków kolidują swoją spodnią stroną. Dlatego, ja, sprawdzając kolizje, dla każdego tetramino, szukam miejsc kolizji. O co chodzi? Klocek spadając, może kolidować z ułożonymi już wcześniej klockami, polami maksymalnie wychylonymi w dół w każdej kolumnie macierzy. Dla lepszego zobrazowania, punktami kolizyjnymi dla wcześniej już zaprezentowanych tetramino w mojej macierzy, są punkty oznaczone na czerwono na poniższym obrazku:

collision

Macierz tetramino niejako porusza się po częściowo zapełnionej macierzy tetrionu (mapy) i jeśli poniżej któregokolwiek punktu kolizyjnego tetramino, w tetrionie, pole jest zapełnione to występuje kolizja. Fajnie, wszystko działa, tyle tylko, że nie przewidziałem możliwości wsuwania klocków, np: (jaśniejszy klocek przedstawia aktualnie spadający)

left-right-collision

Jeśli po wciśnięciu strzałek prawo/lewo nie będziemy sprawdzać, czy aby pola po tej stronie nie są już zapełnione to niestety pojawi się błąd którego skutkiem będzie wjazd w już ustawiony klocek, w tej sytuacji naciśnięcie 2 razy strzałki w lewo w ostatniej fazie spowoduje:

bug

No, i o takiej możliwości zapomniałem.

 

Problemem, który sprawił mi język, a raczej standardowa biblioteka graph, było miganie. Problem niby dość prosty do rozwiązania – podwójne buforowanie (ang. double buffering). W SDLu czy Allegro sprawa dość prosta do rozwiązania, zdefiniować drugi obszar w pamięci gdzie będzie tworzona scena, następnie stworzoną już całość kopiować na ekran. Niby w graphie istnieją funkcję:

 

SetVisualPage() oraz SetActivePage()

 

jednak przy:


initGraph( VGA, VGAHi, '' );

 

strony nie działają, i z tego co wyczytałem na necie nie ma możliwości aby to zadziałało. Znalazłem info jak temu zaradzić – tryb 13h, jednak nie znając Asemblera, nie chcę wpychać kodu którego nie rozumiem. Więc ten sposób odrzuciłem nawet nie zastanawiając się nad nim zbytnio. Jedyne co mi pozostało to zamalowywanie spadającego klocka, przez co to tylko on miga. Efekt nie jest oszałamiający, jednak na pewno o niebo lepiej się w grę gra przy migającym jedynie aktualnie spadającym tetramino niżeli jakby migało wszystko (po kilku minutach takiej gry naprawdę odechciewa się wszystkiego).

To tyle jeśli chodzi o moje starcie z tetrisem, jest pierwsza gra która została prze zemnie napisana. Wyżej opisane błędy i niedociągnięcia nie zostały zniwelowane w aktualnej wersji, która nie jest jeszcze stabilna, np. przy game over pojawia się błąd. Jak to ktoś kiedyś powiedział: „90% kodu piszę się przez 90% czasu, kolejne 10% kodu piszę się w kolejne 90% czasu”, całkowicie zgadzam się z tą zasadą. Jeśli pisałbym tetrisa drugi raz, dużo rzeczy bym oczywiście pozmieniał. Wersję stabilną będę raczej pisał od nowa, na bazie aktualnej, no chyba, że naprawdę nie będzie mi się chciało ;]

 

Co do dodatków do gry, przydało by się napisać:

– pauze
– cień aktualnie spadającego tetramino, tak aby widzieć od razu gdzie spadnie po naciśnięciu strzałki w dół
– jakieś menu

 

Link do downloadu: PasTris.exe

Reklamy
 

2 Responses to “Tetris”

  1. Benkowik Says:

    Gratulacje! Jak na możliwości Turbo Pascala to gra jest świetna. Może powstanie jeszcze jakaś gra w TP autorstwa luq’a ;)

  2. luq Says:

    Nie przewiduje już żadnej gry w Pascalu. Piszę w tym języku tylko i wyłącznie wtedy kiedy, muszę (czyt. na zajęciach z programowania). Pewnie i powstanie w przyszłości gra nr 2, tyle, że ta już będzie w C++ i SDLu :>


Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s