Co to są płytki? Kafelkowa grafika w grach. Własny silnik Tilemap w wersjach roboczych Z piaskownicy


(płytka - płytka) jest zasadniczo metodą tworzenia duże obrazy (obrazy) przy użyciu mniejszych elementów.

Ogólnie rzecz biorąc, jest coś pięknego i znowu nie Rosyjskie słowo - mozaika. Pamiętaj, co to jest. Dzieje się tak, gdy składasz duży obraz kawałek po kawałku, a to prawie to samo, co rajstopy. Albo pamiętaj, jak wycinali pieniądze i kładli płytki.

// Mieszanie tematów na blogu to zły pomysł...


Jaki dach? Płytka. Cudowna właściwość: możesz zamienić rzeczownik w przymiotnik, ale wtedy nie da się go normalnie przetłumaczyć, ale jest łatwy do zrozumienia.
Wróćmy do naszego tematu, grafika kafelkowa w grach, co to jest?

Jest to grafika składająca się z kafelków (Czapka). Przykład:


Czasami okazuje się bardzo piękny


Te krzesła i stół również są z płytek. Płytki to ściany, podłogi i inne elementy. Drzwi tutaj najprawdopodobniej nie są kafelkami, ale przedmiotami, ponieważ możliwa jest z nimi interakcja.

Ponadto grafika kafelkowa w zasadzie przypomina nieco sztukę pikselową, podobnie jak mozaika, obraz jest rysowany piksel po pikselu. Element po elemencie.


Więcej grafiki pikselowej tutaj


Ale na tym zdjęciu (to wcale nie jest gra), grafika nie jest kafelkowa. Wszystko tutaj jest rysowane indywidualnie. Tu dochodzimy do pierwszego problemu z grafiką kafelkową – czasami wygląda zbyt monotonnie.


Standardowy przykład płytek w studiu twórców gier


Pamiętacie nawet edytor map StarCrafta:


A potem przeczytaj mój artykuł - w którym o nim pisałem. W pierwszym staruszku wszystko to zostało zrobione dość ciekawie i tam udało się częściowo przełamać monotonię, gdyż niemal każdy element był generowany losowo, nawet jeśli był tego samego typu. O czym mówię?

Bierzemy ten sam ekran i powiększamy go.


Płytki się nie powtarzają


A kiedy był to mój ulubiony pierwszy StarCraft?

Bóg wie kiedy, a oni już coś takiego wymyślili. A teraz niektórzy twórcy gier nadal umieszczają kafelki tego samego rodzaju w rzędach.

Kwestia grafiki w grach jest bardzo istotna, gdyż w dużym stopniu determinuje ostateczny budżet i czas produkcji.

Tworzysz narzędzia takie jak edytor map, a potem je tam umieszczasz, a oni już wszystko pięknie i inteligentnie układają. Im więcej narzędzi będą mieli, tym będzie piękniej, ale to dużo pracy.

Nie tylko to wszystko narysować, ale także ułożyć, a potem wymyślić sposób na losowe zestawienie elementów, jeśli to ma być zrobione.

Jeśli chcesz, żeby gra ostatecznie była piękniejsza, musisz narysować kilka duszków dla jednego drzewa na raz. I nie, choinka i dąb to różne płytki i sparity, będą osobne. Potrzebujesz dużo choinek i dużo dębów na raz.

Płytki najczęściej wykonywane są w formie paczki (zestawu), zwanej matrycą płytek. Jest to duży fragment podzielony na mniejsze. Coś takiego:



A teraz z tego zestawu wyjęto konkretne płytki. Może to być po prostu zielony kwadrat – trawa, drzewo lub cokolwiek innego.

Wszystko tutaj jest dość proste, a jednocześnie piękne. Motyw śniegu. Mając gotowy zestaw płytek, wykonałeś już połowę pracy, wystarczy je tylko pięknie ułożyć.

Płytki są lżejsze od obiektów, są lepsze pod względem szybkości gry, dadzą ci wyższy FPS i wydajność, jeśli użyjesz ich, a nie obiektów. Potrzebujesz obiektów ze duszkami tylko wtedy, gdy masz z nimi interakcję. Powiedzmy, że jeśli miotacz ognia spali las, to tak, najprawdopodobniej będziesz musiał przebić drzewa przez obiekt.

Ale prawie wszystkie są dekoracyjne (czysto wizualnie) elementy można wykonać z płytek.

  • Przeczytaj także:
Powiedzmy, że to te same filary. Cóż, po co ci jakakolwiek interakcja między bohaterem a filarami? Wystarczy kolizja (kiedy nie możesz przez to przejść).

A w przypadku kolizji możesz po prostu uczynić obiekt solidnym, niewidocznym obszarem, a następnie przenieść go pod filar. Potem przez filar (duszek - płytka) przejście nie będzie możliwe, ruch będzie blokowany przez „stały” obszar.

W , o którym obecnie kręcę film, pojawiły się nowe funkcje pracy z kafelkami, pojawiły się animowane kafelki. Możesz także je wywołać (i usunąć) za pomocą kodu. Bardzo interesująca rzecz. Ponadto, możesz teraz umieszczać płytki partiami na raz i szybko zapełniać pokój z mapami płytkami.

Całkiem wygodne, szczególnie w przypadku małych płytek.


Dla początkującego, który chce tworzyć gry w kreatorze gier, w zasadzie nie jest konieczne używanie płytek, często początkujący po prostu robią to wszystko (pole, drzewa itp.) zwykłe przedmioty ze spritami i do proste gry może być ok.

Ale kiedy zdecydujesz się stworzyć grę RPG (lub gra z innego gatunku) bez grafiki potrzebne będą płytki. Mam nadzieję, że odpowiedziałem na pytanie - czym są kafelki i podałem akceptowalne przykłady grafiki kafelków w grach.

A jeśli jesteś zainteresowany konkretne przykłady i jak to wszystko działa w GameMaker Studio 2, możesz zobaczyć mój wideo (9 minut). Subskrybuj mój Kanał Econ Dude - o tworzeniu gier od podstaw , jeśli jeszcze nie subskrybujesz.

Co to jest płytka
Prawdopodobnie masz pojęcie, czym jest płytka, ale przyjrzyjmy się temu bliżej. Płytka wygląda jak obraz o stałym rozmiarze. Co więcej, jest narysowany w taki sposób, że w porównaniu z innymi płytkami uzyskuje się pojedynczy obraz bez zauważalnych „szwów”. Najłatwiej wyobrazić sobie płytki jako płytki używane do pokrywania ścian lub podłóg. Najprostsza płytka to kwadratowy obraz, symetryczny w pionie i poziomie (widać to na ilustracji). Jeśli połączysz te zdjęcia, otrzymasz duże płótno darń. A jeśli dodać do tego malowniczy obraz dla odmiany jeszcze jeden rodzaj kafelka, powiedzmy, przedstawiający drogę, to możesz już zrobić prymitywną mapę.
Obliczmy teraz koszty jakie będą nam potrzebne do stworzenia mapy komórek o wymiarach 512x512. Załóżmy, że sam kafelek będzie miał wymiary 32x32 piksele, wówczas zajmie 1024 bajty w pamięci - 1 kilobajt. Po obliczeniach okazuje się, że najprostsza mapa zajmuje około 262 kilobajtów pamięci plus pamięć do przechowywania obrazów samych płytek. Gdybyśmy jednak ręcznie narysowali obszar tej samej wielkości, musielibyśmy postawić 268 megabajtów (!) na ołtarzu postępu technicznego. I to pomimo tego, że dla uproszczenia wziąłem tryb 256 kolorów. Oczywiste jest, że nawet teraz nie każdy komputer ma taką ilość pamięci, dlatego struktura kafelkowa map jest stosowana w zdecydowanej większości gier dwuwymiarowych i wystarczającej liczbie gier trójwymiarowych.
Płytki prostokątne i kwadratowe dobrze nadają się do przedstawienia widoku z lotu ptaka, ale istnieje inny rodzaj rzutowania zwany izometrią. Stosuje się go, gdy konieczne jest nadanie poczucia objętości, głębi, wykonanie pseudo-3D. Dlatego systemy izometryczne są czasami nazywane 2,5D. O co tu chodzi? Teraz płytka będzie wyglądać na obróconą pod jednym kątem w stronę widza i jakby wchodząc głębiej (spójrz na ilustrację). Obraz z natury dwuwymiarowy nabiera trzeciego wymiaru. W takim przypadku wymiary kwadratu (płytki) określa się w następujący sposób:
1. Długość — od lewego do prawego punktu obrazu.
2. Szerokość - od „najdalszego” do „najbliższego” punktu widza.
3. Wysokość - „grubość” płytki.
Aby uzyskać efekt objętości, szerokość powinna wynosić w przybliżeniu połowę długości. Eksperymentując z tą zależnością, wydaje się, że obracasz „płytkę” w trójwymiarowej przestrzeni, wybierając pożądaną projekcję. W tym celu przydatne jest użycie pewnego rodzaju analogu studyjnego 3D. Utwórz tam płytkę, wybierz jej położenie, a następnie zmierz boki i powstałe proporcje.
Ale jak mogę teraz rysować?
taki kafelek na ekranie? W końcu zwykłe funkcje rysowania są przyzwyczajone do wyświetlania prostokątnego obszaru i radzą sobie bardzo dobrze. Problem ten rozwiązuje się za pomocą masek. Na ilustracji widać, że kontury płytki wpadają w biały obszar, a to, co pozostaje na zewnątrz, jest pomalowane na czarno i tworzy prostokąt. Prowadzi to do powstania zasady szablonu: obraz nakładany jest na maskę i na „płótno”, a tylko te punkty, które mieszczą się w obrębie biały kolor. Nawet standardowe Funkcje rysowania systemu Windows są przeszkolone do robienia tego typu rzeczy, nie mówiąc już o funkcjach DirectX. Jednocześnie użycie masek pozwala na tworzenie innych efektów. Na przykład możesz narysować tylko głowę płytki, odrzucając jej wysokość. Lub utwórz różne sekcje trawy, używając tylko jednego zdjęcia. Jeśli stworzymy maskę składającą się wyłącznie z otworów i wykorzystamy ją do wyeksponowania płytki z trawą w miejsce istniejącej płytki innego typu, uzyskamy płynne przejście z jednej powierzchni na drugą. Podobną technikę można zastosować w wielu przypadkach, a maski „dziurowe” można generować losowo. Wtedy nikt nie zgadnie, że Twój krajobraz nie jest wstępnie renderowany. Efektem jest swego rodzaju multiteksturowanie: nałożenie dwóch wzajemnie przezroczystych obrazów na jeden obszar. To prawda, że ​​zajmuje to sporo czasu komputera.
W najprostszym przypadku wysokość płytki wynosi zero i nie jest obliczana. Jeśli jednak użyjemy tylko takich „cegieł”, wówczas osiągniemy stworzenie najlepszy scenariusz przyjemne oczyszczenie. Stosując różne wysokości, uzyskamy bardziej realistyczny krajobraz, ze ścianami i wzgórzami. Oczywiście wyświetlenie takich „klocków” na ekranie będzie trudniejsze. Powinniśmy teraz zapoznać się z koncepcją linii bazowej kafelka.
Linia bazowa- jest to miejsce styku płytki z „podłożem”. Są one wyróżnione na zdjęciu różowy. Linię bazową można umieścić w dowolnym miejscu linii pionowej, ponieważ ten sam obraz można zastosować do ścian o różnych rozmiarach. Następnie na mapie rozmieszczenia płytek wyświetlane są linie bazowe, a same płytki zaczynają być rysowane z wyższej pozycji.

2Dfx

Sprawdziliśmy już, jakie efekty można uzyskać przy użyciu kilku warstw płytek. W prawdziwych grach
cała mapa jest wielowarstwowa, jak przysłowiowy placek: pierwsza warstwa- to jest ziemia, kamienie, błoto, woda i tym podobne; druga warstwa- wszelkie peryferia, takie jak drzewa, skały, stoły i krzesła; trzecia warstwa- obiekty: ludzie, potwory, klucze i magiczne mikstury.
Możesz dodać więcej warstw dla powyższych efektów, ale zazwyczaj dla uzyskania najlepszej wydajności używa się czterech do pięciu. Przykładowo, w naszym schemacie można dodać czwartą warstwę, aby stworzyć obiekty znajdujące się powyżej poziomu głów postaci, np. dachy domów. Wszyscy spotkaliście się z takim efektem: kiedy bohater zbliża się do budynku, jego dach nagle znika i widać wnętrze budynku. Bardzo łatwo jest zatem zmusić silnik kafelkowy do zaprzestania rysowania czwartej warstwy, aby użytkownik mógł zobaczyć wszystko, co jest pod nią ukryte.
Silniki kafelkowe, które opierają swoją grafikę na zasadzie palet, aktywnie wykorzystują efekt rotacji kolorów. Niech pewna niebieska gamma zostanie użyta do renderowania wody. Następnie zmieniając tę ​​gammę lub odwrotnie, przestawiając indeksy w kafelku, można uzyskać efekt płynącej wody. Ta sama sztuczka dotyczy innych powierzchni. Powiedzmy, że w jaskini znajdują się kafelki przedstawiające skałę,
można przyciemnić. A jeśli wręczysz bohaterowi pochodnię i w zależności od jego pozycji rozświetlisz otoczenie, efekt będzie bardzo piękny. Już nawet nie mówię o dynamicznej zmianie dnia i nocy. Zarządzanie paletami jest bardzo zainteresowanie Zapytaj, w dodatku bardzo dobrze zaprojektowany i badano w okresie całkowitego kwitnienia 256, kiedy nikt nie mógł obejść się bez palet. Nawet teraz, gdy kolor mniejszy niż 16 bitów uważany jest za nieprzyzwoity, do przechowywania ikonek używa się własnych formatów opartych na tych samych paletach.
Swoją drogą, kto powiedział, że do wyświetlania kafelków trzeba używać oszukanych procedur DirectDraw? Oczywiście, dla przez długi czas istnienia, opracowano algorytmy dla wielu efektów: dynamicznego oświetlenia, a nawet systemów cząstek. Ale wszystkie działają bardzo wolno. Ale to nie jest rok 1996, a grafika Voodoo jest rzadkością tylko dlatego, że wszyscy ją już wyrzucili. Dlatego bardzo kuszące byłoby wykorzystanie możliwości akceleratora 3D do codziennych potrzeb.
Biblioteki 3D mogą pomóc w tworzeniu teksturowanych wielokątów (tych samych płytek) – co jest najwolniejszym momentem w procedurach 2D. W tym przypadku filtrowanie (czyli artystyczne rozmywanie tekstur) jest oczywistym faktem. Ponadto stają się dostępne wszystkie efekty dostępne tylko w grach 3D: światło, przezroczystość, cienie, przejścia światła i tak dalej. Przedmiot jest na tyle interesujący, że warto w nim ćwiczyć. To może być przyszłość gier opartych na kafelkach.

Tworzenie map
Dowolna mapa jest tablicą określającą lokalizację płytek na ich warstwach, a także ich parametry. Najbardziej prosta mapa jest macierzą MxN, w której każdy element zawiera numer płytki z warunkowo przyjętej sekwencji. Jeśli kiedykolwiek korzystałeś ze strategii 2D lub edytora map RPG (lub pracowałeś w Photoshopie), z łatwością zrozumiesz ten pomysł. Gdy dodawane są nowe warstwy, macierz staje się bardziej złożona, efektem jest zbiór (struktura) macierzy, a wraz z wprowadzeniem jakichkolwiek efektów otrzymujemy własny format mapy, który zajmuje na dysku więcej niż jeden megabajt.
Płytkom nie trzeba nadawać kolejnych numerów. Wręcz przeciwnie, dobrze byłoby zacząć od podzielenia całego szeregu liczbowego na kilka przedziałów. Przykładowo zakres od 0 do 63 obejmuje zwykłe płytki, po których można chodzić (grunt, płyty). Od 63 do 127 - nieprzeniknione zarośla dżungli, ściany i inne stałe obiekty. Kolejnym interwałem są wody jezior i bagien, a w końcu specjalne grupy, które wykonują dowolne akcje, gdy bohater na nie „nadepnie”: portale, pułapki itp. Teraz, gdy Photoshop tworzy grafikę, przypisujesz numery nowicjuszom na podstawie przyjęte zasady, a w przyszłości uwolnisz się od wielu problemów związanych z określeniem przejezdności danego obszaru lub tym, jak zareagować, gdy bohater wejdzie do portalu.
Podczas rysowania mapy na początku możesz mieć problemy z narysowaniem kafelków izometrycznych, ponieważ są one tak „zakrzywione”, że nie wiadomo, gdzie narysować jedną, a kontynuować drugą. Trudności mogą pojawić się przy programowaniu płynnego przewijania lub przycinania fragmentów mapy przy ekranie. Nawiasem mówiąc, najlepiej jest tworzyć rozmiary płytek w potędze dwójki (16x16 lub 32x32), co znacznie pomaga zarówno Tobie, jak i procesorowi podczas obliczeń.

To samo dotyczy rozmiaru karty. Powinien być możliwie kwadratowy, a jego wymiary należy podzielić na wielkość składowych „cegieł”. W ten sposób podczas wykonywania obliczeń nigdy nie będziesz mieć wartości ułamkowych, z którymi nie da się pracować. Dlatego większość kart mają wymiary takie jak 128 x 128 lub 512 x 512.
Swoją drogą poruszanie się postaciami po mapie izometrycznej też ma swój sens. Przecież nasza mapa jest obracana „w głąb”, a jej bezwzględny rozmiar w pionie jest dwa razy mniejszy niż w poziomie. Dlatego każdy poruszający się obiekt musi odpowiednio poruszać się „w górę”. Generalnie trzeba tu stosować wzory, ale w najprostszym przypadku na dwa kroki w bok przypada jeden stopień w głąb. Jeśli interesują Cię dokładne obliczenia, łatwo je znajdziesz w Internecie, a w skrajnych przypadkach poproś o poradę. To samo dotyczy każdego ruchu w izometrii, który ma miejsce nawet w całkowicie płaskiej wyprawie.
Na szczęście wszystkie te pytania już dawno przestały być klasyfikowane jako mało zbadane technologie, a w Internecie jest mnóstwo podręczników na temat programowania izometrycznych silników 2D. Radzę zajrzeć do sekcji artykułów na stronach takich jak www.gamedev.net I www.flipcode.com lub po prostu wpisz odpowiednie słowa kluczowe w wyszukiwarce podobnej do Yahoo.

Izometryczny

Cóż, dla tych, którzy lubią „majstrować przy programach”, specjalnie umieściliśmy w kompaktowym silniku o nazwie Izometryczny. Kumuluje wszystko, co zostało powiedziane powyżej. W przeciwieństwie do większości silników 3D i projektantów gier, które zostały sprawdzone w przeszłości „Samopale”, ten silnik nie ma na celu być podstawą twojej gry. Jego celem jest przede wszystkim zobaczenie w praktyce, jak rozwiązuje się wszelkiego rodzaju pytania teoretyczne. Silnik jest w całości wpisany Wizualny C++, posiada kod źródłowy i własny edytor poziomów. Jeśli ty
Jeśli nie interesuje Cię programowanie, nadal możesz wędrować po poziomie testowym, niczego nie kompilując.
Pod względem funkcji IsometriX może wydawać się więcej niż skromny: 640x480 w 8-bitowym kolorze oczywiście tak nie jest. Ale jak powiedziałem, jest to raczej przykład, z którego można dowiedzieć się, jak pracować z mapami, przesuwać postacie, sprawdzać kolizje i robić wiele więcej. Poza tym wszystko działa dobrze w Windows 9x/2000 i najprawdopodobniej będzie działać również w XP.

Jako słowo pożegnalne


Cokolwiek mówią, dwuwymiarowe
silniki kafelkowe są nadal najbardziej żywe dzisiaj. Żadna gra 3D nie może się jeszcze równać z klasycznymi grami 2D pod względem szczegółowości i piękna rysunku. Weźmy na przykład Fallout Tactics – gra ta wykorzystuje być może najbardziej postępowe osiągnięcia w dziedzinie 2D. I nikt nie odważyłby się nazwać grafiki tej gry biedną.
Ponadto płytki idealnie nadają się do tworzenia ogromnych światów. Korzystając z segmentacji, gdy mapa jest podzielona na kilka części, z których każda jest dynamicznie ładowana, można tworzyć mapy o wręcz fantastycznych rozmiarach. Jest to aktywnie wykorzystywane w grach RPG. To kolejny czynnik, dla którego programiści nie spieszą się z wkraczaniem w świat akceleratorów i multiteksturowania.
I wreszcie, grafika kafelkowa jest znacznie łatwiejsza do nauczenia niż jakikolwiek silnik 3D (chociaż może to być mój subiektywna opinia). A nauka obsługi duszków za pomocą DirectDraw jest nieporównywalnie łatwiejsza i przejrzystsza niż Direct3D, a nawet OpenGL. Dlatego nie próbuj spieszyć się od razu na linię frontu. Być może powinieneś zajrzeć także do starego, dobrego świata 2D. No, może trochę 2,5D...
  • Tłumaczenie

W tym poście opiszę dwa algorytmy tworzenia skomplikowanych światów proceduralnych z prostych zestawów kolorowych płytek w oparciu o ograniczenia dotyczące rozmieszczenia tych płytek. Pokażę, jak dzięki starannemu zaprojektowaniu tych zestawów klocków można stworzyć interesującą, proceduralnie generowaną zawartość, taką jak krajobrazy z miastami lub lochy ze złożonymi strukturami wewnętrznymi. Poniższy film przedstawia tworzenie systemu świat proceduralny oparta na zasadach zakodowanych w 43 kolorowych kafelkach.


Poniższy obrazek przedstawia zestaw płytek, na podstawie których został wygenerowany świat z filmu. Świat zaopatrzony jest w notatki, które pomogą Ci wyobrazić sobie go w rzeczywistym środowisku.


Możemy zdefiniować kafelkowanie jako skończoną siatkę, w której każdy z kafelków znajduje się w swojej własnej komórce siatki. Prawidłowy świat definiujemy jako świat, w którym kolory wzdłuż krawędzi sąsiednich płytek powinny być takie same.
Płytki mają tylko jedno żelazna zasada: Kolory krawędzi płytek muszą się zgadzać. W oparciu o tę zasadę rozwija się cała struktura wysokiego szczebla.

Prawidłowe ułożenie płytek wygląda następująco:

Jest to kafelek, który powinien przedstawiać mapę z wodą, wybrzeżami, trawą, miastami z budynkami (niebieskie prostokąty) i górami z ośnieżonymi szczytami. Czarne linie pokazują granice pomiędzy płytkami.

Myślę, że jest to ciekawy sposób opisywania i tworzenia światów, ponieważ bardzo często algorytmy generowania proceduralnego przyjmują podejście odgórne. Na przykład systemy L wykorzystują rekurencyjny opis obiektu, w którym duże szczegóły wysokiego poziomu są określane wcześniej niż szczegóły niskiego poziomu. Nie ma nic złego w tym podejściu, ale myślę, że interesujące jest tworzenie zestawów klocków, które mogą kodować tylko proste relacje niskiego poziomu (np. woda morska i trawę powinny być oddzielone liniami brzegowymi, budynki powinny mieć jedynie wypukłe narożniki pod kątem 90 stopni) i zwracać uwagę na pojawienie się wzorów na wysokim poziomie (np. budynków kwadratowych).

Kafelkowanie jest problemem spełniania więzów NP-zupełnych

Dla czytelnika zaznajomionego z problemami spełniania ograniczeń (CSP) jest już oczywiste, że układanie skończonego świata jest CSP. W VMA mamy wiele zmiennych, wiele wartości, jakie może przyjąć każda zmienna (tzw. jej dziedzinę) oraz wiele ograniczeń. W naszym przypadku zmienne są współrzędnymi na mapie, obszarem definicji każdej zmiennej jest zestaw klocków, a ograniczenia są takie, że krawędzie płytek muszą pokrywać się z krawędziami sąsiadów.

Intuicyjnie zadanie prawidłowego utworzenia nietrywialnego kafelkowania jest trudne, ponieważ zestawy klocków mogą kodować dowolne, rozbudowane zależności. Kiedy rozważamy zbiór płytek jako całość, to z formalnego punktu widzenia jest to problem spełniania ograniczeń NP-zupełnych. Naiwny algorytm układania płytek polega na wyczerpującym przeszukiwaniu przestrzeni płytek i działa w czasie wykładniczym. Jest nadzieja, że ​​możemy tworzyć ciekawe światy oparte na zestawach klocków, rozwiązywane przez wyszukiwanie, które można przyspieszyć za pomocą heurystyki. Inną opcją jest utworzenie fragmentów, które są w przybliżeniu poprawne, ale zawierają niewielką liczbę nieprawidłowych lokalizacji. Znalazłem dwa algorytmy, które dobrze sprawdzają się w przypadku kilku interesujących zestawów klocków i opiszę je poniżej.

Metoda 1: Chciwy układ z odgałęzieniami wstecznymi

Wybieramy losowe miejsca i umieszczamy tam odpowiednie płytki. Jeśli utkniemy, usuwamy niektóre z nich i próbujemy ponownie.

Zainicjuj całą mapę jako NIEROZWIĄZANA

Dopóki na mapie znajdują się NIEROZWIĄZANE kafelki
czy na mapie można umieścić odpowiednią płytkę
T<- коллекция всех возможных расположений подходящих тайлов
l<- случайная выборка из t, взвешенная по вероятностям тайлов
umieść l na mapie
W przeciwnym razie
wybierz losowy kafelek NIEROZWIĄZONY i przypisz status NIEROZWIĄZONY wszystkim jego sąsiadom


Moja pierwsza próba stworzenia kafelka z zestawu płytek polegała na pozostawieniu całej siatki w nierozwiązanym stanie, a następnie iteracyjnie umieszczałem losową płytkę w odpowiednim miejscu lub, jeśli nie było odpowiednich lokalizacji, przydzielałem mały obszar obok nierozwiązaną płytkę do stanu „nierozwiązanego” i dalej zachłannie układał płytki. „Greedy Layout” to strategia polegająca na układaniu płytek tak długo, jak ich krawędzie odpowiadają już ułożonym płytkom, niezależnie od tego, czy takie umieszczenie spowodowałoby częściowe ułożenie płytek, których nie można ukończyć bez wymiany już ułożonych płytek. Gdy dojdzie do takiej sytuacji i nie będziemy już mogli układać płytek, musimy usunąć część wcześniej ułożonych płytek. Nie wiemy jednak, które najlepiej usunąć, bo gdybyśmy mogli rozwiązać ten problem, to prawdopodobnie rozwiązalibyśmy w pierwszej kolejności także problem prawidłowego ułożenia płytek. Aby dać algorytmowi kolejną szansę na znalezienie odpowiedniego kafelka dla danego obszaru, ustawiamy wszystkie kafelki wokół nierozwiązanego punktu na stan „nierozwiązany” i kontynuujemy strategię zachłannego umieszczania. Mamy nadzieję, że prędzej czy później zostaną znalezione odpowiednie płytki, ale nie ma żadnych gwarancji. Algorytm będzie działał do momentu znalezienia prawidłowego kafelka, co może zająć nieskończony czas. Nie ma możliwości wykrycia, że ​​zestawu klocków nie da się rozwiązać.

Nie ma gwarancji, że algorytm zakończy swoją pracę. Prosty zestaw płytek składający się z dwóch płytek, które nie mają wspólnych kolorów, spowoduje, że algorytm przejdzie w nieskończoną pętlę. Jeszcze prostszym przypadkiem byłaby jedna płytka z różnymi kolorami na górze i na dole. Rozsądne byłoby znalezienie sposobu na wykrycie, że zestawy płytek nie tworzą prawidłowych płytek. Można powiedzieć, że zestaw klocków jest zdecydowanie poprawny, jeśli może pokryć nieskończoną płaszczyznę. W niektórych przypadkach można łatwo udowodnić, że zestaw płytek może, ale nie musi, pokrywać nieskończoną płaszczyznę, ale ogólnie rzecz biorąc, problemu tego nie da się rozwiązać. Dlatego zadaniem projektanta jest stworzenie zestawu płytek, który umożliwi wykonanie prawidłowego ułożenia płytek.

Algorytm ten nie jest w stanie znaleźć dobrych rozwiązań dla zestawu lochów z filmu na początku postu. Dobrze sprawdza się w przypadku prostszych zestawów płytek. Chcielibyśmy dowiedzieć się, jak rozwiązywać bardziej złożone układy kafelków z wieloma możliwymi rodzajami przejść między kafelkami i różnymi zakodowanymi zasadami (na przykład, że drogi powinny zaczynać się i kończyć obok budynków).

Potrzebujemy algorytmu, który potrafi patrzeć w przyszłość i tworzyć układy płytek, mając jednocześnie świadomość tego, w jaki sposób te układy są otwarte na przyszłe rozmieszczenie płytek. Pozwoli nam to skutecznie rozwiązywać złożone zestawy klocków.

Pod względem spełnienia ograniczeń

Algorytm ten jest podobny do wyszukiwania wstecznego. Na każdym kroku staramy się przypisać jedną zmienną. Jeżeli nie jest to możliwe, usuwamy przypisanie zmiennej i wszystkich zmiennych, które są z nią powiązane ograniczeniami. Nazywa się to „backjumpingiem” i różni się od cofania, w którym cofamy przypisanie jednej zmiennej na raz, dopóki nie będziemy mogli kontynuować prawidłowego przypisania. Wracając, generalnie cofamy przypisanie zmiennych w odwrotnej kolejności ich przypisania, natomiast cofając się, cofamy przypisanie zmiennych zgodnie ze strukturą danego problemu. Logiczne jest, że jeśli nie możemy umieścić żadnego kafelka w określonym miejscu, to musimy zmienić położenie sąsiednich kafelków, ponieważ ich rozmieszczenie stworzyło sytuację nierozwiązywalną. Zamiast tego powrót może spowodować cofnięcie przypisania zmiennych, które są od siebie odległe przestrzennie, ale zostały niedawno przypisane.

W tym wyszukiwaniu nie są stosowane żadne techniki lokalnej integralności. Oznacza to, że nie próbujemy umieszczać płytek, które później doprowadziłyby do sytuacji nierozwiązywalnej, nawet jeden krok poszukiwań później. Możliwe jest przyspieszenie wyszukiwania poprzez śledzenie wpływu, jaki lokalizacja będzie miała na możliwe lokalizacje oddalone o kilka pól od bieżącego punktu. Mamy nadzieję, że zapobiegnie to konieczności spędzania tak dużej ilości czasu przez wyszukiwarkę na cofaniu swojej pracy. Dokładnie to robi nasz algorytm.

Metoda 2: Lokalizacja z największymi ograniczeniami i dystrybucją informacji lokalnych

Zachowujemy rozkład prawdopodobieństwa płytek w każdym punkcie, wprowadzając nielokalne zmiany w tych rozkładach przy podejmowaniu decyzji o lokalizacji. Nigdy nie wracamy.
Następnie opiszę algorytm, który gwarantuje wykonanie i daje bardziej przyjemne wizualnie wyniki dla wszystkich testowanych przeze mnie płytek. Dodatkowo może tworzyć niemal prawidłowe układy płytek w przypadku znacznie bardziej złożonych zestawów płytek. Kompromis polega na tym, że ten algorytm nie gwarantuje, że wynik będzie zawsze prawidłowy. Sekcja Optymalizacje opisuje optymalizacje, które umożliwiają szybsze działanie tego algorytmu, nawet w przypadku większych zestawów klocków i map.

Trudność w utworzeniu prawidłowego kafelka zależy w dużej mierze od liczby przejść wymaganych do przejścia między dwoma typami kafelków. Prosty zestaw klocków może zawierać tylko piasek, wodę i trawę. Jeśli trawa i woda nie mogą się ze sobą stykać, to między nimi musi nastąpić przejście w piasek. Jest to prosty przykład, który można łatwo rozwiązać za pomocą algorytmu przedstawionego wcześniej. W bardziej złożonym przypadku może występować wiele wbudowanych poziomów typów kafelków. Na przykład możemy mieć głęboką wodę, wodę, piasek, trawę, wysoką równinę, górę i ośnieżony szczyt. Aby wszystkie tego typu kafelki pojawiły się na mapie, musi nastąpić siedem przejść, przy założeniu, że te typy nie mogą się ze sobą stykać inaczej niż w określonej przeze mnie kolejności. Dodatkową złożoność można dodać, tworząc kafelki, które w naturalny sposób tworzą rozległe zależności między kafelkami, takie jak drogi, które muszą zaczynać się i kończyć w pobliżu określonych typów kafelków.

Intuicyjnie algorytm tego zadania powinien potrafić „patrzeć w przyszłość” i uwzględniać przynajmniej kilka przejść, które mogą być konsekwencją wybranej lokalizacji. Aby to zaimplementować, możesz pomyśleć o mapie kafelków jako o rozkładzie prawdopodobieństwa dla płytek w każdym punkcie. Kiedy algorytm umieszcza płytkę, aktualizuje rozkłady prawdopodobieństwa wokół tej płytki w odpowiedzi na jej lokalizację w taki sposób, że zwiększa prawdopodobieństwo sąsiadujących płytek, które prawdopodobnie będą zgodne z bieżącym układem.

Na przykład, jeśli na mapie znajduje się kafelek wody, to kafle obok niego muszą zawierać wodę. Płytki obok nich mogą również zawierać wodę, ale są też inne możliwości, np. trawa, jeśli obok oryginalnej płytki wody zostanie umieszczone wybrzeże. Im dalej odejdziemy od ustawionej płytki, tym więcej rodzajów płytek stanie się możliwych. Aby skorzystać z tej obserwacji, możemy policzyć, na ile sposobów możemy dotrzeć do lokalizacji każdej płytki obok oryginalnej płytki. W niektórych przypadkach tylko pojedyncza sekwencja przejść może doprowadzić do przejścia z jednej płytki na drugą na zadaną odległość. W innych przypadkach może istnieć wiele różnych sekwencji przejść. Po ułożeniu kafelka możemy wyznaczyć rozkłady prawdopodobieństwa kafelków w sąsiednich punktach, licząc na ile sposobów możemy wykonać przejście z ułożonego kafelka na sąsiednie kafelki. „Patrzenie w przyszłość” realizowane przez ten algorytm polega na śledzeniu takiej liczby przejść i traktowaniu ich jako rozkładów prawdopodobieństwa, z których można wybrać nowe płytki do umieszczenia.


Na każdym etapie algorytm sprawdza wszystkie nierozwiązane lokalizacje płytek, z których każda ma rozkład prawdopodobieństwa na płytkach, i wybiera jedną lokalizację, która „zbiega się” na płytce. Wybiera rozkład z mapy o minimalnej entropii. Rozkłady wielomianowe o niskiej entropii mają zwykle prawdopodobieństwa skupione w kilku modach, więc zbieżność tych pierwszych skutkuje efektem lokalizacji płytek, które mają już pewne ograniczenia. Dlatego algorytm umieszcza kafelki obok tych, które ułożyliśmy jako pierwsze.

Jest to najwydajniejszy algorytm jaki udało mi się zaimplementować do tego zadania. Ma jeszcze jedną zaletę: po wykonaniu tworzy piękne wizualizacje. Być może istnieje sposób na ulepszenie tego algorytmu poprzez wprowadzenie jakiejś formy cofania się. Jeśli w wynikowym wykończonym kafelku znajduje się nieprawidłowy punkt, cofnięcie lokalizacji sąsiednich płytek i ponowne próbkowanie z wynikowych rozkładów w ich punktach może pozwolić na znalezienie rozwiązania dla wykończonego kafelka. Oczywiście jeśli będziesz chciał kontynuować wyszukiwanie aż znajdziesz odpowiednie kafelki, przekroczysz podany gwarantowany czas realizacji.

Optymalizacje

Najważniejszą operacją tej metody jest aktualizacja prawdopodobieństw wokół pozycjonowanej płytki. Jednym ze sposobów byłoby policzenie możliwych przejść „na zewnątrz” z pozycjonowanej płytki za każdym razem, gdy jest ona pozycjonowana. Będzie to bardzo powolne, ponieważ dla każdego punktu na mapie, do którego będą się rozprzestrzeniać nowe prawdopodobieństwa, trzeba będzie wziąć pod uwagę wiele par przejściowych. Oczywistą optymalizacją byłoby nierozprzestrzenianie się na całą mapę. Bardziej interesującą optymalizacją byłoby buforowanie wpływu, jaki każdy układ kafelków będzie miał na punkty wokół niego, tak aby każdy układ kafelków po prostu przeprowadzał wyszukiwanie, aby sprawdzić, jakiego rodzaju zmiany układ wprowadza w pobliskich prawdopodobieństwach, a następnie stosował tę zmianę za pomocą kilka prostych operacji. Poniżej opiszę moją implementację tej metody optymalizacji.

Wyobraź sobie kafelek umieszczony na całkowicie pustej mapie. To ustawienie zaktualizuje prawdopodobieństwo sąsiadujących płytek. Możemy postrzegać te zaktualizowane rozkłady jako posiadające poprzedni rozkład podany przez poprzednie lokalizacje kafelków. Jeśli ułożonych zostanie wiele płytek, poprzedni przydział zostanie udostępniony. Przybliżam to późniejsze prawdopodobieństwo, biorąc pod uwagę poprzednie połączenie jako iloczyn rozkładów dla każdej lokalizacji w przeszłości.


Aby to zaimplementować, wyobraźmy sobie, że umieszczenie kafelka na pustej mapie powoduje znaczące zmiany w rozmieszczeniu sąsiednich punktów na mapie. Zadzwonię do tych aktualizacji kula płytka, czyli sfera wpływów płytki rzucona wokół niej, gdy zostanie umieszczona na pustej mapie. Kiedy dwie płytki zostaną umieszczone obok siebie, ich kule oddziałują na siebie i tworzą ostateczne rozkłady, na które wpływają oba rozmieszczenia. Biorąc pod uwagę, że w pobliżu danej nierozwiązanej lokalizacji może znajdować się wiele płytek, będzie istniała duża liczba oddziałujących na siebie ograniczeń, co powoduje, że decyzja oparta na liczbie w celu określenia prawdopodobieństwa pojawienia się różnych płytek w tym punkcie będzie bardzo powolnym procesem. A co jeśli zamiast tego rozważymy jedynie prosty model interakcji pomiędzy wcześniej obliczonymi sferami płytek, które już znajdowały się na mapie?
Umieszczając płytkę, aktualizuję mapę prawdopodobieństwa dla każdego elementu, mnożąc rozkład sferyczny tej płytki w każdym punkcie mapy przez rozkład już zapisany w tym punkcie mapy. Pomocne może być przyjrzenie się przykładowi tego, co można zrobić z mapą dystrybucji. Załóżmy, że dany punkt na mapie ma obecnie rozkład, który z równym prawdopodobieństwem wybierze trawę lub wodę, i umieszczamy kafelek wody obok tego punktu. Na kuli z wodą z dużym prawdopodobieństwem będzie znajdować się woda obok płytki z wodą, a z niskim prawdopodobieństwem na płytce z trawą. Gdy pomnożymy te rozkłady element po elemencie, otrzymane prawdopodobieństwo pojawienia się wody będzie wysokie, ponieważ jest to iloczyn dwóch wysokich prawdopodobieństw, ale prawdopodobieństwo trawy stanie się niskie, ponieważ jest to iloczyn wysokiego prawdopodobieństwa zapisanego na mapie za pomocą niskie prawdopodobieństwo przechowywane w kuli.
Strategia ta pozwala nam skutecznie przybliżyć wpływ, jaki każda lokalizacja kafelka powinna mieć na mapę prawdopodobieństwa.

Pod względem spełnienia ograniczeń

Aby skutecznie rozwiązywać problemy ze spełnieniem ograniczeń, często mądrze jest śledzić przypisania do innych zmiennych, które stają się niemożliwe w przypadku przypisania do konkretnej zmiennej. Zasada ta nazywana jest wprowadzeniem lokalnych warunków zgodności. Wprowadzenie pewnego rodzaju zgodności lokalnej pozwala uniknąć przypisywania wartości do zmiennej podczas przypisywania niezgodnej wartości do sąsiedniej zmiennej, gdy konieczny będzie powrót. Transformacje takie należą do dziedziny metod propagacji ograniczeń w literaturze dotyczącej CCD. W naszym algorytmie za każdym razem, gdy kładziemy kafelek, rozprowadzamy informację na niewielkim obszarze mapy. Rozpowszechniane informacje informują, które kafelki mogą, a które nie mogą pojawić się w pobliżu. Na przykład, jeśli umieścimy płytkę z górami, wiemy, że dwie płytki od niej nie może znajdować się otwarta płytka z morzem, co oznacza, że ​​prawdopodobieństwo, że płytka z morzem będzie we wszystkich punktach na mapie w odległości dwóch płytek od zlokalizowanej płytki wynosi zero . Informacje te są rejestrowane w obszarach, o których mówiliśmy powyżej. Kule kodują lokalną zgodność, którą chcemy narzucić.

Redukując liczbę możliwych przypisań do sąsiednich płytek, znacznie zmniejszamy przestrzeń poszukiwań, którą algorytm musi przetworzyć po każdym przypisaniu. Wiemy, że w tej małej okolicy prawdopodobieństwo pojawienia się płytek niezgodnych z lokalizacją wynosi zero. Jest to analogiczne do usuwania tych wartości z zakresów zmiennych w tych punktach. Oznacza to, że każda para sąsiadujących punktów w obszarze wokół zlokalizowanej płytki ma w swoim obszarze definicji pewną płytkę, która jest kompatybilna z jakąś płytką nadal znajdującą się w obszarze definicji sąsiadów. Kiedy dwie zmienne są połączone ograniczeniem w problem CR, a ich domeny zawierają tylko wartości spełniające ograniczenie, wówczas mówi się, że mają kompatybilność łukową, co oznacza, że ​​ta metoda jest w rzeczywistości skuteczną strategią wprowadzenia kompatybilności łukowej.

W PCA „najbardziej ograniczona” zmienna w danym przypisaniu częściowym to ta, która ma najmniejszą liczbę możliwych wartości w swojej domenie definicji. Zasada umieszczania kafelka w punkcie mapy o minimalnym rozkładzie entropii jest podobna do przypisywania wartości najbardziej ograniczonej zmiennej w SDC, co jest standardową heurystyką porządkowania zmiennych podczas rozwiązywania SDC za pomocą wyszukiwania.

Manipulacja kafelkami poprzez zmianę prawdopodobieństwa wyboru kafelków

Do tej pory mówiłem tylko o tym, jak stworzyć prawidłowe kafelki, ale oprócz poprawności kafelkowanie może wymagać także innych właściwości. Na przykład możemy chcieć określonego stosunku jednego rodzaju kafelków do drugiego lub możemy chcieć mieć pewność, że nie wszystkie kafelki są tego samego rodzaju, nawet jeśli kafelki są prawidłowe. Aby rozwiązać ten problem, oba opisane przeze mnie algorytmy przyjmują jako dane wejściowe podstawowe prawdopodobieństwo związane z każdą płytką. Im wyższe jest to prawdopodobieństwo, tym większe jest prawdopodobieństwo, że ta płytka będzie obecna w gotowej płytce. Obydwa algorytmy dokonują losowego wyboru ze zbiorów płytek, a ja po prostu dodam wagę do tego losowego wyboru zgodnie z podstawowymi prawdopodobieństwami płytek.

Przykład tej zasady pokazano poniżej. Zmieniając prawdopodobieństwo pojawienia się stałego kafelka wody, mogę kontrolować rozmiar i częstotliwość pojawiania się zbiorników wodnych na mapie.

Stwórz własne zestawy płytek

Krótko:
  • sklonuj moje repozytorium Github
  • zainstaluj Przetwarzanie
  • w folderze data/ repozytorium zmieńtiles.png
  • użyj przetwarzania, aby otworzyć plik wangTiles.pde i kliknij przycisk odtwarzania
Korzystając z kodu opublikowanego na githubie (możesz go modyfikować, ale robisz to na własne ryzyko - większość napisałem w liceum), możesz tworzyć własne zestawy klocków za pomocą edytora obrazów i obserwować, jak narzędzie do kafelkowania tworzy światy za pomocą ich . Po prostu sklonuj repozytorium i edytuj obraz dungeon.png, a następnie użyj Processing, aby uruchomić wangTiles.pde i zobaczyć wygenerowaną animację mapy. Poniżej opiszę „język”, którego wymaga to narzędzie do rozwiązywania płytek.

Specyfikacja zestawu płytek


Płytki ułożone są w siatce 4x4. Każda komórka w lewym górnym obszarze 3x3 zawiera kolorowy kafelek, a pozostałe 7 pikseli zawiera metadane kafelka. Piksel znajdujący się pod środkiem kafelka może zostać pokolorowany na czerwono, aby dodać komentarz do kafelka i wykluczyć go z zestawu klocków. Solver nigdy nie umieści tego na mapie. Górny piksel po prawej stronie kafelka można pomalować na czarno, aby dodać wszystkie cztery obroty kafelków do zestawu płytek. Jest to przydatna funkcja, jeśli chcesz dodać coś w rodzaju kąta istniejącego w czterech orientacjach. Wreszcie najważniejszą częścią znacznika jest piksel w lewym dolnym rogu kafelka. Kontroluje podstawowe prawdopodobieństwo pojawienia się kafelka na mapie. Im ciemniejszy piksel, tym większe prawdopodobieństwo pojawienia się kafelka.

Powiązane prace

Wiele osób zainteresowało się kafelkami Van, czyli zestawami płytek z kolorowymi krawędziami, które muszą pasować do krawędzi płytek, obok których są umieszczone, tak jak płytki, na które patrzymy.

Rozwiązanie „Najbardziej ograniczone rozmieszczenie ze spójnością łuku rozmytego” jest podobne do projektu Wave Function Collapse użytkownika Twittera

Co to jest płytka
Prawdopodobnie masz pojęcie, czym jest płytka, ale przyjrzyjmy się temu bliżej. Płytka wygląda jak obraz o stałym rozmiarze. Co więcej, jest narysowany w taki sposób, że w porównaniu z innymi płytkami uzyskuje się pojedynczy obraz bez zauważalnych „szwów”. Najłatwiej wyobrazić sobie płytki jako płytki używane do pokrywania ścian lub podłóg. Najprostsza płytka to kwadratowy obraz, symetryczny w pionie i poziomie (widać to na ilustracji). Jeśli złożysz te zdjęcia razem, otrzymasz duże płótno z trawą. A jeśli dla urozmaicenia dodasz inny rodzaj kafelka do tego malowniczego obrazu, powiedzmy przedstawiającego drogę, możesz już stworzyć prymitywną mapę.
Obliczmy teraz koszty jakie będą nam potrzebne do stworzenia mapy komórek o wymiarach 512x512. Załóżmy, że sam kafelek będzie miał wymiary 32x32 piksele, wówczas zajmie 1024 bajty w pamięci - 1 kilobajt. Po obliczeniach okazuje się, że najprostsza mapa zajmuje około 262 kilobajtów pamięci plus pamięć do przechowywania obrazów samych płytek. Gdybyśmy jednak ręcznie narysowali obszar tej samej wielkości, musielibyśmy postawić 268 megabajtów (!) na ołtarzu postępu technicznego. I to pomimo tego, że dla uproszczenia wziąłem tryb 256 kolorów. Oczywiste jest, że nawet teraz nie każdy komputer ma taką ilość pamięci, dlatego struktura kafelkowa map jest stosowana w zdecydowanej większości gier dwuwymiarowych i wystarczającej liczbie gier trójwymiarowych. Prosta prostokątna płytka.
Płytki prostokątne i kwadratowe dobrze nadają się do przedstawienia widoku z lotu ptaka, ale istnieje inny rodzaj rzutowania zwany izometrią. Stosuje się go, gdy konieczne jest nadanie poczucia objętości, głębi, wykonanie pseudo-3D. Dlatego systemy izometryczne są czasami nazywane 2,5D. O co tu chodzi? Teraz płytka będzie wyglądać na obróconą pod jednym kątem w stronę widza i jakby wchodząc głębiej (spójrz na ilustrację). Obraz z natury dwuwymiarowy nabiera trzeciego wymiaru. W takim przypadku wymiary kwadratu (płytki) określa się w następujący sposób:
1. Długość — od lewego do prawego punktu obrazu.
2. Szerokość - od „najdalszego” do „najbliższego” punktu widza.
3. Wysokość - „grubość” płytki.
Aby uzyskać efekt objętości, szerokość powinna wynosić w przybliżeniu połowę długości. Eksperymentując z tą zależnością, wydaje się, że obracasz „płytkę” w trójwymiarowej przestrzeni, wybierając pożądaną projekcję. W tym celu przydatne jest użycie pewnego rodzaju analogu studyjnego 3D. Utwórz tam płytkę, wybierz jej położenie, a następnie zmierz boki i powstałe proporcje.
Ale jak mogę teraz rysować? Prosta płytka izometryczna. taki kafelek na ekranie? W końcu zwykłe funkcje rysowania są przyzwyczajone do wyświetlania prostokątnego obszaru i radzą sobie bardzo dobrze. Problem ten rozwiązuje się za pomocą masek. Na ilustracji widać, że kontury płytki wpadają w biały obszar, a to, co pozostaje na zewnątrz, jest pomalowane na czarno i tworzy prostokąt. Otrzymuje się zasadę szablonu: obraz nakłada się na maskę i na „płótno” i przechodzą tylko te punkty, które wpadają w biały kolor. Nawet standardowe funkcje rysowania systemu Windows są przystosowane do tego typu zadań, nie mówiąc już o funkcjach DirectX. Jednocześnie użycie masek pozwala na tworzenie innych efektów. Na przykład możesz narysować tylko głowę płytki, odrzucając jej wysokość. Lub utwórz różne sekcje trawy, używając tylko jednego zdjęcia. Jeśli stworzymy maskę składającą się wyłącznie z otworów i wykorzystamy ją do wyeksponowania płytki z trawą w miejsce istniejącej płytki innego typu, uzyskamy płynne przejście z jednej powierzchni na drugą. Podobną technikę można zastosować w wielu przypadkach, a maski „dziurowe” można generować losowo. Wtedy nikt nie zgadnie, że Twój krajobraz nie jest wstępnie renderowany. Efektem jest swego rodzaju multiteksturowanie: nałożenie dwóch wzajemnie przezroczystych obrazów na jeden obszar. To prawda, że ​​zajmuje to sporo czasu komputera.
W najprostszym przypadku wysokość płytki wynosi zero i nie jest obliczana. Jeśli jednak zastosujemy tylko takie „cegiełki”, to w najlepszym wypadku uzyskamy przyjemną polanę. Stosując różne wysokości, uzyskamy bardziej realistyczny krajobraz, ze ścianami i wzgórzami. Oczywiście wyświetlenie takich „klocków” na ekranie będzie trudniejsze. Powinniśmy teraz zapoznać się z koncepcją linii bazowej kafelka.
Linia bazowa- jest to miejsce styku płytki z „podłożem”. Na zdjęciu są one zaznaczone na różowo. Linię bazową można umieścić w dowolnym miejscu linii pionowej, ponieważ ten sam obraz można zastosować do ścian o różnych rozmiarach. Następnie na mapie rozmieszczenia płytek wyświetlane są linie bazowe, a same płytki zaczynają być rysowane z wyższej pozycji.

2Dfx

Sprawdziliśmy już, jakie efekty można uzyskać przy użyciu kilku warstw płytek. W prawdziwych grach W ten sposób obliczane są rozmiary płytek. cała mapa jest wielowarstwowa, jak przysłowiowy placek: pierwsza warstwa- to jest ziemia, kamienie, błoto, woda i tym podobne; druga warstwa- wszelkie peryferia, takie jak drzewa, skały, stoły i krzesła; trzecia warstwa- obiekty: ludzie, potwory, klucze i magiczne mikstury.
Możesz dodać więcej warstw dla powyższych efektów, ale zazwyczaj dla uzyskania najlepszej wydajności używa się czterech do pięciu. Przykładowo, w naszym schemacie można dodać czwartą warstwę, aby stworzyć obiekty znajdujące się powyżej poziomu głów postaci, np. dachy domów. Wszyscy spotkaliście się z takim efektem: kiedy bohater zbliża się do budynku, jego dach nagle znika i widać wnętrze budynku. Bardzo łatwo jest zatem zmusić silnik kafelkowy do zaprzestania rysowania czwartej warstwy, aby użytkownik mógł zobaczyć wszystko, co jest pod nią ukryte.
Silniki kafelkowe, które opierają swoją grafikę na zasadzie palet, aktywnie wykorzystują efekt rotacji kolorów. Niech pewna niebieska gamma zostanie użyta do renderowania wody. Następnie zmieniając tę ​​gammę lub odwrotnie, przestawiając indeksy w kafelku, można uzyskać efekt płynącej wody. Ta sama sztuczka dotyczy innych powierzchni. Powiedzmy, że w jaskini znajdują się kafelki przedstawiające skałę, Płytka i jego maska. Podczas rysowania na ekranie
widoczna jest tylko część wpadająca w biel
obszar maski. można przyciemnić. A jeśli wręczysz bohaterowi pochodnię i w zależności od jego pozycji rozświetlisz otoczenie, efekt będzie bardzo piękny. Już nawet nie mówię o dynamicznej zmianie dnia i nocy. Zarządzanie paletami jest bardzo ciekawym zagadnieniem, w dodatku zostało bardzo dobrze opracowane i zbadane w okresie całkowitego kwitnienia 256, kiedy nikt nie mógł się obejść bez palet. Nawet teraz, gdy kolor mniejszy niż 16 bitów uważany jest za nieprzyzwoity, do przechowywania ikonek używa się własnych formatów opartych na tych samych paletach.
Swoją drogą, kto powiedział, że do wyświetlania kafelków trzeba używać oszukanych procedur DirectDraw? Oczywiście przez długi okres istnienia opracowano algorytmy dla wielu efektów: dynamicznego oświetlenia, a nawet systemów cząstek. Ale wszystkie działają bardzo wolno. Ale to nie jest rok 1996, a grafika Voodoo jest rzadkością tylko dlatego, że wszyscy ją już wyrzucili. Dlatego bardzo kuszące byłoby wykorzystanie możliwości akceleratora 3D do codziennych potrzeb.
Biblioteki 3D mogą pomóc w tworzeniu teksturowanych wielokątów (tych samych płytek) – co jest najwolniejszym momentem w procedurach 2D. W tym przypadku filtrowanie (czyli artystyczne rozmywanie tekstur) jest oczywistym faktem. Ponadto stają się dostępne wszystkie efekty dostępne tylko w grach 3D: światło, przezroczystość, cienie, przejścia światła i tak dalej. Przedmiot jest na tyle interesujący, że warto w nim ćwiczyć. To może być przyszłość gier opartych na kafelkach.

Tworzenie map
Dowolna mapa jest tablicą określającą lokalizację płytek na ich warstwach, a także ich parametry. Najprostszą mapą jest macierz MxN, gdzie każdy element zawiera numer kafelka z umownie przyjętej sekwencji. Jeśli kiedykolwiek korzystałeś ze strategii 2D lub edytora map RPG (lub pracowałeś w Photoshopie), z łatwością zrozumiesz ten pomysł. Gdy Identyczne płytki mogą różnić się wysokością,
gdy stosowana jest metoda podstawowa. dodawane są nowe warstwy, macierz staje się bardziej złożona, efektem jest zbiór (struktura) macierzy, a wraz z wprowadzeniem jakichkolwiek efektów otrzymujemy własny format mapy, który zajmuje na dysku więcej niż jeden megabajt.
Płytkom nie trzeba nadawać kolejnych numerów. Wręcz przeciwnie, dobrze byłoby zacząć od podzielenia całego szeregu liczbowego na kilka przedziałów. Przykładowo zakres od 0 do 63 obejmuje zwykłe płytki, po których można chodzić (grunt, płyty). Od 63 do 127 - nieprzeniknione zarośla dżungli, ściany i inne stałe obiekty. Kolejnym interwałem są wody jezior i bagien, a w końcu specjalne grupy, które wykonują dowolne akcje, gdy bohater na nie „nadepnie”: portale, pułapki itp. Teraz, gdy Photoshop tworzy grafikę, przydzielasz numery nowicjuszom na podstawie przyjętych zasad, a w przyszłości uwalniasz się od wielu problemów związanych z określeniem przejezdności terenu czy tego, jak zareagować, gdy bohater wejdzie do portalu.
Podczas rysowania mapy na początku możesz mieć problemy z narysowaniem kafelków izometrycznych, ponieważ są one tak „zakrzywione”, że nie wiadomo, gdzie narysować jedną, a kontynuować drugą. Trudności mogą pojawić się przy programowaniu płynnego przewijania lub przycinania fragmentów mapy przy ekranie. Nawiasem mówiąc, najlepiej jest tworzyć rozmiary płytek w potędze dwójki (16x16 lub 32x32), co znacznie pomaga zarówno Tobie, jak i procesorowi podczas obliczeń. To samo dotyczy rozmiaru karty. Powinien być możliwie kwadratowy, a jego wymiary należy podzielić na wielkość składowych „cegieł”. W ten sposób podczas wykonywania obliczeń nigdy nie będziesz mieć wartości ułamkowych, z którymi nie da się pracować. Dlatego większość kart ma wymiary takie jak 128x128 lub 512x512.
Swoją drogą poruszanie się postaciami po mapie izometrycznej też ma swój sens. Przecież nasza mapa jest obracana „w głąb”, a jej bezwzględny rozmiar w pionie jest dwa razy mniejszy niż w poziomie. Dlatego każdy poruszający się obiekt musi odpowiednio poruszać się „w górę”. Generalnie trzeba tu stosować wzory, ale w najprostszym przypadku na dwa kroki w bok przypada jeden stopień w głąb. Jeśli interesują Cię dokładne obliczenia, łatwo je znajdziesz w Internecie, a w skrajnych przypadkach poproś o poradę. To samo dotyczy każdego ruchu w izometrii, który ma miejsce nawet w całkowicie płaskiej wyprawie.
Na szczęście wszystkie te pytania już dawno przestały być klasyfikowane jako mało zbadane technologie, a w Internecie jest mnóstwo podręczników na temat programowania izometrycznych silników 2D. Radzę zajrzeć do sekcji artykułów na stronach takich jak www.gamedev.net I www.flipcode.com lub po prostu wpisz odpowiednie słowa kluczowe w wyszukiwarce podobnej do Yahoo.

Izometryczny

Cóż, dla tych, którzy lubią „majstrować przy programach”, specjalnie umieściliśmy w kompaktowym silniku o nazwie Izometryczny. Kumuluje wszystko, co zostało powiedziane powyżej. W przeciwieństwie do większości silników 3D i projektantów gier, które zostały sprawdzone w przeszłości „Samopale”, ten silnik nie ma na celu być podstawą twojej gry. Jego celem jest przede wszystkim zobaczenie w praktyce, jak rozwiązuje się wszelkiego rodzaju pytania teoretyczne. Silnik jest w całości wpisany Wizualny C++, posiada kod źródłowy i własny edytor poziomów. Jeśli nie interesuje Cię programowanie, nadal możesz wędrować po poziomie testowym, niczego nie kompilując.
Pod względem funkcji IsometriX może wydawać się więcej niż skromny: 640x480 w 8-bitowym kolorze oczywiście tak nie jest. Ale jak powiedziałem, jest to raczej przykład, z którego można dowiedzieć się, jak pracować z mapami, przesuwać postacie, sprawdzać kolizje i robić wiele więcej. Poza tym wszystko działa dobrze w Windows 9x/2000 i najprawdopodobniej będzie działać również w XP.

Jako słowo pożegnalne
Cokolwiek mówią, dwuwymiarowe silniki kafelkowe są nadal najbardziej żywe dzisiaj. Żadna gra 3D nie może się jeszcze równać z klasycznymi grami 2D pod względem szczegółowości i piękna rysunku. Weźmy na przykład Fallout Tactics – gra ta wykorzystuje być może najbardziej postępowe osiągnięcia w dziedzinie 2D. I nikt nie odważyłby się nazwać grafiki tej gry biedną.
Ponadto płytki idealnie nadają się do tworzenia ogromnych światów. Korzystając z segmentacji, gdy mapa jest podzielona na kilka części, z których każda jest dynamicznie ładowana, można tworzyć mapy o wręcz fantastycznych rozmiarach. Jest to aktywnie wykorzystywane w grach RPG. To kolejny czynnik, dla którego programiści nie spieszą się z wkraczaniem w świat akceleratorów i multiteksturowania.
I wreszcie grafika kafelkowa jest znacznie łatwiejsza do nauczenia niż jakikolwiek silnik 3D (choć może to być moja subiektywna opinia). A nauka obsługi duszków za pomocą DirectDraw jest nieporównywalnie łatwiejsza i przejrzystsza niż Direct3D, a nawet OpenGL. Dlatego nie próbuj spieszyć się od razu na linię frontu. Być może powinieneś zajrzeć także do starego, dobrego świata 2D. No, może trochę 2,5D...

W tym artykule nauczę Cię, jak tworzyć poziomy do gier niemal każdego gatunku i znacznie ułatwić ich rozwój. Stworzymy silnik mapy kafelków, który możesz wykorzystać w swoich projektach. Będziemy używać Haxe i OpenFL, ale proces tworzenia jest podobny dla wielu języków.

Trochę o tym, co zostanie opisane w artykule

  • Co to jest gra oparta na kafelkach?
  • Twórz lub wyszukuj własne „kafelki”
  • Pisanie kodu wyświetlającego poziom
  • Edycja poziomów

Co to jest gra oparta na kafelkach?

Definicję grafiki kafelkowej można oczywiście znaleźć na Wikipedii, ale aby zrozumieć, co to jest, wystarczy zrozumieć kilka rzeczy
  • Kafelek - mały obraz, zwykle w kształcie prostokąta, który pełni rolę elementu układanki przy konstruowaniu dużych obrazów
  • Mapa - grupa płytek zgrupowanych razem
  • Oparty na kafelkach odnosi się do metody tworzenia poziomów w grach. Kod umieszcza kafelki w predefiniowanych lokalizacjach
W naszym artykule płytki będą miały kształt prostokąta. Istnieje kilka ciekawych funkcji, które można uzyskać, korzystając z grafiki kafelkowej. Najfajniejsze jest to, że nie ma potrzeby rysowania ogromnych obrazów dla każdego poziomu. Pięćdziesiąt obrazów o rozdzielczości 1280 x 768 pikseli dla gry na 50 poziomach w porównaniu z jednym obrazem zawierającym sto płytek to ogromna różnica. Kolejną korzyścią jest to, że umieszczanie przedmiotów za pomocą grafiki kafelkowej staje się zauważalnie łatwiejsze.

Utwórz lub wyszukaj kafelki

Pierwszą rzeczą, której potrzebujesz do zbudowania silnika, jest zestaw płytek. Masz dwie możliwości: skorzystać z gotowych płytek lub stworzyć własne. Jeśli zdecydujesz się skorzystać z gotowych obrazów, można je łatwo znaleźć w całym Internecie. Minusem jest to, że te grafiki nie zostały stworzone specjalnie dla Twojej gry. Z drugiej strony, jeśli po prostu eksperymentujesz, ta opcja jest całkiem odpowiednia.

Myślę, że znalezienie płytek nie powinno stanowić problemu, dlatego nie będę się nad tym szczegółowo rozwodzić.

Tworzenie płytek
Istnieje wiele świetnych narzędzi, które ułatwiają tworzenie obrazów. Wielu programistów używa tych narzędzi w swojej pracy.

To najpopularniejsze narzędzia do tworzenia grafiki pikselowej. Jeśli potrzebujesz czegoś potężniejszego, GIMP jest idealny.

Po wybraniu programu możesz zacząć eksperymentować z własnymi kafelkami. Ponieważ w tym artykule dowiesz się, jak stworzyć własny silnik graficzny kafelków, nie będę wdawał się w szczegóły dotyczące samych kafelków.

Pisanie kodu

Gdy mamy już wszystko, czego potrzebujemy, możemy przejść bezpośrednio do samego programowania.
Wyświetl jeden kafelek na ekranie
Zacznijmy od najprostszego zadania, czyli wyświetlenia na ekranie pojedynczego kafelka. Upewnij się, że wszystkie obrazy mają ten sam rozmiar i są zapisane w różnych plikach (o przechowywaniu duszków w jednym pliku porozmawiamy później).

Gdy wszystkie kafelki znajdą się w folderze zasobów projektu, możesz napisać prostą klasę Tile. Oto przykład dotyczący Haxe
importuj flash.display.Sprite; importuj flash.display.Bitmap; importuj openfl.Assets; klasa Tile rozszerza Sprite ( prywatny var image:Bitmap; funkcja publiczna new() ( super(); image = new Bitmap(Assets.getBitmapData("assets/grassLeftBlock.png")); addChild(image); ) )
Teraz pozostaje nam tylko umieścić kafelek na ekranie. Jedyne, co robi ta klasa, to importuje obraz z folderu zasobów i dodaje go jako obiekt podrzędny. To, jak będzie wyglądać ta klasa, zależy w dużej mierze od języka programowania, którego używasz.

Teraz, gdy mamy klasę Tile, musimy utworzyć instancję Tile i dodać ją do naszej klasy głównej.
importuj flash.display.Sprite; importuj flash.events.Event; importuj flash.Lib; klasa Main rozszerza Sprite ( funkcja publiczna new() ( super(); vartile = new Tile(); addChild(tile); ) publiczna funkcja statyczna main() ( Lib.current.addChild(new Main()); ) )
Klasa Main tworzy nowy obiekt Tile po wywołaniu konstruktora i dodaje go do listy wyświetlania.

Po uruchomieniu gry zostanie wywołana funkcja main() i na scenę zostanie dodany nowy obiekt typu Main. Pamiętaj, że nowy kafelek pojawi się w lewym górnym rogu ekranu.

Używanie tablic do wyświetlania wszystkich płytek
Następnym krokiem jest wymyślenie sposobu wyświetlania wszystkich płytek. Najprostszą metodą jest wypełnienie tablicy liczbami, z których każda odpowiada kafelkowi. Następnie po prostu iterujesz po wszystkich elementach tablicy i wyświetlasz je.

Mamy wybór: użyć zwykłej tablicy lub macierzy. Jeśli nie jesteś zaznajomiony z macierzami, wiedz po prostu, że jest to tablica zawierająca więcej tablic. Większość języków programowania przedstawia to jako nameOfArray[x][y].

Używamy X i Y jako współrzędnych na ekranie. Może moglibyśmy użyć tych X i Y do wyświetlenia naszych kafelków? Przyjrzyjmy się zatem matrixowi
prywatny var przykładArr = [ , , , ,
Należy zauważyć, że element zerowy w tej tablicy jest tablicą pięciu liczb. Oznacza to, że najpierw otrzymujesz element y, a następnie x. Jeśli spróbujesz przejąć żywioł, uzyskasz dostęp do szóstego kafelka.

Jeśli nie rozumiesz, jak działają macierze, nie martw się. W tym artykule użyję zwykłej tablicy, aby uprościć nasze zadanie.
prywatny var przykładArr = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0];
Powyższy przykład pokazuje, że użycie zwykłej tablicy jest znacznie prostsze. Konkretny element możemy wyświetlić obliczając współrzędne za pomocą prostego wzoru.

Napiszmy teraz kod tworzący naszą tablicę. Wypełnijmy go cyfrą 1. Liczba jeden będzie oznaczać identyfikator naszego pierwszego kafelka.

Aby przechowywać tablicę, musimy utworzyć zmienną wewnątrz klasy Main
prywatna mapa var:Array ;
Może to wyglądać trochę dziwnie, więc wyjaśnię.
Nazwa zmiennej to mapa, a typ to Array. oznacza, że ​​tablica zawiera liczby.
Dodajmy teraz trochę kodu do konstruktora naszej klasy, aby zainicjować naszą mapę
mapa = nowa tablica ();
Ten fragment tworzy pustą tablicę, którą wkrótce wypełnimy. Ale najpierw zadeklarujmy kilka zmiennych, które pomogą nam w obliczeniach.
publiczna statyczna zmienna TILE_WIDTH = 60; publiczna statyczna zmienna TILE_HEIGHT = 60; publiczna statyczna zmienna SCREEN_WIDTH = 600; publiczna statyczna zmienna SCREEN_HEIGHT = 360;
Zmienne te są publiczne i statyczne, abyśmy mogli mieć do nich dostęp z dowolnego miejsca w naszym programie. Być może zauważyłeś, że na podstawie tych liczb zdecydujemy, ile komórek przechowywać w tablicy.
var w = Std.int(SCREEN_WIDTH / TILE_WIDTH); var h = Std.int(SCREEN_HEIGHT / TILE_HEIGHT); for (i in 0...w * h) ( map[i] = 1 )
Tutaj, jak powiedziałem, ustawiamy wartość 10 dla zmiennej w i 6 dla h. Następnie musimy przejść przez tablicę, aby zmieścić 10 * 6 liczb.

Mamy teraz prostą mapę, ale musimy poprawnie ułożyć kafelki, prawda? W tym celu wróćmy do klasy Tile i utwórzmy funkcję, która nam to umożliwi
funkcja publiczna setLoc(x:Int, y:Int) ( image.x = x * Main.TILE_WIDTH; image.y = y * Main.TILE_HEIGHT; )
Kiedy wywołujemy funkcję setLoc(), przekazujemy współrzędne x i y. Funkcja pobiera te wartości i konwertuje je na współrzędne w pikselach mnożąc przez TILE_WIDTH i TILE_HEIGHT

Pozostało już tylko opisać w klasie Main proces tworzenia i rozmieszczania kafelków na mapie
for (i in 0...map.length) ( vartile = new Tile(); var x = i % w; var y = Math.floor(i / w);tile.setLoc(x, y); addChild (płytka); )
Tak! Wszystko jest poprawne. Ekran jest wypełniony kafelkami. Rozumiemy, co dzieje się powyżej

Formuła
Omówmy formułę, o której wspomniałem powyżej.

Obliczamy x, podając resztę z dzielenia i przez w. Ma to na celu zwrócenie x do 0 na początku każdej linii.

Dla y bierzemy Floor() z i/w.

Na koniec chciałbym powiedzieć trochę o przewijaniu poziomów. Zwykle nie będziesz w stanie stworzyć poziomu, który w całości zmieści się na ekranie. Twoje mapy będą zauważalnie większe niż ekran, więc nie ma potrzeby rysowania części mapy, której użytkownik nie zobaczy. Można to skorygować, stosując tę ​​samą matematykę. Musisz policzyć, które kafelki będą widoczne na ekranie, a które nie.

Na przykład: ekran ma wymiary 500x500, kafelki mają wymiary 100x100, a twój świat ma wymiary 1000x1000. Przed narysowaniem płytki należy wykonać proste sprawdzenie.

Pozostaje nam tylko stworzyć różne rodzaje płytek i wyeksponować coś pięknego.

Różne rodzaje płytek
OK, teraz mamy mapę pełną identycznych elementów. Byłoby miło mieć więcej niż jeden typ elementu, co oznacza, że ​​będziemy musieli zmienić naszego konstruktora w klasie Tile
funkcja publiczna new(id:Int) ( super(); switch(id) ( przypadek 1: image = new Bitmap(Assets.getBitmapData("assets/grassLeftBlock.png")); przypadek 2: image = new Bitmap(Assets. getBitmapData("assets/grassCenterBlock.png")); przypadek 3: obraz = nowa Bitmap(Assets.getBitmapData("assets/grassRightBlock.png")); przypadek 4: obraz = nowa Bitmap(Assets.getBitmapData("assets/goldBlock .png")); przypadek 5: obraz = nowa Bitmap(Assets.getBitmapData("assets/globe.png")); przypadek 6: obraz = nowa Bitmap(Assets.getBitmapData("assets/mushroom.png")); ) addChild(image); )
Obecnie mamy sześć różnych rodzajów płytek. Potrzebuję konstrukcji przełącznika, aby wybrać obraz do wyświetlenia. Być może zauważyłeś, że konstruktor przyjmuje teraz jako parametr liczbę wskazującą typ kafelka.

Wróćmy do konstruktora klasy Main i edytujmy naszą pętlę
for (i in 0...map.length) ( vartile = new Tile(map[i]); var x = i % w; var y = Math.floor(i / w);tile.setLoc(x, y); addChild(kafelk); )
Jedyna zmiana polega na tym, że przekazujemy teraz typ bloku konstruktorowi. Próba uruchomienia programu bez tej zmiany zakończy się błędem.

Teraz wszystko jest na swoim miejscu, ale musimy wymyślić projekt mapy, zamiast zapełniać ją losowymi blokami. Najpierw usuń pętlę w konstruktorze Main, która wypełnia tablicę jedynkami. A następnie utwórz mapę ręcznie
mapa = [ 0, 4, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 0, 0, 0, 0, 6 , 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3];
Jeśli sformatujesz tablicę, tak jak ja, możesz łatwo zobaczyć przybliżony wygląd poziomu. Ale nikt nie zabrania ci po prostu wypełniać tablicy w jednej linii.

Po uruchomieniu programu zobaczysz kilka błędów. Problem polega na tym, że nasza mapa zawiera typ bloku zerowego, który nie ma obrazu, a nasza klasa po prostu nie wie, co z nim zrobić. Poprawmy to nieporozumienie
if (image != null) addChild(image);
To krótkie sprawdzenie uratuje nas od irytującego błędu wskaźnika zerowego. Ostatnia zmiana będzie miała wpływ na funkcję setLoc(). Próbujemy użyć zmiennych x i y, które nie zostały zainicjowane
funkcja publiczna setLoc(x:Int, y:Int) ( if (image != null) ( image.x = x * Main.TILE_WIDTH; image.y = y * Main.TILE_HEIGHT; ) )
Dzięki tym dwóm prostym warunkom możesz teraz rozpocząć grę i zobaczyć prosty poziom. Płytki o identyfikatorze 0 postrzegamy jako pustą przestrzeń. Dodaj trochę tła. żeby wyglądało atrakcyjniej.

Wniosek

Właśnie stworzyłeś silnik oparty na opowieściach. Teraz już wiesz, czym są grafiki kafelkowe i jak je wykorzystać. Nauczyłeś się tworzyć i edytować poziomy. Ale nie poprzestawaj na tym, jest jeszcze wiele do ulepszenia w naszym silniku.
Wybór redaktorów
Aby skorzystać z podglądu prezentacji utwórz konto Google i zaloguj się:...

Około 400 lat temu William Gilbert sformułował postulat, który można uznać za główny postulat nauk przyrodniczych. Pomimo...

Funkcje zarządzania Slajdy: 9 Słowa: 245 Dźwięki: 0 Efekty: 60 Istota zarządzania. Kluczowe idee. Klucz menadżera zarządzającego...

Okres mechaniczny Arytmometr - maszyna licząca wykonująca wszystkie 4 operacje arytmetyczne (1874, Odner) Silnik analityczny -...
Aby skorzystać z podglądu prezentacji utwórz konto Google i zaloguj się:...
Podgląd: aby skorzystać z podglądu prezentacji, utwórz konto Google i...
Aby skorzystać z podglądu prezentacji utwórz konto Google i zaloguj się:...
W 1943 roku Karaczajowie zostali nielegalnie deportowani ze swoich rodzinnych miejsc. Z dnia na dzień stracili wszystko – dom, ojczyznę i…
Mówiąc o regionach Mari i Vyatka na naszej stronie internetowej, często wspominaliśmy i. Jego pochodzenie jest tajemnicze; ponadto Mari (sami...