Warsztat.GDCompo!ProjektyMediaArtykułyQ&AForumOferty pracyPobieranie

Opisz napotkaną sytuację, a redakcja niezwłocznie znajdzie rozwiązanie!

wyślij anuluj

Piszemy platformówkę

Tekst został importowany z Warsztatowych artykułów. Jego oryginalnym autorem jest Toster. Jeżeli został importowany poprawnie, usuń ten szablon!

Artsa tego pisze bo znalazłem chwile czasu i się nudzę, postaram się pokazać jak można zrobić prostą grę platformową, od razu zaznaczam, że skupie się na Enginie, a nie na rysowaniu tego na ekranie. Tak więc całość będzie rysowana na PaintBoxie, jak się komuś nie podoba zawsze może podłączyć to do innego silnika i będzie gut. To zaczynamy:

1. Założenia.

  • Ludzik chodzi ze stałą prędkością w lewo/prawo
  • Podskok ma być taki jak w rzeczywistości, (zwalnia lot przy wznoszeniu i przyśpiesza przy spadaniu)
  • przez platformy da się przeniknąć “od dołu” tzn. Ludzik nie uderza głową o platformę przy skakaniu.

2. Co nam potrzebne.

  • umiejętność programowania obiektowego
  • mózg
  • chwila czasu i cierpliwości
  • delphi

3. Zaczynamy.

Na początek warto się zastanowić jak będziemy trzymać dane o naszym levelu ? Ja wybrałem rozwiązane oparte o listę obiektów (każdy obiekt w tej liście będzie zawierał informacje o lokalizacji platform) inna droga to zrobienie tablicy o odpowiednich wymiarach i trzymanie w niej mapy na podstawie. Ok co musimy pamiętać w naszej platformie ? Otóż na początek kilka podstawowych rzeczy czyli:

  • współrzędne początku x,y
  • wysokość oraz szerokość platformy

W późniejszym czasie będzie można dodać np. prędkość poruszania się platformy (jeśli ma latać) albo czy platforma zabija naszego ludzika (np. kolce i inne chadziajstwa), ale to może kiedy indziej na razie pamiętamy gdzie ta platforma stoi).

Drugi ważny element naszej gry to ludzik :) Tak więc musimy pamiętać o nim to co o platformie (gdzie jest i jaki duży jest) oraz kilka dodatkowych rzeczy:

  • czy spada/skacze ?
  • Jeśli spada lub skacze to jaka jest jego prędkość Y ?

I tak właściwie to mamy już wszystko :) Teraz weźmy się za pisanie, zrobimy sobie 4 klasy:

TDimObj – w tej klasie będziemy trzymać informacje o wymiarach obiektów, klasa macierzysta dla pozostałych obiektów
TLudek – klasa dziedzicząca po TDimObj wszystko co jest nam potrzebne do ludzika
TPlatform – klasa, w której będziemy trzymać informacje o platformach
TLevel – klasa, w której będziemy trzymali listę platform oraz inne procki potrzebne nam do zarządzania levelem.

Nie będę kopiował tutaj deklaracji klas bo szkoda na to czasu i miejsca. Omówie co ciekawsze (wg mnie) kawałki kodu, resztę trzeba zrozumieć samemu, program jest napisany bardzo prymitywnie wiec nie sądzę aby były z tym jakieś problemy.

Jak to to działa ?

Jak klikniemy Button to:

  • stworzymy plansze
  • stworzymy ludzika
  • uruchomimy timer

W timerze znajduje się główna część odpowiedzialna za działanie wszystkiego w jednym tempie, tzn. Wykonujemy update Ludzika oraz jego pozycji, nakazujemy odrysowanie levelu. Jak zapewne widać ruch ludzika odbywa się na podstawie dwóch pól (fDoLeft, fDoRight) jeśli któreś z nich jest ustawione na true (dzieje się to w metodzie OnKeyDown) to ludek będzie dreptał w określonym kierunku, gdy jest false (patrz OnKeyUp) to nie będzie dreptał. Skok jest realizowany poprzez wywołanie metody Ludek.Jump co można znaleźć w OnKeyUp.

Tyle się właściwie dzieje na głównej formie naszego projektu, jak widać niewiele, engine jest w 90% niezależny od tej formy i właściwie równie dobrze może działać na konsoli (trzeba przerobić tylko metody Draw w odpowiednich klasach).

Backend.

Tutaj na razie też nie ma żadnej rewelacji po krótce omówie kilka metod:

procedure TLudek.Jump; begin //hopla if fDoJump = true then exit; fDoJump := true; fYVel := cStartVel; end;

Sprawdzamy czy już nie lecimy/spadamy, jeśli nie to ustawiamy odpowiednią zmienną na true oraz ustalamy prędkość początkową, im wyższa prędkość tym wyżej skoczymy :) Ale to już wszyscy wiemy z fizyki. Druga Metoda to TLudek.Fall bystre osoby zauważą że różni się ona od Jump'a tylko jedną sprawą, a mianowicie fYVel jest -1, ta mała kosmetyczna zmianka powoduje, że ludzik nie będzie się wznosił tylko od razu zacznie spadać, prawda że fajne ?

TLudek.Update główna metoda, która coś robi w miarę aktywnego w całym enginie, a mianowicie pozwala naszemu ludzikowi skakać i spadać, większość jest opisana w kodzie i raczej nie powinno być problemów wiec skupie się tylko nad tymi linijkami:

if fDoJump = true then begin Y := fy - fYVel; fYVel := fYVel - cGravity; if fYVel < -15 then fYVel := -15; //ogranicznik prędkości spadania, jak prędkość będzie > cTileSizeXY to bedzie można przelecieć przez platformę :) end;

Też raczej nic odkrywczego wychodzimy ze wzoru na drogę w ruchu jednostajnie opóźnionym tj: s(t) = Vo*t – 1/2*a*t*t. Aby uniknąć zabawy ze zliczaniem czasu lotu (bo i po co to komu) wzór ten należy pozbawić czasu, a najprościej to zrobić korzystając z wektorów o tak:

V=Vo

a później już tylko dodawanko i odejmowanko

s = s + V
V = V – Vs
Vs = a/t

czyli jeśli znamy a/t czyli o ile zwolni nasz obiekt co jedną jednostkę czasu to znika nam czas (hura ;) ). Tak nawiasem Vs w programie nazywa się cGravity a Vo nazywa się cStartVel.
I jeszcze ważna sprawa, musimy wprowadzić mały ogranicznik dla V, jeśli dojdziemy już do spadania i V > grubość platformy (pomińmy niezgodność jednostek....) to okaże się, że nasz ludzik może (ale nie zawsze będzie, sami dojdźcie dlaczego) przelatywać przez platformy.

4. Przemieszczanie ludzika pomiędzy platformami

Będziemy bazowali na programie, który napisałem ostatnio tylko go rozbudujemy. Jakie zmiany są wprowadzone każdy potrafi stwierdzić więc nie będę się rozpisywał co i gdzie dodałem. Skupimy się w pierwszej kolejności na zasadzie działania, a później omówię pokrótce co ciekawsze części kodu.

1. Idea.

Otóż każdą platformę potraktujemy jako węzeł grafu, albo mówiąc inaczej węzeł czyli coś do czego mogą prowadzić drogi lub skąd mogą prowadzić drogi. Skoro mamy kilka węzłów (bo jest kilka platform) to jasne jest, że będziemy tworzyli sieć połączeń między tymi węzłami. Drogi o których mowa będą jednokierunkowe (graf skierowany) czyli jeśli mamy drogę nr 1 z punktu A do B oznacza to, że możemy iść tylko z A -> B, powrót musi być realizowany inną drogą (np. drogą 2). Skoro mamy już węzły i drogi to trzeba będzie nauczyć program wyszukiwać drogi z zadanego punktu początkowego do zadanego punktu docelowego. Oczywiście może się okazać że droga taka nie istnieje (w zależności od tego jaki powstał graf) i nasz program też musi sobie z tym poradzić. Jak będziemy szukać ? Otóż najprościej jak się da oznacza to, że wyznaczona droga nie musi być optymalna pod względem długości (niekoniecznie będzie najkrótszą drogą), a algorytm który użyjemy będzie dosyć wolny, wyglądać toto będzie tak:

  1. Stajemy w węźle początkowym i sprawdzamy czy prowadzi stąd droga do węzła końcowego. Jeśli tak zapamiętujemy tą drogę, kończymy szukanie.
  2. Idziemy pierwszą drogą, którą znaleźliśmy w węźle początkowym i wykonujemy dla niego podpunkt 1.
  3. Operacje z punktu 2 powtarzamy dla wszystkich dróg w analizowanym węźle.
  4. Jeśli droga do celu jest odnaleziona to cofamy się drogą którą przyszliśmy i zapamiętujemy drogę prowadzącą do tego miejsca. Robimy to tak długo (cofamy się) aż dotrzemy do węzła początkowego.

Jak widać jest to algorytm rekurencyjny, żre dużo pamięci i niekoniecznie jest szybki ale jest prosty dlatego go wybrałem. W tym miejscu kończy się właściwie idea.

2. Implementacja

Ok aby zrealizować naszą ideę musimy zaimplementować następujące funkcje:

  1. Tworzenie grafu na podstawie istniejących platform
  2. Wyszukiwanie drogi w oparciu o graf
  3. Poruszanie postaci w oparciu o odnalezioną drogę.

Zacznijmy od punktu 1 czyli tworzenia grafu. Metoda, która się tym zajmuje nazywa się Tplatform.CreateWebWay i przyjmuje jako parametr ludzika dlaczego ? Bo każdy ludzik może mieć swój graf poruszania się (ludziki mogą się różnić np wielkością, prędkością poruszania, wysokością skoku itp. dlatego po tych samych platformach różne postacie będą się różnie poruszały). Od czego zaczynamy ? Otóż plan jest prosty bierzemy pokoleji wszystkie platformy, stawiamy na nich ludzika i sprawdzamy gdzie spadnie (po lewej i po prawej), później stawiamy tego ludzika na krawędzi platformy i każemy mu skakać w lewo oraz prawo i zapamiętujemy gdzie spadł, później przesuwamy go w prawo o wartość równą prędkości jego chodzenie i znowu każemy mu skakać, robimy to tak długo aż dojdzie do drugiej krawędzi. W ten oto sposób dostajemy wszystkie drogi, które prowadzą z tej platformy na inne. Kolejnym krokiem jest optymalizacja znalezionych dróg. Dlaczego ? Otóż po wykonaniu tego algorytmu może się okazać że dostaniemy setki dróg prowadzących na np 3 platformy, po analizie okaże się, że da się to skompresować, robimy to tak:

  1. Usuwamy drogi które prowadzą na platformę z której wyruszamy.
  2. Jeśli na inną (tą samą platformę) prowadzą np 2 drogi które polegają na skoku w lewo, to łączymy te drogi w jedną ustalamy tylko odpowiedni fXStart i fXStop. Jeśli ludzik będzie w przedziale wyznaczonym przez te dwie zmienne oznacza to, że prowadzi stąd jedna droga.

Po zakończeniu tych operacji mamy stworzony graf dróg. Warto zerknąć na metodę TLudzik.Simulate zajmuje się ona symulacją chodzenia i skakania ludzika dzięki niej wiemy gdzie tak naprawdę doleci ludzik jeśli skoczy z zadanego miejsca na platformie.

Wyszukiwanie drogi w oparciu o graf realizują trzy metody: TLudek.GoToPlatform, oraz TLudek.FindWay oraz TLudek.WebWaySearch. Pierwsza z nich wywołuje właściwą procedurę szukającą, a po jej zakończeniu sprawdza czy droga została odnaleziona, jeśli tak to pobiera pierwszą daną potrzebną do rozpoczęcia ruchu i zapamiętuje ją w polu fNextWebWay. Druga metoda przygotowuje listę, w której będzie trzymana droga, wywołuje metodę wyszukującą drogę, a następnie odwraca kolejność w liście opisującej drogę. Metoda nr 3 jest właściwą metodą poszukującą drogi, została ona omówiona na samym początku.

Poruszanie ludzika. W tym momencie mamy już drogę więc czas zacząć chodzić. Sprawny umysł od razu zauważy zmiany jakie zaszły w procedurze Update. Pojawił się blok które sprawdza czy mamy ustalony jakiś cel gdzie będziemy szli, jeśli nie to szukamy sobie jakiejś losowej platformy na, którą się udamy. Druga część powoduje wywołanie metody TLudek.ExecuteDreptacz, która to metoda jest odpowiedzialna za właściwy ruch. Jej działanie jest następujące:

  1. Jeśli stoimy na platformie to sprawdzamy gdzie znajduje się na niej punkt z którego rozpoczyna się droga do innej platformy, następnie poruszamy się w jego kierunku
  2. Jeśli jesteśmy w miejscu pomiedzy fXStart fXStop to wykonujemy odpowiednie polecenie (np. skok, pionowy w lewo lub w prawo)
  3. Lecimy i czekamy aż spadniemy na nowej platformie
  4. Pobieramy kolejny punkt drogi.

I to z grubsza tyle. W programie jest kilka małych procek, które ułatwiają zrozumienie działania wszystkiego (np wyświetlanie drogi w ListBoxie, podświetlanie wybranej myszką platformy oraz pokazanie platform, do których prowadzą z niej drogi itp.). Mam nadzieje, że z artsa nie wyszedł jeden wielki bełkot, i że ktoś zrozumiał o co mi chodziło :)

Pozdrawiam

Toster
E-Mail:[email protected]
Web:Toster.ps.pl

Załączniki:
0302160708Programik.rar (6.1 kB)
2102214949AIArt.zip (15.2 kB)

Tekst dodał:
Artur Poznański
26.03.2006 15:31

Ostatnia edycja:
Artur Poznański
26.03.2006 15:31

Kategorie:

Aby edytować tekst, musisz się zalogować.

# Edytuj Porównaj Czas Autor Rozmiar
#1 edytuj 26.03.2006 15:31 Artur Poznański 12.55 KB
Zwykły
Do sprawdzenia
Do akceptacji
  • ~Cez 24 sierpnia 2007 10:33
    To się nazywa kiczowaty art. Zamiast wyjaśnić wszystko krok po kroku, Autor pokazuje tylko wybrane elementy gry. Chyba uważa, że wszyscy mają Jego poziom umiejętności.
  • ~wojo 24 sierpnia 2007 15:11
    Witam programuje od kilku ladnych latek w roznych tam jezykach... Pytanie Po co pisac tutowial bez wyjasnienia - chyba tylko po to zeby wylizac wlasne jaja... Ogolnie uwazam to za buraczanke Pozdrawiam Polskich programistow:)
  • ~Toster 15 września 2007 16:22
    @Wojo Lizanie jaj to to co uwielbiam. Wyjasnienia sa ale tylko to co uznalem za najwazniejsze. Rozumiem ze zaliczasz sie do biedakow ktorzy tylko po forach pisza posty typu: Mam problem prosze pomozcie.

    @Cez Do analizy krok po kroku jest program, odrobina wysilku nie zabija. Inna sprawa ze po to dalem adres mailowy ze gdyby ktos mial pytania to chetnie odpowiem.
  • ~veeroo 14 lutego 2008 19:44
    Gratuluje artykulu :) bardzo dobrze wprowadza w podstawy programowania gier i daje obraz wykorzystania odpowiednich struktur danych w pisaniu engine'u gry. Zachecajaco wprowadza w poczatki pisania gier :) Czekam na dalsze publikacje!

    @Wojo, @Cez: Czy uwazacie ze programowanie polega na przepisywaniu gotowych zrodel dostepnym w internecie? Jesli sadzicie ze tak, to prosze Was: dajcie sobie spokoj z programowaniem!! Autor nie bez celu zalaczyl zrodla programu, wystarczy sciagnac i przeanalizowac aby wszystko zrozumiec. Nie ma celu opisywac kazdej linijki kodu i robic kolejnego kursu Delphi skoro strona poswiecona jest programowaniu gier samo przez sie wymagana jest podstawowa znajomosc programowania (w tym wypadku w Delphi). Artykul opisuje podstawowe mechanizmy gdy a dostepny kod zrodlowy po przeanalizowaniu daje pelen obraz dzialania enginu gry.

    Pozdrawiam programistow Delphi!
  • Napisz komentarz:
    Aby dodać swój komentarz, musisz się zalogować.
Licencja Creative Commons

Warsztat używa plików cookies. | Copyright © 2006-2017 Warsztat · Kontakt · Regulamin i polityka prywatności
build #ff080b4740 (Tue Mar 25 11:39:28 CET 2014)