Zaimplementowałem kilka ekranów używając libGDX, które oczywiście korzystałyby z Screen
klasy dostarczonej przez framework libGDX. Jednak implementacja dla tych ekranów działa tylko ze wstępnie zdefiniowanymi rozmiarami ekranu. Na przykład, jeśli duszek był przeznaczony dla ekranu o rozmiarze 640 x 480 (współczynnik proporcji 4: 3), nie będzie działał zgodnie z przeznaczeniem na innych rozmiarach ekranu, ponieważ sprite dopasowuje się do granic ekranu i nie są skalowane do rozmiaru ekranu w ogóle. Co więcej, gdyby libGDX zapewniało proste skalowanie, problem, z którym się zmagam, nadal istniałby, ponieważ spowodowałoby to zmianę proporcji ekranu gry.
Po poszukaniu informacji w Internecie trafiłem na blog / forum , na którym omawiano ten sam problem. Zaimplementowałem to i na razie działa dobrze. Ale chcę potwierdzić, czy jest to najlepsza opcja, aby to osiągnąć, czy też istnieją lepsze alternatywy. Poniżej znajduje się kod pokazujący, jak radzę sobie z tym uzasadnionym problemem.
LINK FORUM: http://www.java-gaming.org/index.php?topic=25685.new
public class SplashScreen implements Screen {
// Aspect Ratio maintenance
private static final int VIRTUAL_WIDTH = 640;
private static final int VIRTUAL_HEIGHT = 480;
private static final float ASPECT_RATIO = (float) VIRTUAL_WIDTH / (float) VIRTUAL_HEIGHT;
private Camera camera;
private Rectangle viewport;
// ------end------
MainGame TempMainGame;
public Texture splashScreen;
public TextureRegion splashScreenRegion;
public SpriteBatch splashScreenSprite;
public SplashScreen(MainGame maingame) {
TempMainGame = maingame;
}
@Override
public void dispose() {
splashScreenSprite.dispose();
splashScreen.dispose();
}
@Override
public void render(float arg0) {
//----Aspect Ratio maintenance
// update camera
camera.update();
camera.apply(Gdx.gl10);
// set viewport
Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,
(int) viewport.width, (int) viewport.height);
// clear previous frame
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// DRAW EVERYTHING
//--maintenance end--
splashScreenSprite.begin();
splashScreenSprite.disableBlending();
splashScreenSprite.draw(splashScreenRegion, 0, 0);
splashScreenSprite.end();
}
@Override
public void resize(int width, int height) {
//--Aspect Ratio Maintenance--
// calculate new viewport
float aspectRatio = (float)width/(float)height;
float scale = 1f;
Vector2 crop = new Vector2(0f, 0f);
if(aspectRatio > ASPECT_RATIO) {
scale = (float) height / (float) VIRTUAL_HEIGHT;
crop.x = (width - VIRTUAL_WIDTH * scale) / 2f;
} else if(aspectRatio < ASPECT_RATIO) {
scale = (float) width / (float) VIRTUAL_WIDTH;
crop.y = (height - VIRTUAL_HEIGHT * scale) / 2f;
} else {
scale = (float) width / (float) VIRTUAL_WIDTH;
}
float w = (float) VIRTUAL_WIDTH * scale;
float h = (float) VIRTUAL_HEIGHT * scale;
viewport = new Rectangle(crop.x, crop.y, w, h);
//Maintenance ends here--
}
@Override
public void show() {
camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); //Aspect Ratio Maintenance
splashScreen = new Texture(Gdx.files.internal("images/splashScreen.png"));
splashScreenRegion = new TextureRegion(splashScreen, 0, 0, 640, 480);
splashScreenSprite = new SpriteBatch();
if(Assets.load()) {
this.dispose();
TempMainGame.setScreen(TempMainGame.mainmenu);
}
}
}
AKTUALIZACJA: Niedawno dowiedziałem się, że libGDX ma swoją własną funkcjonalność do utrzymywania współczynników proporcji, które chciałbym tutaj omówić. Podczas wyszukiwania informacji o problemie ze współczynnikiem proporcji w Internecie natknąłem się na kilka forów / programistów, którzy mieli problem z pytaniem „Jak zachować proporcje na różnych rozmiarach ekranu?” Jedno z rozwiązań, które naprawdę mi się sprawdziło, zostało zamieszczone powyżej.
Później, kiedy przystąpiłem do implementacji touchDown()
metod dla ekranu, stwierdziłem, że ze względu na skalowanie przy touchDown()
zmianie rozmiaru współrzędne, na których zaimplementowałem , zmieniłyby się znacznie. Po przepracowaniu jakiegoś kodu w celu przetłumaczenia współrzędnych zgodnie ze zmianą rozmiaru ekranu, zmniejszyłem tę kwotę w dużym stopniu, ale nie udało mi się zachować ich z dokładnością do punktu. Na przykład, gdybym zaimplementował touchDown()
teksturę, zmiana rozmiaru ekranu spowodowałaby przesunięcie narzędzia touchListener w obszarze tekstury o kilka pikseli w prawo lub w lewo, w zależności od zmiany rozmiaru i było to oczywiście niepożądane.
Później dowiedziałem się, że klasa stage ma własną natywną funkcjonalność, aby utrzymać współczynnik kształtu ( boolean stretch = false
). Teraz, gdy zaimplementowałem mój ekran przy użyciu klasy stage, współczynnik proporcji jest przez nią dobrze utrzymywany. Jednak w przypadku zmiany rozmiaru lub innych rozmiarów ekranu, generowany czarny obszar zawsze pojawia się po prawej stronie ekranu; to znaczy ekran nie jest wyśrodkowany, co sprawia, że jest dość brzydki, jeśli czarny obszar jest znacznie duży.
Czy jakikolwiek członek społeczności może mi pomóc rozwiązać ten problem?
źródło
Odpowiedzi:
Jak to się teraz robi:
Ponieważ jest to jedno z najbardziej znanych pytań dotyczących libgdx, podam mu małą aktualizację :
LibGDX v1.0 wprowadzono w
Viewport
celu rozwiązania tego problemu. Jest o wiele łatwiejszy w użyciu, a strategia skalowania jest podłączana, co oznacza, że pojedyncza linia może zmienić zachowanie i możesz z nią grać i zobaczyć, która z nich najlepiej pasuje do Twojej gry.Wszystko, co musisz o tym wiedzieć, znajdziesz tutaj .
źródło
TextureRegion
Streches. Jeśli pozostawreszie(int width, int height)
funkcję pustą. THeTextureRegion
nie strectch.EDYCJA: libGDX ewoluowało. Najlepszą odpowiedzią jest teraz ta przez użytkownika. Koniecznie sprawdź link do
Viewport
dokumentacji. .Kiedy SteveBlack zamieścił link do problemu, który został zgłoszony na zajęciach scenicznych, poszedłem tam tylko po to, aby odkryć, że problem (to nie był w rzeczywistości mój problem) został rozwiązany w najnowszych nocnych nocach.
Po przeszukaniu w Internecie problemu, który miałem, nie mogłem znaleźć żadnych rozwiązań, więc zdecydowałem się skontaktować bezpośrednio z osobą, która zgłosiła błąd. Następnie odpowiedział mi na forach libgdx i jestem mu wdzięczny za pomoc. Tutaj jest link
To był pojedynczy wiersz kodu i wszystko, co musisz zrobić, to:
W metodzie resize ():
stage.setViewport(640, 480, false); stage.getCamera().position.set(640/2, 480/2, 0);
Gdzie 640 X 480 to rozdzielczość Twojego TextureRegion, która opisuje zamierzony współczynnik proporcji. Jeśli twój rozmiar TextureRegion wynosił 320 x 240, to oba argumenty powinny zostać zmienione na nową rozdzielczość, aby załatwić sprawę.
Link do profilu oryginalnej osoby, która faktycznie rozwiązała mój problem
źródło
setViewport
z 3 parametrami jest teraz niedostępny!Czarne pasy po lewej / prawej lub u góry / u dołu wyglądają lepiej niż zniekształcanie całej sceny w celu dopasowania do ekranu. Jeśli celujesz w współczynnik proporcji, który znajduje się pośrodku możliwych zakresów (4: 3 to prawdopodobnie najniższy koniec, 16: 9 to prawdopodobnie wysoki koniec), paski powinny pozostać małe dla większości urządzeń. Dzięki temu możesz używać większości ekranu nawet na większych ekranach, a masz już kod tego faceta, więc jest to całkiem proste. Byłoby jeszcze lepiej, gdyby była to tylko opcja wbudowana w libgdx.
Ale myślę, że najlepszym podejściem jest użycie całego ekranu. Nie zrobiłem tego jeszcze, ale takie podejście przyjmuję przy następnym projekcie. Chodzi o to, że jeśli ktoś ma szerszy ekran, to powinien widzieć więcej po bokach. Chris Pruett mówi o tym, jak to zrobić w jednym ze swoich wykładów ( link do miejsca w rozmowie - w rzeczywistości całość jest całkiem niezła). Chodzi o to, aby przeskalować wysokość, a następnie ustawić rzutnię wystarczająco szeroką, aby pasowała do ekranu. OpenGL powinien zająć się wyświetleniem reszty. Sposób, w jaki to robi, jest tutaj .
W przypadku libgdx może istnieje łatwy sposób na zrobienie tego ze sceną2d, przesuwając kamerę po scenie, ale tak naprawdę nigdy nie pracowałem ze sceną2d. W każdym razie uruchomienie aplikacji jako natywnego okna o zmiennym rozmiarze jest znacznie łatwiejszym sposobem przetestowania wielu rozmiarów ekranu niż utworzenie zestawu plików AVD.
źródło
Zobacz ostatnią część sekcji Viewport w oficjalnych dokumentach: https://code.google.com/p/libgdx/wiki/scene2d#Viewport
źródło
ResolutionFileResolver klasa pozwala rozwiązać nazwy pliku do najlepszej rozdzielczości. Uważam, że będzie to działać również z różnymi współczynnikami kształtu, pod warunkiem, że stworzyłeś sprite'y dla tych współczynników. Istnieje przykład użycia w AssetManagerTest .
źródło
Używam tej metody z http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/
Stworzyłem tę funkcję, która zwraca dotknięty punkt na ekranie, przeskalowany w dół do żądanej pozycji gry.
public Vector2 getScaledPos(float x, float y) { float yR = viewport.height / (y - viewport.y); y = CAMERA_HEIGHT / yR; float xR = viewport.width / (x - viewport.x); x = CAMERA_WIDTH / xR; return new Vector2(x, CAMERA_HEIGHT - y); }
Użyj tego w touchdown / up / drag i możesz sprawdzić dotyk w swojej grze.
źródło
Ten kod działa dla mnie z najnowszą aktualizacją: * OrthographicCamera to cam, to nie powoduje przycinania, po prostu zmienia widok, więc szerokość jest nadal „tyle” razy większa niż rzeczywiste okno / urządzenie
public void resize(int width, int height) { int newW = width, newH = height; if (cam.viewportWidth > width) { float scale = (float) cam.viewportWidth / (float) width; newW *= scale; newH *= scale; } // true here to flip the Y-axis cam.setToOrtho(true, newW, newH); }
źródło