Aktualizacja: poprawiony algorytm renderowania mapy, dodano więcej ilustracji, zmieniono formatowanie.
Być może zaletą techniki „zygzakowatości” mapowania kafelków na ekran można powiedzieć, że kafelki x
i y
współrzędne są na osi pionowej i poziomej.
Podejście „ciągnąc za diament”:
Rysując mapę izometryczną za pomocą „rysowania w diamentie”, co moim zdaniem odnosi się do renderowania mapy za pomocą zagnieżdżonej for
pętli nad dwuwymiarową tablicą, na przykład w tym przykładzie:
tile_map[][] = [[...],...]
for (cellY = 0; cellY < tile_map.size; cellY++):
for (cellX = 0; cellX < tile_map[cellY].size cellX++):
draw(
tile_map[cellX][cellY],
screenX = (cellX * tile_width / 2) + (cellY * tile_width / 2)
screenY = (cellY * tile_height / 2) - (cellX * tile_height / 2)
)
Korzyść:
Zaletą tego podejścia jest to, że jest to prosta zagnieżdżona for
pętla z dość prostą logiką, która działa konsekwentnie na wszystkich płytkach.
Niekorzyść:
Jednym minusem tej metody jest to, że x
i y
współrzędne płytki na mapie wzrośnie w ukośne linie, które mogłyby utrudnić wizualnie map lokalizację na ekranie mapie reprezentowane jako tablica:
Jednak zaimplementowanie powyższego przykładowego kodu będzie pułapką - kolejność renderowania spowoduje, że płytki, które powinny znajdować się za niektórymi płytkami, zostaną narysowane na wierzchu płytek z przodu:
Aby rozwiązać ten problem, for
kolejność pętli wewnętrznej musi zostać odwrócona - zaczynając od najwyższej wartości i renderując w kierunku niższej wartości:
tile_map[][] = [[...],...]
for (i = 0; i < tile_map.size; i++):
for (j = tile_map[i].size; j >= 0; j--): // Changed loop condition here.
draw(
tile_map[i][j],
x = (j * tile_width / 2) + (i * tile_width / 2)
y = (i * tile_height / 2) - (j * tile_height / 2)
)
Przy powyższej poprawce renderowanie mapy powinno zostać poprawione:
Podejście „zygzakowate”:
Korzyść:
Być może zaletą podejścia „zygzakowatego” jest to, że renderowana mapa może wydawać się nieco bardziej zwarta w pionie niż podejście „diamentowe”:
Niekorzyść:
Próbując wdrożyć technikę zygzakowatą, wadą może być to, że nieco trudniej jest napisać kod renderujący, ponieważ nie można go napisać tak prosto, jak zagnieżdżona for
pętla nad każdym elementem w tablicy:
tile_map[][] = [[...],...]
for (i = 0; i < tile_map.size; i++):
if i is odd:
offset_x = tile_width / 2
else:
offset_x = 0
for (j = 0; j < tile_map[i].size; j++):
draw(
tile_map[i][j],
x = (j * tile_width) + offset_x,
y = i * tile_height / 2
)
Ponadto może być trochę trudna próba ustalenia współrzędnych płytki ze względu na rozłożony charakter kolejności renderowania:
Uwaga: ilustracje zawarte w tej odpowiedzi zostały utworzone przy użyciu implementacji Java przedstawionego kodu renderowania kafelków, z następującą int
tablicą jako mapą:
tileMap = new int[][] {
{0, 1, 2, 3},
{3, 2, 1, 0},
{0, 0, 1, 1},
{2, 2, 3, 3}
};
Obrazy kafelków to:
tileImage[0] ->
Pudełko z pudełkiem w środku.
tileImage[1] ->
Czarna skrzynka.
tileImage[2] ->
Białe pudełko.
tileImage[3] ->
Pudełko z wysokim szarym przedmiotem.
Uwaga na temat szerokości i wysokości płytek
Zmienne tile_width
i tile_height
które są stosowane w powyższych przykładach kodu odnoszą się do szerokości i wysokości płyty naziemnej w obrazie reprezentującym płytki:
Korzystanie z wymiarów obrazu będzie działać, o ile wymiary obrazu i wymiary kafelków będą takie same. W przeciwnym razie mapę kafelków można renderować z przerwami między kafelkami.
j = (2 * x - 4 * y) / tilewidth * 0.5; i = (p.x * 2 / tilewidth) - j;
.Tak czy inaczej, praca zostanie wykonana. Zakładam, że zygzakiem masz na myśli coś takiego: (liczby są kolejnością renderowania)
A przez diament rozumiesz:
Pierwsza metoda wymaga renderowania większej liczby kafelków, aby narysować pełny ekran, ale można łatwo sprawdzić granicę i pominąć wszystkie kafelki całkowicie poza ekranem. Obie metody będą wymagały pewnej liczby zgryzów, aby dowiedzieć się, jaka jest lokalizacja płytki 01. W końcu obie metody są w przybliżeniu równe pod względem matematycznym wymaganym dla pewnego poziomu wydajności.
źródło
Jeśli masz jakieś płytki, które przekraczają granice twojego diamentu, zalecamy rysowanie w kolejności:
źródło
Odpowiedź Coobirda jest poprawna, kompletna. Jednak połączyłem jego podpowiedzi z poradami z innej witryny, aby stworzyć kod, który działa w mojej aplikacji (iOS / Objective-C), który chciałem udostępnić każdemu, kto tu przyjeżdża i szuka czegoś takiego. Jeśli podoba Ci się / głosuj w górę na tę odpowiedź, zrób to samo dla oryginałów; wszystko, co zrobiłem, to „stanąć na ramionach gigantów”.
Jeśli chodzi o porządek sortowania, moja technika jest zmodyfikowanym algorytmem malarza: każdy obiekt ma (a) wysokość podstawy (nazywam „poziomem”) i (b) X / Y dla „podstawy” lub „stopy” obraz (przykłady: podstawa awatara jest u jego stóp; podstawa drzewa u podstawy; podstawa samolotu to środkowy obraz itp.) Następnie sortuję od najniższego do najwyższego poziomu, a następnie od najniższego (najwyższego na ekranie) do najwyższej bazy Y, a następnie najniższa (najbardziej na lewo) do najwyższej podstawy-X. To renderuje kafelki tak, jak można by się spodziewać.
Kod do konwersji ekranu (punktu) na kafelek (komórkę) i odwrotnie:
źródło
Możesz użyć odległości euklidesowej od punktu najwyższego i najbliższego dla widza, z tą różnicą, że nie jest to w porządku. Daje to sferyczny porządek sortowania. Możesz to naprawić, patrząc z dalszej odległości. Dalej krzywizna ulega spłaszczeniu. Więc po prostu dodaj powiedz 1000 do każdego ze składników x, y i z, aby otrzymać x ', y' i z '. Sortuj według x '* x' + y '* y' + z '* z'.
źródło
Prawdziwy problem polega na tym, że musisz narysować kilka kafelków / duszek przecinających się / obejmujących dwa lub więcej innych kafelków.
Po 2 (ciężkich) miesiącach osobistej analizy problemu w końcu znalazłem i wdrożyłem „poprawny rysunek renderowania” dla mojej nowej gry cocos2d-js. Rozwiązanie polega na mapowaniu dla każdego kafelka (podatnego), którego duszki to „przód, tył, góra i tył”. Po wykonaniu tej czynności możesz je narysować zgodnie z „logiką rekurencyjną”.
źródło