Используйте библиотеку игрового контроллера

Используйте следующие функции для добавления поддержки игрового контроллера в вашу игру с помощью библиотеки игровых контроллеров.

Инициализируйте и удалите библиотеку игрового контроллера

Используйте функцию Paddleboat_init для инициализации библиотеки игрового контроллера.

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 . Функция возвращает логическое значение. Если значение равно true, API доступен для использования.

bool Paddleboat_isInitialized()

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

void Paddleboat_destroy(JNIEnv *env)

Информировать библиотеку о событиях жизненного цикла

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

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

Регистрация или удаление обратного вызова статуса контроллера

Библиотека игровых контроллеров использует функцию обратного вызова статуса контроллера для уведомления игры о его подключении или отключении. Она поддерживает только одну функцию обратного вызова статуса контроллера одновременно.

  • Чтобы зарегистрировать обратный вызов состояния контроллера или заменить любой ранее зарегистрированный обратный вызов новой функцией обратного вызова, вызовите функцию 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)

События процесса

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

Библиотека игровых контроллеров поддерживает два типа событий ввода: события ввода AInputEvents и события ввода GameActivity .

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

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

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

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

Обработка событий 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 если событие было обработано и использовано библиотекой игрового контроллера.

Для 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;
        }
    }
}

Контроллеры чтения

Библиотека игровых контроллеров использует индексное значение для ссылки на конкретный контроллер. Допустимые значения индекса находятся в диапазоне от 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 .