תמיכה בכמה שלטים לגיימינג

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

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

מיפוי נגנים למזהי מכשירים עם בקר

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

הערה: במכשירים שבהם פועל Android 4.1 (API) ברמה 16 ומעלה), אפשר לקבל מתאר של מכשיר קלט באמצעות getDescriptor(), שמחזירה ערך מחרוזת קבוע למכשיר הקלט. בניגוד למזהה מכשיר, התיאור הערך לא ישתנה גם אם מכשיר הקלט מנותק, מחובר מחדש או הוגדרה מחדש.

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

הקריאה החוזרת (callback) של onInputDeviceAdded() ושל onInputDeviceRemoved() וה-methods הן חלק משכבת ההפשטה שאנחנו מציגים תמיכה בנאמני מידע בכל גרסאות Android. על ידי הטמעת הכללים האלה קריאות חוזרות (callback) של המאזינים, המשחק יכול לזהות את מזהה המכשיר של בקר המשחקים כאשר בוצעה הוספה או הסרה של בקר משחקים. הזיהוי הזה תואם ל-Android מגרסה 2.3 (API ברמה 9) ומעלה.

Kotlin

private val ships = SparseArray<Ship>()

override fun onInputDeviceAdded(deviceId: Int) {
    getShipForID(deviceId)
}

override fun onInputDeviceRemoved(deviceId: Int) {
    removeShipForID(deviceId)
}

private fun getShipForID(shipID: Int): Ship {
    return ships.get(shipID) ?: Ship().also {
        ships.append(shipID, it)
    }
}

private fun removeShipForID(shipID: Int) {
    ships.remove(shipID)
}

Java

private final SparseArray<Ship> ships = new SparseArray<Ship>();

@Override
public void onInputDeviceAdded(int deviceId) {
    getShipForID(deviceId);
}

@Override
public void onInputDeviceRemoved(int deviceId) {
    removeShipForID(deviceId);
}

private Ship getShipForID(int shipID) {
    Ship currentShip = ships.get(shipID);
    if ( null == currentShip ) {
        currentShip = new Ship();
        ships.append(shipID, currentShip);
    }
    return currentShip;
}

private void removeShipForID(int shipID) {
    ships.remove(shipID);
}

עיבוד קלט של כמה בקרים

המשחק שלך צריך להפעיל את הלולאה הבאה כדי לעבד קלט מכמה בקרים:

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

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

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

Kotlin

override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
    if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) {
        event.deviceId.takeIf { it != -1 }?.also { deviceId ->
            val currentShip: Ship = getShipForID(deviceId)
            // Based on which key was pressed, update the player avatar
            // (e.g. set the ship headings or fire lasers)
            return true
        }
    }
    return super.onKeyDown(keyCode, event)
}

Java

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((event.getSource() & InputDevice.SOURCE_GAMEPAD)
                == InputDevice.SOURCE_GAMEPAD) {
        int deviceId = event.getDeviceId();
        if (deviceId != -1) {
            Ship currentShip = getShipForId(deviceId);
            // Based on which key was pressed, update the player avatar
            // (e.g. set the ship headings or fire lasers)
            ...
            return true;
        }
    }
    return super.onKeyDown(keyCode, event);
}

הערה: השיטה המומלצת היא לקבוע אם המשתמש בקר המשחק מתנתק, צריך להשהות את המשחק ולשאול אם המשתמש רוצה להתחבר מחדש.