Pytanie
Kiedy masz grę 2D, która wykorzystuje naprawdę duże obrazy (większe niż sprzęt może obsłużyć), co robisz? Może jest jakieś interesujące rozwiązanie tego problemu, które nigdy wcześniej mi się nie zdarzyło.
W zasadzie pracuję nad rodzajem graficznego twórcy gier przygodowych. Moją grupą docelową są ludzie z niewielkim lub żadnym doświadczeniem w tworzeniu gier (i programowaniu). Jeśli pracujesz z taką aplikacją, czy nie wolałbyś, aby poradziła sobie z tym problemem wewnętrznie, niż nakazując „podzielenie zdjęć”?
Kontekst
Powszechnie wiadomo, że karty graficzne nakładają zestaw ograniczeń dotyczących rozmiaru tekstur, których mogą używać. Na przykład podczas pracy z XNA jesteś ograniczony do maksymalnego rozmiaru tekstury 2048 lub 4096 pikseli w zależności od wybranego profilu.
Zwykle nie stanowi to większego problemu w grach 2D, ponieważ większość z nich ma poziomy, które można zbudować z mniejszych pojedynczych elementów (np. Kafelków lub przetworzonych duszków).
Ale pomyśl o kilku klasycznych graficznych przygodowych punktach i zabawach (np. Monkey Island). Pokoje w graficznych grach przygodowych są zwykle zaprojektowane jako całość, z niewielkimi lub żadnymi powtarzalnymi sekcjami, podobnie jak malarz pracujący nad krajobrazem. A może gra taka jak Final Fantasy 7, która wykorzystuje duże, wstępnie renderowane tła.
Niektóre z tych pokoi mogą stać się dość duże, często obejmując trzy lub więcej ekranów o szerokości. Teraz, jeśli weźmiemy pod uwagę te tła w kontekście nowoczesnej gry w wysokiej rozdzielczości, z łatwością przekroczą maksymalny obsługiwany rozmiar tekstury.
Oczywistym rozwiązaniem tego problemu jest podzielenie tła na mniejsze sekcje, które pasują do wymagań i narysowanie ich obok siebie. Ale czy to ty (lub twój artysta) musisz być tym, który dzieli wszystkie twoje tekstury?
Jeśli pracujesz z interfejsem API wysokiego poziomu, czyż nie powinno być przygotowane na poradzenie sobie z tą sytuacją i wykonanie podziału i składania tekstur wewnętrznie (jako proces wstępny, taki jak potok treści XNA lub w czasie wykonywania)?
Edytować
Oto, o czym myślałem, z punktu widzenia implementacji XNA.
Mój silnik 2D wymaga tylko bardzo małego podzbioru funkcji Texture2D. Naprawdę mogę to zredukować do tego interfejsu:
public interface ITexture
{
int Height { get; }
int Width { get; }
void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}
Jedyną metodą zewnętrzną, której używam, która opiera się na Texture2D, jest SpriteBatch.Draw (), aby móc utworzyć pomost między nimi, dodając metodę rozszerzenia:
public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
{
texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
}
Pozwoliłoby mi to używać zamiennie ITexture za każdym razem, gdy korzystałem wcześniej z Texture2D.
Następnie mógłbym stworzyć dwie różne implementacje ITexture, np. RegularTexture i LargeTexture, gdzie RegularTexture po prostu owinąłby zwykłą Texture2D.
Z drugiej strony LargeTexture zachowałby Listę Texture2D odpowiadającą jednemu z podzielonych fragmentów pełnego obrazu. Najważniejsze jest to, że wywołanie Draw () na LargeTexture powinno być w stanie zastosować wszystkie transformacje i narysować wszystkie elementy tak, jakby były tylko jednym ciągłym obrazem.
Wreszcie, aby cały proces był przejrzysty, stworzyłbym ujednoliconą klasę modułu ładującego tekstury, który działałby jako metoda fabryczna. Wziąłby ścieżkę tekstury jako parametr i zwróciłby teksturę, która byłaby tekstem regularnym lub tekstem dużym, w zależności od rozmiaru obrazu przekraczającego limit lub nie. Ale użytkownik nie musiał wiedzieć, który to był.
Trochę przesada, czy to brzmi dobrze?