Как использовать библиотеку Game Controller

Чтобы добавить в игру поддержку контроллера, используйте библиотеку Game Controller и следующие функции:

Инициализация и уничтожение библиотеки Game Controller

Используйте функцию Paddleboat_init, чтобы инициализировать библиотеку Game Controller.

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Функция Paddleboat_init принимает два параметра:

  • Указатель на JNIEnv, прикрепленный к текущему потоку
  • Ссылка на объект JNI jobject для производного класса Context. Допустим любой объект производного класса Context, в том числе Activity, NativeActivity или GameActivity.

Paddleboat_init возвращает PADDLEBOAT_NO_ERROR, если инициализация прошла успешно, в противном случае возвращается соответствующий код ошибки.

Вы можете использовать Paddleboat_isInitialized, чтобы проверить, успешно ли инициализирована библиотека Game Controller. Функция возвращает логическое значение. Если указано значение true, API доступен для использования.

bool Paddleboat_isInitialized()

Перед завершением работы приложения используйте функцию Paddleboat_destroy, чтобы закрыть библиотеку контроллера. Функция принимает один параметр – указатель на объект JNIEnv, прикрепленный к текущему потоку. Paddleboat_init можно вызвать снова после Paddleboat_destroy.

void Paddleboat_destroy(JNIEnv *env)

Как сообщать библиотеке о событиях жизненного цикла

Библиотека Game Controller должна получать информацию о жизненном цикле объекта activity, а также о событиях onStop и onStart. Вызовите функции Paddleboat_onStop и Paddleboat_onStart из кода обработчика событий остановки и запуска. Обе функции принимают один параметр – указатель на объект JNIEnv, прикрепленный к текущему потоку.

void Paddleboat_onStop(JNIEnv *env)
void Paddleboat_onStart(JNIEnv *env)

Как зарегистрировать или удалить обратный вызов статуса контроллера

Библиотека Game Controller использует обратный вызов статуса контроллера, чтобы уведомлять игру о подключении или отключении контроллера. Одновременно поддерживается только один обратный вызов статуса контроллера.

  • Чтобы зарегистрировать обратный вызов статуса контроллера или заменить ранее зарегистрированный обратный вызов новой функцией обратного вызова, вызовите функцию Paddleboat_setControllerStatusCallback.
  • Чтобы удалить зарегистрированный обратный вызов, передайте NULL или nullptr.
  • Параметр userData – это необязательный указатель на данные, заданные пользователем. Параметр userData будет передан функции обратного вызова. Этот указатель хранится внутри системы, пока не будет изменен при последующем вызове функции Paddleboat_setControllerStatusCallback.
void Paddleboat_setControllerStatusCallback(Paddleboat_ControllerStatusCallback
  statusCallback, void *userData)

Подпись функции обратного вызова выглядит следующим образом:

typedef void (*Paddleboat_ControllerStatusCallback)(
  const int32_t controllerIndex,
  const Paddleboat_ControllerStatus controllerStatus,
  void *userData)
Параметр Описание
controllerIndex Индекс контроллера, который инициировал обратный вызов. Значение от 0 до
. PADDLEBOAT_MAX_CONTROLLERS - 1
controllerStatus Перечисляемое значение PADDLEBOAT_CONTROLLER_JUST_CONNECTED или
PADDLEBOAT_CONTROLLER_JUST_DISCONNECTED.
userData Необязательный указатель (может иметь значение NULL) на пользовательские данные, заданные последним вызовом функции Paddleboat_setControllerStatusCallback.

Вызовите функцию обновления библиотеки контроллера игр

Функцию обновления библиотеки игрового контроллера, Paddleboat_update, следует вызывать один раз за кадр игры, желательно в начале кадра. Функция принимает один параметр – указатель на объект JNIEnv, прикрепленный к текущему потоку.

void Paddleboat_update(JNIEnv *env)

Обработка событий

При получении событий ввода игра должна пересылать их в библиотеку Game Controller для проверки. Библиотека Game Controller определяет, связано ли событие ввода с одним из управляемых ею устройств. События с управляемых устройств обрабатываются и используются.

Библиотека Game Controller поддерживает два типа событий ввода: AInputEvents и GameActivity.

Обработка событий ввода AInputEvent

Ваша игра должна пересылать AInputEvents, вызывая Paddleboat_processInputEvent из кода обработчика событий.

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

Paddleboat_processInputEvent возвращает 0, если событие было проигнорировано, и 1, если оно было обработано библиотекой Game Controller.

Обработка событий GameActivity

Если в вашей игре используется GameActivity, пересылайте события GameActivityKeyEvent и GameActivityMotionEvent, вызывая Paddleboat_processGameActivityKeyInputEvent или Paddleboat_processGameActivityMotionInputEvent из кода обработки событий.

int32_t Paddleboat_processGameActivityKeyInputEvent(const void *event,
                                                    const size_t eventSize)
int32_t Paddleboat_processGameActivityMotionInputEvent(const void *event,
                                                       const size_t eventSize)
Параметр Описание
event Указатель на структуру GameActivityKeyEvent или GameActivityMotionEvent в зависимости от того, какая функция вызывается.
eventSize Размер структуры события в байтах, переданной в параметре event.

Обе функции возвращают значение 0, если событие было проигнорировано, и 1, если оно было обработано и использовано библиотекой Game Controller.

Для атрибута "ось движения" GameActivity необходимо указать активную ось движения с помощью функции GameActivityPointerAxes_enableAxis. Вызов Paddleboat_getActiveAxisMask возвращает битовую маску активных осей движения, используемых подключенными контроллерами.

uint64_t Paddleboat_getActiveAxisMask()

Пример того, как это можно сделать, приведен в образце библиотеки Game Controller, в котором используется GameActivity. Пример опрашивает активную маску оси и сообщает GameActivity, когда используются новые оси. Это реализовано в функции NativeEngine::CheckForNewAxis().

void NativeEngine::CheckForNewAxis() {
    // Tell GameActivity about any new axis ids so it reports
    // their events
    const uint64_t activeAxisIds = Paddleboat_getActiveAxisMask();
    uint64_t newAxisIds = activeAxisIds ^ mActiveAxisIds;
    if (newAxisIds != 0) {
        mActiveAxisIds = activeAxisIds;
        int32_t currentAxisId = 0;
        while(newAxisIds != 0) {
            if ((newAxisIds & 1) != 0) {
                LOGD("Enable Axis: %d", currentAxisId);
                GameActivityPointerAxes_enableAxis(currentAxisId);
            }
            ++currentAxisId;
            newAxisIds >>= 1;
        }
    }
}

Чтение данных контроллеров

Библиотека Game Controller использует индексное значение для ссылки на определенный контроллер. Допустимые значения индекса: от 0 до PADDLEBOAT_MAX_CONTROLLERS - 1. Функция Paddleboat_getControllerStatus определяет статус указанного индекса контроллера.

Paddleboat_ControllerStatus Paddleboat_getControllerStatus(
  const int32_t controllerIndex)

Существует три функции для чтения информации с подключенного контроллера.

Название контроллера

Функция Paddleboat_getControllerName function принимает два входных параметра: индекс контроллера, размер буфера и указатель на буфер, в котором будет храниться строка с названием контроллера. Строка имени отформатирована как строка C с использованием кодировки UTF-8. Название устройства определяется внутренним образом с помощью InputDevice.getName().

Если Paddleboat_getControllerName успешно получает имя, возвращается PADDLEBOAT_NO_ERROR, в противном случае возвращается соответствующий код ошибки.

Paddleboat_ErrorCode Paddleboat_getControllerName(const int32_t controllerIndex,
                                                  const size_t bufferSize,
                                                  char *controllerName);
Параметр Описание
controllerIndex Индекс контроллера, который инициировал обратный вызов. Значение от 0 до
. PADDLEBOAT_MAX_CONTROLLERS - 1
bufferSize Размер буфера в байтах, переданного функцией controllerName. Если необходимо, строка названия будет усечена, чтобы поместиться в буфер.
controllerName Указатель на буфер размером bufferSize байт, в котором будет храниться название контроллера. Имя будет храниться как строка C в кодировке UTF-8.

Информация об устройстве контроллера

Функция Paddleboat_getControllerInfo function принимает два входных параметра: индекс контроллера и указатель на структуру Paddleboat_Controller_Info.

Если в Paddleboat_Controller_Info успешно добавлены данные, Paddleboat_getControllerInfo возвращает PADDLEBOAT_NO_ERROR, в противном случае возвращается соответствующий код ошибки.

Paddleboat_ErrorCode Paddleboat_getControllerInfo(const int32_t controllerIndex,
  Paddleboat_Controller_Info *controllerInfo)

Структура Paddleboat_Controller_Info содержит информацию о контроллере, относящуюся к определенному устройству.

typedef struct Paddleboat_Controller_Info {
    uint32_t controllerFlags;
    int32_t controllerNumber;
    int32_t vendorId;
    int32_t productId;
    int32_t deviceId;
    Paddleboat_Controller_Thumbstick_Precision leftStickPrecision;
    Paddleboat_Controller_Thumbstick_Precision rightStickPrecision;
} Paddleboat_Controller_Info;

typedef struct Paddleboat_Controller_Thumbstick_Precision {
    float stickFlatX;
    float stickFlatY;
    float stickFuzzX;
    float stickFuzzY;
} Paddleboat_Controller_Thumbstick_Precision;

Некоторые члены структуры заполняются значениями, взятыми из InputDevice, связанного с контроллером:

controllerNumber    -   InputDevice.getControllerNumber()
vendorId              - InputDevice.getVendorId()
productId             - InputDevice.getProductId()
deviceId              - InputDevice.getId()
  • Значение stickFlat представляет собой степень центрального положения. Это значение в основном используется для расчета центральной мертвой зоны на устройствах с автоматическим центрированием.
  • Значение stickFuzz представляет собой допустимую погрешность, то есть насколько текущее значение может отличаться от фактического из-за шума и ограничений чувствительности устройства.

Оба значения нормализуются до максимального значения оси 1.0 в любом измерении.

Член controllerFlags содержит комбинацию отдельных битовых масок и многобитовых значений.

Выполнение логической операции AND над controllerFlags и PADDLEBOAT_CONTROLLER_LAYOUT_MASK приводит к значению, которое можно привести к перечислению Paddleboat_ControllerButtonLayout. Этот перечисляемый тип определяет значки и макет кнопок, используемые контроллером.

enum Paddleboat_ControllerButtonLayout {
    //  Y
    // X B
    //  A
    PADDLEBOAT_CONTROLLER_LAYOUT_STANDARD = 0,
    //  △
    // □ ○
    //  x
    PADDLEBOAT_CONTROLLER_LAYOUT_SHAPES = 1,
    //  X
    // Y A
    //  B
    PADDLEBOAT_CONTROLLER_LAYOUT_REVERSE = 2,
    // X Y R1 L1
    // A B R2 L2
    PADDLEBOAT_CONTROLLER_LAYOUT_ARCADE_STICK = 3,
    PADDLEBOAT_CONTROLLER_LAYOUT_MASK = 3
};

Следующие константы определяют биты возможностей. Чтобы определить, поддерживает ли контроллер определенную функцию, выполните логическую операцию AND соответствующей константы с controllerFlags. Ненулевой результат означает, что контроллер поддерживает эту функцию.

PADDLEBOAT_CONTROLLER_FLAG_TOUCHPAD

Если этот бит установлен, у контроллера есть встроенная сенсорная панель. Если нажать на сенсорную панель, контроллер установит бит PADDLEBOAT_BUTTON_TOUCHPAD в поле Paddleboat_Controller_Data.buttonsDown.

PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE

Если этот флаг установлен, контроллер эмулирует указатель. Поле virtualPointer структуры Paddleboat_Controller_Data заполняется текущими координатами виртуального указателя.

Данные контроллера

Функция Paddleboat_getControllerData принимает два входных параметра: индекс контроллера и указатель на структуру Paddleboat_Controller_Data. Если в Paddleboat_Controller_Data успешно добавлены данные, Paddleboat_getControllerInfo возвращает PADDLEBOAT_NO_ERROR, в противном случае возвращается соответствующий код ошибки.

Paddleboat_ErrorCode Paddleboat_getControllerData(const int32_t controllerIndex,
  Paddleboat_Controller_Data *controllerData)

Структура Paddleboat_Controller_Data содержит текущие значения входных данных контроллера.

typedef struct Paddleboat_Controller_Data {
    uint64_t timestamp;
    uint32_t buttonsDown;
    Paddleboat_Controller_Thumbstick leftStick;
    Paddleboat_Controller_Thumbstick rightStick;
    float triggerL1;
    float triggerL2;
    float triggerR1;
    float triggerR2;
    Paddleboat_Controller_Pointer virtualPointer;
} Paddleboat_Controller_Data;

typedef struct Paddleboat_Controller_Pointer {
    float pointerX;
    float pointerY;
} Paddleboat_Controller_Pointer;

typedef struct Paddleboat_Controller_Thumbstick {
    float stickX;
    float stickY;
} Paddleboat_Controller_Thumbstick;

Диапазоны значений

Тип входных данных Диапазон значений
Ось аналогового стика -1.0 – 1.0
Триггеры 0.0 – 1.0
Виртуальные указатели 0.0 – ширина/высота окна (в пикселях).

Сведения о структуре

Участник дома Описание
buttonsDown Массив битовых полей для каждой кнопки. Константы битовой маски кнопок определены в заголовочном файле paddleboat.h и начинаются с PADDLEBOAT_BUTTON_.
timestamp. Временная метка последнего события ввода с контроллера. Временная метка – это количество микросекунд, прошедших с начала эпохи.
virtualPointer Местоположение виртуального указателя. Действительно, только если в controllerFlags задан флаг PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE, в противном случае будет 0.0, 0.0.