Wspólny wzór do skalowania „rzeczywistych jednostek” do pikseli?

10

To jest pytanie uzupełniające do tego drugiego .

Chciałbym wiedzieć, czy istnieje wspólny / typowy / najlepszy wzór do skalowania mojej reprezentacji świata (obecnie 160 km x 160 km), aby dopasować ją do obszaru rysowania (obecnie 800 x 600 pikseli).

Mogę wymyślić co najmniej cztery różne podejścia:

Naiwny (tak jak dotychczas to zrobiłem). Zaimplementowałem funkcję globalną sc(vector), która po prostu zwróci pomniejszoną kopię przekazywanego wektora. To oczywiście działa, ale zobowiązuje mnie do napisania kodu takiego jak:

drawCircle(sc(radius), sc(position))

Funkcje owijania . Mógłbym zdefiniować kilka funkcji, z których każda otacza oryginalną wersję oprogramowania pośredniego. Na przykład mógłbym zdefiniować myDrawCircle, że najpierw skaluje argumenty, które wymagają skalowania, a następnie wywołuje drawCirclez tym drugim. To by uczyniło mój kod być może bardziej czytelnym i łatwiejszym w utrzymaniu, ale powinienem napisać wiele funkcji zawijania, które brzmią głupio.

Dekorator funkcji . Mógłbym po prostu udekorować istniejące funkcje oprogramowania pośredniego, zapewniając automatyczne skalowanie wszystkich parametrów, które są wystąpieniem klasy Vector3D, ale problem polega na tym, że te funkcje działają również z tymi samymi parametrami, które są listlub Vector2Dteż, a dekorator nie miałby sposobu, aby wiedzieć które listy należy skalować (na przykład promień), a które nie (wartości RGB).

Inicjalizacja powierzchni . Podczas definiowania powierzchni, na której zamierzam rysować, mogłem zdefiniować współczynnik skalowania (tak, że jako parametry używałbym mierników, a nie pikseli). To działałoby dla mnie transparentnie i byłoby moim rozwiązaniem z wyboru, ale oczywiście powinno być zaimplementowane w oprogramowaniu pośrednim, więc nie jest to realna opcja.

... w każdym razie: skoro jest to bardzo powszechny problem, zastanawiam się, czy istnieje ustalony wzór, który elegancko rozwiązuje ten problem, którego nie udało mi się znaleźć.

PS: W tym projekcie używam Pythona (z pygame ), ale - choć doceniona jest odpowiedź specyficzna dla python / pygame, bardziej interesuje mnie ogólny / ogólny opis wzorca, a nie jego konkretna implementacja.

Z góry dziękuję za poświęcony czas i wiedzę.

prochowiec
źródło

Odpowiedzi:

6

Standardowym sposobem jest skonfigurowanie macierzy transformacji do wykonania konwersji podczas renderowania. W przypadku renderowania 3D jest to matryca transformacji widoku dla kamery.

Większość interfejsów API 2D umożliwia także określenie transformacji widoku jako macierzy 2x3 lub osobnej skali, translacji i obrotu.

Szybkie spojrzenie na dokumentację pygame sugeruje, że musisz samodzielnie zaimplementować macierz transformacji widoku. Czy pozwala ci wyprowadzić własną klasę z klasy powierzchni, aby umożliwić ci dodanie tej funkcjonalności?

Adam
źródło
Twoja odpowiedź jest bardzo przydatna (+1). Mogę podklasować moją klasę powierzchni, ale potrzebuję więcej czasu na zbadanie, czy mogę osiągnąć to, co wskazano w twoim poście. Jestem zupełnie nowy w programowaniu gier i ogólnie grafice, czy masz jakiś link, który poleciłby wyjaśnienie tego podejścia do macierzy (a nawet tylko matematyki związanej z użyciem macierzy do skalowania powierzchni?). Dziękuję Ci!
mac.
1
Ponieważ jest to 2D i nie ma żadnego obrotu, @mac w zasadzie mówi o zawijaniu funkcji i możesz użyć prostego podziału skali w tych opakowaniach. Powodem, dla którego zwykle używana jest pełna matryca, jest to, że większość API ma matrycę kontrolującą rzutnię, ale wygląda na to, że pygame tego nie robi, więc musisz zrobić to sam, jedna warstwa w górę.
Patrick Hughes,
2

ponieważ jest to bardzo powszechny problem, zastanawiam się, czy istnieje ustalony wzór, który elegancko rozwiązuje ten problem, którego nie udało mi się znaleźć.

Zwykle ludzie nie próbują wykonywać skalowania w czasie wykonywania w grach 2D. Nie zgadzam się, że jest to powszechny problem. Jeśli ludzie chcą mini-mapy lub jakiegoś innego stałego przeskalowania, często przygotowuje się nowy zestaw grafiki do tego celu. Rzadko zdarza się, że potrzebujesz jednej procedury, aby uruchomić grę na 2 różnych poziomach powiększenia w grze 2D.

Jeśli korzystasz z interfejsu API 3D, możesz uzyskać tę funkcjonalność za darmo - wystarczy zmienić parametry kamery / rzutni.

PyGame jest bardzo starym interfejsem API i niestety tak naprawdę nadaje się tylko do 2D. Nawet jeśli uda Ci się opracować odpowiednie systemy skalowania dla różnych poziomów powiększenia, wydajność nie będzie wystarczająco dobra, a wygląd prawdopodobnie będzie niedopuszczalnie zły.

Radzę, że jeśli chcesz bardzo powiększyć lub pomniejszyć, jak najszybciej możesz przejść do nowoczesnego API 3D. Polecam pyglet ale mogą być też inne.

Kylotan
źródło
Dziękujemy za odpowiedź (+1). W pygletsprzeszłości korzystałem już z symulacji 3D. Jest z pewnością bardziej zdolny niż pygame, ale obsługa 2D jest znacznie niższa niż ta w pygame. Dostępna dokumentacja / przykłady są również mniej szczegółowe, co jest dla mnie wielkim hitem, ponieważ jestem początkującym w tworzeniu gier i naprawdę muszę zrozumieć podstawy najczęściej wykonywanych operacji. :) Co do „wieku” gry: masz rację. Modernizacja trwa jednak! :)
mac.
Jeśli chodzi o: „Rzadko potrzebujesz jednej procedury, aby działać przy 2 różnych poziomach powiększenia” ... Myślałem, że to właśnie przydałby się przy zmianie rozmiaru okna / rozdzielczości gry pełnoekranowej. Z twojego komentarza zrozumiałem, że nie jest: jakikolwiek wskaźnik do tego, co jest „wspólne” zamiast tego?
mac.
Jakie operacje 2D wykonujesz, gdy poziom pygletu jest bardziej niski niż pygame? Oba pozwalają narysować duszka z 1 linią kodu. Po zmianie rozmiaru okna gry 2D stosunek pikseli do jednostek świata prawie zawsze pozostaje stały. W rezultacie rysujesz więcej duszków: nie rysujesz ich inaczej.
Kylotan
Jeśli chodzi o rzeczy niskiego poziomu: nie jestem naprawdę ekspertem od żadnej z dwóch bibliotek, ale w pygletach nie mogłem replikować po wyjęciu z pudełka zachowań renderowania grupowego oferowanych przez pygame (jak pygame.sprite.LayeredUpdatesna przykład). Jeśli chodzi o niezmienny stosunek: mam to, co masz na myśli. Opisane przez ciebie zachowanie nie jest tym, które chcę powtórzyć, ale zrozumiałem, co masz na myśli, dzięki za wyjaśnienie! :)
Mac
pyglet ma obiekty OrdersGroup - dokumenty są tutaj, jeśli ty lub ktokolwiek jest zainteresowany: pyglet.org/doc/programming_guide/displaying_images.html#sprites
Kylotan