כשמרחיבים את השימוש בטלפונים לגורמי צורה שונים של מסך גדול, יש שיקולים שקשורים לניהול החלונות במשחק. ב-ChromeOS וב-Google Play Games במחשב, המשחק יכול לפעול במצב חלון מעל לממשק ראשי של מחשב. בטאבלטים ומכשירים מתקפלים חדשים עם Android שפועלת בהם גרסת Android 12L (רמת API 32) ומעלה עם רוחב מסך > ברזולוציה של 600dp, המשחק יכול לפעול זה לצד זה במצב מסך מפוצל עם אפליקציות אחרות. אפשר לשנות את הגודל שלו ואפילו להזיז אותו בין המסך הפנימי לתצוגה החיצוני במכשירים מתקפלים. כתוצאה מכך, ההגדרות של גודל החלון ובחלק מהמכשירים ישתנו בהתאם.
הגדרה בסיסית של מסך גדול
עליך להצהיר אם המשחק שלך יכול להתמודד עם אפשרות של ביטול:
<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 במחשב.
במסכים גדולים של ChromeOS ו-Android
כדי להגדיל את האזור לצפייה של המשחק במסך מלא ב-ChromeOS ובמכשירי Android עם מסך גדול, אפשר לתמוך במצב עשיר במסך מלא ולהסתיר את סרגלי המערכת. לשם כך, מגדירים דגלים ב-decorView
, בהרשאות הגישה לממשק המשתמש של המערכת או דרך ה-API של WindowInsetsCompat
. כדאי גם לטפל באלגנטיות בסיבוב ובשינוי הגודל של אירועים של הגדרות אישיות, או למנוע מהם להתרחש במכשירי ChromeOS.
חשוב לזכור: במכשירי Android עם מסך גדול, המשחק יכול לפעול בהגדרות שעדיין לא טופלו. אם המשחק לא תומך בכל הגדרות הגודל והכיוון של החלונות, המשחק יוצג בפורמט letterbox בפלטפורמות אחרות במצב תאימות. במקרה הצורך, השחקן יציג הנחיה לפני המעבר להגדרה שלא נתמכת.
במכשירים מסוימים, כששחקן עובר לתצורה שלא נתמכת, יכול להיות שתוצג לו אפשרות לטעון את המשחק מחדש וליצור מחדש את הפעילות כך שתתאים בצורה הטובה ביותר לפריסת החלון החדש, מה שמפריע את חוויית המשחק. בודקים את המשחק בכמה תצורות שונות של מצב ריבוי חלונות (2/3, 1/2 או 1/3 חלונות) ומוודאים שלא נחתכים או לא נגישים לרכיבים של הגיימפליי או בממשק המשתמש. בנוסף, אפשר לבדוק איך המשחק מגיב להמשכיות מתקפלת כשעוברים בין המסך הפנימי למסך החיצוני במכשירים מתקפלים. אם נתקלים בבעיות, צריך לטפל באירועי ההגדרה האלה באופן מפורש ולהוסיף תמיכה מתקדמת בהגבלה של מסכים גדולים.
הגבלה מתקדמת של מסך גדול
כדי לצאת ממצב התאימות ולהימנע מצפייה בפעילות גופנית, יש לבצע את הפעולות הבאות:
להצהיר על הפעילות העיקרית שלך כשניתן לשנות את גודלה:
<android:resizeableActivity="true" />
להצהיר על תמיכה מפורשת ב-orientation, screenSize, smallestScreenSize, screenLayout ו-density במאפיין
android:configChanges
שברכיב<activity>
בקובץ המניפסט של המשחק כדי לקבל את כל האירועים של הגדרת מסך גדול:<android:configChanges="screenSize | smallestScreenSize | screenLayout | orientation | keyboard | keyboardHidden | density" />
ביטול של
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
כדי לבדוק את סיבוב המכשירים הנוכחי. באמצעות מטא-נתונים אלה, בודקים את מידות החלון החדש ומעבדים אותו לגודל החלון המלא. יכול להיות שהשיטה הזו לא תעבוד בכל המקרים בגלל הבדלים ביחס גובה-רוחב. לכן, מומלץ לעגן את ממשק המשתמש של המשחק לגודל החלון החדש או לפורמט letterbox לתוכן העיקרי של מהלך המשחק. אם יש מגבלות טכניות או מגבלות עיצוב שמונעות את הגישה הזו, אתם יכולים ליצור פורמט letterbox משלכם במנוע כדי לשמר את יחס הגובה-רוחב, ולשנות את הגודל למידות הטובות ביותר תוך הצהרה על resizeableActivity = false
ולהימנע ממצב תצורה.
ללא קשר לגישה הרצויה, בודקים את המשחק בתצורות שונות (מצב קיפול ופתיחה, שינויים שונים בסיבוב, מצב מסך מפוצל) ומוודאים שאין חיתוך או חפיפה בין רכיבים בממשק המשתמש במשחק, בעיות בנגישות ליעד מגע או בעיות ביחס גובה-רוחב שעלולות לגרום למתיחה, לכיווץ או לעיוות אחר במשחק.
בנוסף, במסכים גדולים יותר בדרך כלל המשמעות היא פיקסלים גדולים יותר, כי יש לכם אותו מספר פיקסלים באזור הרבה יותר גדול. הדבר עלול לגרום לתצוגת פיקסלים עבור מאגרי נתונים זמניים של רינדור או בנכסים עם רזולוציה נמוכה יותר. מומלץ להשתמש בנכסים באיכות הגבוהה ביותר במכשירים עם מסך גדול ובפרופיל ביצועים של המשחק כדי לוודא שלא יהיו בעיות. אם המשחק תומך בכמה רמות איכות, כדאי לוודא שהוא מתאים למכשירים עם מסך גדול.
מצב ריבוי חלונות
מצב ריבוי חלונות מאפשר לאפליקציות מרובות לשתף את אותו המסך בו-זמנית. מצב ריבוי חלונות לא משנה את מחזור החיים של הפעילות. עם זאת, המצב המחודש של אפליקציות במספר חלונות שונה בגרסאות שונות של Android (ראו מחזור חיים של פעילות במצב ריבוי חלונות בקטע תמיכה במצב ריבוי חלונות).
כשהשחקן מעביר אפליקציה או משחק למצב 'ריבוי חלונות', המערכת מודיעה לפעילות על שינוי ההגדרה כפי שמתואר בקטע הגבלה מתקדמת של מסך גדול. שינוי הגדרה מתרחש גם כשהשחקן משנה את גודל המשחק או מחזיר את המשחק למצב מסך מלא.
אי אפשר להבטיח שהאפליקציה תתמקד מחדש כשהיא תועבר למצב 'ריבוי חלונות'. לכן, אם משתמשים באירוע של מצב האפליקציה כדי להשהות את המשחק, אין להסתמך על אירוע המיקוד של צירוף המשתמשים (onWindowFocusChanged()
כאשר ערך המיקוד מוגדר כ-true) כדי להמשיך את המשחק. במקום זאת, צריך להשתמש בגורמים אחרים המטפלים באירועים או בשינויי מצב, כמו onConfigurationChanged()
או onResume()
. לתשומת ליבכם: תמיד אפשר להשתמש בשיטה isInMultiWindowMode()
כדי לזהות אם הפעילות הנוכחית פועלת במצב של ריבוי חלונות.
במצב ריבוי חלונות ב-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 ואילך) שמספקת תמיכה טובה במצב ריבוי חלונות.
תמיכה ביציבה מתקפלת
תוכלו להשתמש בספריית הפריסה של Windows Manager ב-Jetpack כדי לתמוך במצבים מתקפלים כמו שולחניות, כדי להגביר את העניין של השחקנים ולעודד אותם להתנסות:
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); }