Rozszerzenie zakresu urządzeń z telefonów na inne urządzenia z dużym ekranem wiąże się z koniecznością uwzględnienia sposobu zarządzania oknami w grze. Na Googlebooku, ChromeOS i w Grach Google Play na PC gra może działać w trybie okienkowym na głównym interfejsie komputera. Na nowych tabletach i urządzeniach składanych z Androidem w wersji 12L (poziom interfejsu API 32) lub nowszej, których szerokość ekranu jest większa niż 600 dp, gra może działać obok innych aplikacji w trybie podzielonego ekranu, zmieniać rozmiar, a nawet być przenoszona między wewnętrznym a zewnętrznym wyświetlaczem na urządzeniach składanych. Powoduje to zmianę konfiguracji rozmiaru okna, a na niektórych urządzeniach także orientacji.
Zmiana rozmiaru w przypadku gier w Unity
Podstawowa konfiguracja dużego ekranu
Określ, czy gra obsługuje zmianę rozmiaru:
<android:resizeableActivity="true" or "false" />
Jeśli nie możesz obsługiwać zmiany rozmiaru, upewnij się, że w pliku manifestu gry są wyraźnie określone minimalny i maksymalny obsługiwany format obrazu:
<!-- Render full screen between 3:2 and 21:9 aspect ratio -->
<!-- Let the platform letterbox otherwise -->
<activity android:minAspectRatio="1.5">
<activity android:maxAspectRatio="2.33">
Gry Google Play na PC
W przypadku Gier Google Play na PC platforma obsługuje zmianę rozmiaru okna, zachowując określony współczynnik proporcji. Rozmiar okna jest automatycznie blokowany na optymalnych wymiarach. Jeśli Twoja gra jest w orientacji poziomej, musisz obsługiwać co najmniej format obrazu 16:9, a jeśli jest w orientacji pionowej – format obrazu 9:16. Aby zapewnić jak najlepsze wrażenia, w przypadku gier w orientacji poziomej wyraźnie obsługuj formaty obrazu 21:9, 16:10 i 3:2. Możliwość zmiany rozmiaru okna nie jest tu wymagana, ale warto ją mieć ze względu na zgodność z innymi formatami urządzeń.
Więcej informacji i sprawdzone metody znajdziesz w artykule Konfigurowanie grafiki w Grach Google Play na PC.
Duże ekrany
Aby zmaksymalizować obszar widoczny w grze na pełnym ekranie na tabletach z dużym ekranem, urządzeniach składanych, Chromebookach, ChromeOS i podłączonych wyświetlaczach, obsługuj tryb pełnoekranowy i ukrywaj paski systemu, ustawiając flagi w decorView, widoczności interfejsu systemu lub za pomocą interfejsu WindowInsetsCompat API. Warto też odpowiednio obsługiwać zdarzenia związane z obracaniem i zmianą rozmiaru lub im zapobiegać.
Pamiętaj, że na urządzeniach z Androidem z dużym ekranem gra może działać w konfiguracjach, których jeszcze nie obsługujesz. Jeśli gra nie obsługuje wszystkich konfiguracji rozmiaru i orientacji okna, platforma wyświetla ją w trybie zgodności i w razie potrzeby wyświetla graczowi komunikat przed przejściem do nieobsługiwanej konfiguracji.
Na niektórych urządzeniach, gdy gracz przejdzie do nieobsługiwanej konfiguracji, może pojawić się prośba o ponowne wczytanie gry i odtworzenie aktywności, aby jak najlepiej dopasować ją do nowego układu okna. Może to zakłócić rozgrywkę. Przetestuj grę w różnych konfiguracjach trybu wielu okien (rozmiar okna 2/3, 1/2, 1/3) i sprawdź, czy żadne elementy rozgrywki ani interfejsu nie są przycięte lub niedostępne. Sprawdź też, jak gra reaguje na ciągłość na urządzeniach składanych podczas przełączania się między ekranem wewnętrznym a zewnętrznym. Jeśli zauważysz problemy, wyraźnie obsłuż te zdarzenia konfiguracji i dodaj zaawansowaną obsługę zmiany rozmiaru na dużym ekranie.
Zaawansowana zmiana rozmiaru na dużym ekranie
Aby wyjść z trybu zgodności i uniknąć ponownego tworzenia aktywności:
Zadeklaruj, że główna aktywność może zmieniać rozmiar:
<android:resizeableActivity="true" />Aby otrzymywać wszystkie zdarzenia związane z konfiguracją na dużym ekranie, zadeklaruj w atrybucie
android:configChangeselementu<activity>w pliku manifestu gry wyraźną obsługę parametrów „orientation”, „screenSize”, „smallestScreenSize”, „screenLayout” i „density”:<android:configChanges="screenSize | smallestScreenSize | screenLayout | orientation | keyboard | keyboardHidden | density" />Zastąp
onConfigurationChanged()i obsłuż zdarzenie konfiguracji, w tym bieżącą orientację, rozmiar okna, szerokość i wysokość:Kotlin
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) val density: Float = resources.displayMetrics.density val newScreenWidthPixels = (newConfig.screenWidthDp * density).toInt() val newScreenHeightPixels = (newConfig.screenHeightDp * density).toInt() // Configuration.ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE val newScreenOrientation: Int = newConfig.orientation // ROTATION_0, ROTATION_90, ROTATION_180, or ROTATION_270 val newScreenRotation: Int = windowManager.defaultDisplay.rotation }
Java
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); float density = getResources().getDisplayMetrics().density; int newScreenWidthPixels = (int) (newConfig.screenWidthDp * density); int newScreenHeightPixels = (int) (newConfig.screenHeightDp * density); // Configuration.ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE int newScreenOrientation = newConfig.orientation; // ROTATION_0, ROTATION_90, ROTATION_180, or ROTATION_270 int newScreenRotation = getWindowManager().getDefaultDisplay() .getRotation(); }
Możesz też wysłać zapytanie do WindowManager, aby sprawdzić bieżące obracanie urządzenia. Na podstawie tych metadanych sprawdź wymiary nowego okna i wyświetl je w pełnym rozmiarze. Ze względu na różnice w proporcjach obrazu może to nie działać we wszystkich przypadkach. Możesz też przypiąć interfejs gry do nowego rozmiaru okna i dodać czarne pasy u góry i u dołu głównej zawartości gry. Jeśli istnieją ograniczenia techniczne lub projektowe uniemożliwiające zastosowanie którejkolwiek z tych metod, zastosuj własne letterboxing w silniku, aby zachować współczynnik proporcji, i skaluj do najlepszych możliwych wymiarów, deklarując resizeableActivity = false i unikając trybu konfiguracji.
Niezależnie od wybranej metody przetestuj grę w różnych konfiguracjach (złożony i rozłożony telefon, różne zmiany orientacji, tryb podzielonego ekranu) i upewnij się, że nie ma obciętych ani nakładających się elementów interfejsu w grze, problemów z dostępnością elementów dotykowych ani problemów z formatem obrazu, które powodują rozciągnięcie, ściśnięcie lub inne zniekształcenie gry.
Większe ekrany zwykle oznaczają większe piksele, ponieważ ta sama liczba pikseli jest rozłożona na znacznie większej powierzchni. Może to powodować pikselizację w przypadku pomniejszonych buforów renderowania lub komponentów o niższej rozdzielczości. Używaj komponentów o najwyższej jakości na urządzeniach z dużym ekranem i sprawdź profil wydajności gry, aby upewnić się, że nie ma żadnych problemów. Jeśli Twoja gra obsługuje wiele poziomów jakości, upewnij się, że uwzględnia ona urządzenia z dużym ekranem.
Tryb wielu okien
Tryb wielu okien umożliwia korzystanie z kilku aplikacji jednocześnie na tym samym ekranie. Tryb wielu okien nie zmienia cyklu życia aktywności, ale stan wznowienia aplikacji w wielu oknach różni się w zależności od wersji Androida (więcej informacji znajdziesz w sekcji Cykl życia aktywności w trybie wielu okien w artykule Obsługa trybu wielu okien).
Gdy gracz przełączy aplikację lub grę w tryb wielu okien, system powiadomi aktywność o zmianie konfiguracji zgodnie z opisem w sekcji Zaawansowana zmiana rozmiaru na dużym ekranie. Zmiana konfiguracji następuje też wtedy, gdy odtwarzacz zmienia rozmiar gry lub przywraca tryb pełnoekranowy.
Nie ma gwarancji, że aplikacja odzyska fokus po przejściu w tryb wielu okien. Jeśli więc używasz zdarzeń stanu aplikacji do wstrzymywania gry, nie polegaj na zdarzeniu uzyskania fokusu (onWindowFocusChanged() z wartością fokusu ustawioną na „true”) w celu wznowienia gry. Zamiast tego użyj innych funkcji obsługi zdarzeń lub funkcji obsługi zmiany stanu, takich jak onConfigurationChanged() lub onResume(). Pamiętaj, że zawsze możesz użyć metody isInMultiWindowMode(), aby sprawdzić, czy bieżąca aktywność jest uruchomiona w trybie wielu okien.
W przypadku okien na komputerach Googlebook, urządzeniach z ChromeOS oraz tabletach i urządzeniach składanych z dużym ekranem początkowe wymiary okna mają duże znaczenie. Gra nie musi być wyświetlana na pełnym ekranie. W takim przypadku musisz określić rozmiar okna. Zalecamy 2 sposoby postępowania.
Pierwsza opcja polega na użyciu określonych atrybutów w tagu <layout> w pliku manifestu Androida. Atrybuty defaultHeight i defaultWidth określają początkowe wymiary. Pamiętaj też o atrybutach minHeight i minWidth, aby uniemożliwić graczom zmianę rozmiaru okna gry na wymiary, których nie obsługujesz. Ostatni atrybut to gravity, który określa, w którym miejscu ekranu pojawi się okno po uruchomieniu. Oto przykładowy tag układu z użyciem tych atrybutów:
<layout android:defaultHeight="500dp"
android:defaultWidth="600dp"
android:gravity="top|end"
android:minHeight="450dp"
android:minWidth="300dp" />
Druga opcja ustawiania rozmiaru okna polega na użyciu dynamicznych granic uruchamiania. Za pomocą parametru setLaunchBounds(Rect) możesz określić początkowe wymiary okna. Jeśli określono pusty prostokąt, aktywność zostanie uruchomiona w stanie zmaksymalizowanym.
Jeśli używasz silników gier Unity lub Unreal, upewnij się, że korzystasz z najnowszej wersji (Unity 2019.4.40 i Unreal 5.3 lub nowszej), która dobrze obsługuje tryb wielu okien.
Składana podpórka
Użyj biblioteki układu WindowManager Jetpack, aby obsługiwać pozycje urządzeń składanych, takie jak tryb stołowy, co zwiększy zaangażowanie graczy:
Kotlin
fun isTableTopPosture(foldFeature : FoldingFeature?) : Boolean { contract { returns(true) implies (foldFeature != null) } return foldFeature?.state == FoldingFeature.State.HALF_OPENED && foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL }
Java
boolean isTableTopPosture(FoldingFeature foldFeature) { return (foldFeature != null) && (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) && (foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL); }