תמיכה בכיווץ של מסך גדול

כשמרחיבים את המשחק ממכשירים ניידים למסכים גדולים, צריך לקחת בחשבון איך המשחק מנהל את החלונות. ב-Googlebook, ב-ChromeOS וב-Google Play Games במחשב, המשחק יכול לפעול במצב חלון על פני ממשק שולחן עבודה ראשי. בטאבלטים ומכשירים מתקפלים חדשים עם Android שפועלת בהם גרסה Android 12L (רמת API‏ 32) ואילך עם רוחב מסך של יותר מ-600dp, אפשר להפעיל את המשחק זה לצד זה במצב מסך מפוצל עם אפליקציות אחרות, לשנות את הגודל שלו ואפילו להעביר אותו בין התצוגה הפנימית והחיצונית במכשירים מתקפלים. כתוצאה מכך, מתבצע שינוי בהגדרות של גודל החלון, ובמכשירים מסוימים גם בכיוון.

שינוי גודל של משחקי Unity

הגדרה בסיסית למסכים גדולים

מציינים אם המשחק יכול לשנות את הגודל שלו:

<android:resizeableActivity="true" or "false" />

אם אין אפשרות לתמוך בשינוי גודל, צריך לוודא שבקובץ המניפסט של המשחק מוגדרים באופן מפורש יחסי הגובה-רוחב המינימליים והמקסימליים הנתמכים:

<!-- 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">

Google Play Games במחשב

ב-Google Play Games במחשב, הפלטפורמה מטפלת בשינוי הגודל של החלון תוך שמירה על יחס הגובה-רוחב שצוין. גודל החלון נעול למידות האופטימליות באופן אוטומטי. אם המשחק שלכם הוא לרוחב, אתם צריכים לתמוך לפחות ביחס גובה-רוחב של 16:9, ואם הוא לאורך, אתם צריכים לתמוך לפחות ביחס גובה-רוחב של 9:16. כדי לקבל את חוויית המשחק הטובה ביותר, צריך לתמוך באופן מפורש ביחסי גובה-רוחב של 21:9,‏ 16:10 ו-3:2 במשחק לרוחב. אין צורך לשנות את גודל החלון כאן, אבל כדאי לעשות את זה כדי ליצור תאימות עם גורמי צורה אחרים.

מידע נוסף ושיטות מומלצות זמינים במאמר הגדרת הגרפיקה ב-Google Play Games במחשב.

מסכים גדולים

כדי למקסם את האזור שבו אפשר לראות את המשחק במסך מלא בטאבלטים עם מסך גדול, במכשירים מתקפלים, ב-Googlebook, ב-ChromeOS ובמסכים מחוברים, צריך לתמוך במצב מסך מלא ולהסתיר את סרגלי המערכת על ידי הגדרת דגלים ב-decorView, בחשיפת ממשק המשתמש של המערכת או באמצעות API של WindowInsetsCompat. כדאי גם לטפל בצורה חלקה באירועי הגדרה של סיבוב ושינוי גודל, או למנוע את ההתרחשות שלהם.

שימו לב: במכשירי Android עם מסך גדול, המשחק יכול לפעול בהגדרות שאולי עדיין לא טיפלתם בהן. אם המשחק לא תומך בכל ההגדרות של גודל החלון והכיוון, הפלטפורמה מוסיפה למשחק פסי שוליים במצב תאימות, ואם צריך, מציגה לשחקן הנחיה לפני מעבר להגדרה לא נתמכת.

איור 1. תיבת דו-שיח של תאימות ההגדרות.

במכשירים מסוימים, כששחקן עובר להגדרה שלא נתמכת, יכול להיות שתופיע לו אפשרות לטעון מחדש את המשחק וליצור מחדש את הפעילות כדי להתאים בצורה הטובה ביותר לפריסת החלון החדשה, מה שמשבש את חוויית המשחק. כדאי לבדוק את המשחק בהגדרות שונות של מצב מרובה חלונות (גודל החלון: 2/3, 1/2, 1/3) ולוודא שרכיבים של המשחק או של ממשק המשתמש לא נחתכים או לא נגישים. בנוסף, כדאי לבדוק איך המשחק מגיב להמשכיות במכשירים מתקפלים כשעוברים בין המסך הפנימי למסך החיצוני. אם מופיעות בעיות, צריך לטפל באופן מפורש באירועי ההגדרה האלה ולהוסיף תמיכה מתקדמת בשינוי גודל המסך.

שינוי גודל מתקדם במסכים גדולים

איור 2. ממשקי משתמש שונים במחשב ובמצב שולחני של טאבלט מתקפל.

כדי לצאת ממצב תאימות ולמנוע יצירה מחדש של פעילות:

  1. מצהירים שהפעילות הראשית ניתנת לשינוי גודל:

    <android:resizeableActivity="true" />
    
  2. כדי לקבל את כל אירועי הגדרת התצורה של מסך גדול, צריך להצהיר על תמיכה מפורשת ב'כיוון', ב'גודל מסך', ב'גודל המסך הקטן ביותר', ב'פריסת המסך' וב'דחיסות' במאפיין android:configChanges של רכיב <activity> במניפסט של המשחק:

    <android:configChanges="screenSize | smallestScreenSize | screenLayout | orientation | keyboard |
                            keyboardHidden | density" />
    
  3. מחליפים את onConfigurationChanged() ומטפלים באירוע ההגדרה, כולל הכיוון הנוכחי, גודל החלון, הרוחב והגובה:

    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();
    }

אפשר גם להריץ שאילתה על WindowManager כדי לבדוק את הסיבוב הנוכחי של המכשיר. בעזרת המטא-נתונים האלה, בודקים את המאפיינים של החלון החדש ומבצעים רינדור לגודל המלא של החלון. יכול להיות שהשיטה הזו לא תעבוד בכל המקרים בגלל הבדלים ביחס הגובה-רוחב. לכן, אפשרות אחרת היא להצמיד את ממשק המשתמש של המשחק לגודל החדש של החלון ולהוסיף מסגרת שחורה לתוכן הליבה של המשחק. אם יש מגבלות טכניות או מגבלות עיצוב שמונעות שימוש באחת מהגישות האלה, אפשר להוסיף את האפקט בעצמכם במנוע כדי לשמור על יחס הגובה-רוחב, ולשנות את הגודל למידות הכי טובות שאפשר תוך הצהרה על resizeableActivity = false והימנעות ממצב הגדרה.

לא משנה באיזו גישה תבחרו, חשוב לבדוק את המשחק בתצורות שונות (קיפול ופתיחה, שינויים שונים בסיבוב, מצב מסך מפוצל) ולוודא שאין אלמנטים בממשק המשתמש של המשחק שנחתכים או חופפים, שאין בעיות בנגישות של אזורי המגע או בעיות ביחס הגובה-רוחב שגורמות למשחק להימתח, להידחס או לעבור עיוות אחר.

בנוסף, במסכים גדולים יותר הפיקסלים בדרך כלל גדולים יותר, כי יש את אותו מספר פיקסלים על שטח גדול בהרבה. התוצאה יכולה להיות פיקסול של מאגרי עיבוד שהוקטנו או של נכסים ברזולוציה נמוכה יותר. כדאי להשתמש בנכסים באיכות הכי גבוהה במכשירים עם מסך גדול וליצור פרופיל ביצועים של המשחק כדי לוודא שאין בעיות. אם המשחק שלכם תומך בכמה רמות איכות, ודאו שהוא מתאים למכשירים עם מסך גדול.

מצב ריבוי חלונות

מצב ריבוי חלונות מאפשר לכמה אפליקציות לחלוק את אותו המסך בו-זמנית. מצב ריבוי חלונות לא משנה את מחזור החיים של הפעילות, אבל המצב של אפליקציות שמופעלות בכמה חלונות שונה בגרסאות שונות של Android (ראו מחזור החיים של הפעילות במצב ריבוי חלונות במאמר תמיכה במצב ריבוי חלונות).

כשהנגן מעביר אפליקציה או משחק למצב ריבוי חלונות, המערכת מודיעה על שינוי בהגדרות הפעילות, כפי שצוין בקטע שינוי גודל מתקדם במסכים גדולים. שינוי בהגדרות התצורה מתרחש גם כשהנגן משנה את גודל המשחק או מחזיר את המשחק למצב מסך מלא.

אין ערובה לכך שהאפליקציה תחזור להתמקד כשהיא תועבר למצב ריבוי חלונות. לכן, אם אתם משתמשים באחד מהאירועים של מצב האפליקציה כדי להשהות את המשחק, אל תסתמכו על אירוע קבלת המיקוד (onWindowFocusChanged() עם ערך המיקוד כ-true) כדי להמשיך את המשחק. במקום זאת, צריך להשתמש ב-handlers אחרים של אירועים או ב-handlers של שינוי מצב, כמו onConfigurationChanged() או onResume(). שימו לב: תמיד אפשר להשתמש בשיטה isInMultiWindowMode() כדי לזהות אם הפעילות הנוכחית מתבצעת במצב חלונות מרובים.

כשמשתמשים בחלונות במחשב ב-Googlebook, ב-ChromeOS ובטאבלטים ובמכשירים מתקפלים עם מסכים גדולים, המידות הראשוניות של החלון הופכות לשיקול חשוב. משחק לא חייב להיות במסך מלא, ותצטרכו להצהיר מה צריך להיות גודל החלון במקרה כזה. יש שתי דרכים מומלצות לעשות את זה.

האפשרות הראשונה פועלת באמצעות מאפיינים ספציפיים בתג <layout> במניפסט של Android. המאפיינים defaultHeight ו-defaultWidth קובעים את המידות הראשוניות. כדאי גם לשים לב למאפיינים minHeight ו-minWidth כדי למנוע מהשחקנים לשנות את הגודל של חלון המשחק למידות שאתם לא תומכים בהן. לבסוף, יש את המאפיין gravity, שקובע איפה במסך יופיע החלון כשהוא יופעל. דוגמה לתג פריסה שמשתמש במאפיינים האלה:

<layout android:defaultHeight="500dp"
        android:defaultWidth="600dp"
        android:gravity="top|end"
        android:minHeight="450dp"
        android:minWidth="300dp" />

האפשרות השנייה להגדרת גודל החלון היא באמצעות גבולות דינמיים להפעלת האפליקציה. באמצעות setLaunchBounds(Rect)⁠⁠, אפשר להגדיר את המימדים של חלון ההתחלה. אם מציינים מלבן ריק, הפעילות מתחילה במצב מוגדל.

בנוסף, אם אתם משתמשים במנועי המשחקים Unity או Unreal, ודאו שאתם משתמשים בגרסה עדכנית (Unity 2019.4.40 ו-Unreal 5.3 ואילך) שמספקת תמיכה טובה במצב מרובה חלונות.

תמיכה במצב של מכשיר מתקפל

כדי לתמוך במצבים של מכשירים מתקפלים, כמו מצב שולחן, ולהגביר את ההתעניינות של השחקנים במשחק, אפשר להשתמש בספריית הפריסה של Jetpack WindowManager:

איור 3. משחק בתנוחת שולחן עם התצוגה הראשית בחלק האנכי של המסך, והפקדים בחלק האופקי.

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);
}