Cómo usar la biblioteca de controles de juegos

Emplea las siguientes funciones para agregar a tu juego la compatibilidad con los controles de juegos con la biblioteca de controles de juegos.

Cómo inicializar y destruir la biblioteca de controles para juegos

Usa la función Paddleboat_init a efectos de inicializar la biblioteca de controles para juegos.

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Paddleboat_init toma dos parámetros:

  • Un puntero para un elemento JNIEnv adjunto al subproceso actual
  • Una referencia de objeto JNI jobject para una clase derivada Context. Cualquier objeto de clase derivada Context resulta válido, incluidos, sin limitaciones, Activity, NativeActivity o GameActivity.

Paddleboat_init muestra PADDLEBOAT_NO_ERROR si la inicialización se realizó con éxito; de lo contrario, se muestra un código de error apropiado.

Puedes usar Paddleboat_isInitialized con el fin de comprobar si la biblioteca de controles para juegos se inicializó correctamente. Se mostrará un valor booleano. Si es verdadero, la API estará disponible para su uso.

bool Paddleboat_isInitialized()

Antes de dejar de usar la aplicación, usa la función Paddleboat_destroy para cerrar la biblioteca de controles para juegos. La función toma un solo parámetro, un puntero para un elemento JNIEnv adjunto al subproceso actual. Es posible que se vuelva a llamar a Paddleboat_init después de Paddleboat_destroy.

void Paddleboat_destroy(JNIEnv *env)

Cómo informar a la biblioteca sobre los eventos de ciclo de vida

Se debe informar a la biblioteca de controles para juegos sobre los eventos onStop y onStart del ciclo de vida de la actividad. Llama a las funciones Paddleboat_onStop y Paddleboat_onStart desde tu código de control de eventos de inicio y detención. Ambas funciones toman un único parámetro: un puntero para un elemento JNIEnv adjunto al subproceso actual.

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

Cómo registrar o quitar una devolución de llamada de estado del control

La biblioteca de controles para juegos usa una devolución de llamada de estado del control a fin de enviar una notificación a un juego cuando se conecta o desconecta un control. Solo admite una devolución de llamada de estado del control por vez.

  • Si deseas registrar una devolución de llamada de estado del control o reemplazar cualquier devolución de llamada registrada con anterioridad por una nueva función de devolución de llamada, llama a la función Paddleboat_setControllerStatusCallback.
  • Para quitar una devolución de llamada registrada, pasa NULL o nullptr.
  • El parámetro userData es un puntero opcional para datos definidos por el usuario. El parámetro userData se pasará a la función de devolución de llamada. Este puntero se retiene internamente hasta que se modifica mediante una llamada posterior a Paddleboat_setControllerStatusCallback.
void Paddleboat_setControllerStatusCallback(Paddleboat_ControllerStatusCallback
  statusCallback, void *userData)

La firma de la función de devolución de llamada es la siguiente:

typedef void (*Paddleboat_ControllerStatusCallback)(
  const int32_t controllerIndex,
  const Paddleboat_ControllerStatus controllerStatus,
  void *userData)
Parámetro Descripción
controllerIndex Índice del controlador que inició la devolución de llamada. Será un valor entre 0 y
PADDLEBOAT_MAX_CONTROLLERS - 1
controllerStatus Valor de enumeración de PADDLEBOAT_CONTROLLER_JUST_CONNECTED o
PADDLEBOAT_CONTROLLER_JUST_DISCONNECTED.
userData Un puntero opcional (puede ser NULO) para datos definidos por el usuario que se especificaron en la última llamada a Paddleboat_setControllerStatusCallback.

Cómo llamar a la función de actualización de la biblioteca de controles para juegos

Se debe llamar a la función de actualización de la biblioteca de controles para juegos, Paddleboat_update, una vez por fotograma de juego, preferentemente cerca del inicio del fotograma. La función toma un solo parámetro, un puntero para un elemento JNIEnv adjunto al subproceso actual.

void Paddleboat_update(JNIEnv *env)

Cómo procesar eventos

Cuando recibes eventos de entrada, tu juego debe reenviarlos a la biblioteca de controles para juegos a fin de realizar una inspección. Esta biblioteca evalúa si un evento de entrada está asociado con uno de sus dispositivos administrados. Los eventos de los dispositivos administrados se procesan y se consumen.

La biblioteca de controles para juegos admite dos tipos de eventos de entrada: AInputEvents y GameActivity.

Cómo procesar AInputEvent

El juego deberá reenviar AInputEvents mediante una llamada a Paddleboat_processInputEvent desde tu código de control de eventos.

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

Paddleboat_processInputEvent mostrará 0 si se omitió el evento y mostrará 1 si la biblioteca de controles para juegos procesó y consumió el evento.

Cómo procesar eventos de GameActivity

Si tu juego usa GameActivity, reenvía los eventos GameActivityKeyEvent y GameActivityMotionEvent llamando a Paddleboat_processGameActivityKeyInputEvent o Paddleboat_processGameActivityMotionInputEvent desde tu código de control de eventos.

int32_t Paddleboat_processGameActivityKeyInputEvent(const void *event,
                                                    const size_t eventSize)
int32_t Paddleboat_processGameActivityMotionInputEvent(const void *event,
                                                       const size_t eventSize)
Parámetro Descripción
event Un puntero para una estructura GameActivityKeyEvent o GameActivityMotionEvent, según la función a la que se llame.
eventSize El tamaño en bytes de la estructura del evento pasado en el parámetro event.

Ambas funciones mostrarán 0 si se omitió el evento y mostrarán 1 si la biblioteca de controles para juegos procesó y consumió el evento.

GameActivity requiere que se especifique el eje de movimiento activo con la función GameActivityPointerAxes_enableAxis. La llamada Paddleboat_getActiveAxisMask muestra una máscara de bits del eje de movimiento actualmente activo que usan los controles conectados.

uint64_t Paddleboat_getActiveAxisMask()

Si deseas ver un ejemplo de cómo controlar esto, consulta la muestra de la biblioteca de controles para juegos que usa GameActivity. Esa muestra consulta la máscara del eje activo e informa a GameActivity cuando se usa un eje nuevo. Esto se implementa en la función 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;
        }
    }
}

Cómo leer los controles

La biblioteca de controles para juegos usa un valor de índice a fin de hacer referencia a un control específico. Los valores de índice válidos varían desde 0 hasta PADDLEBOAT_MAX_CONTROLLERS - 1. La función Paddleboat_getControllerStatus determina el estado de un índice del control especificado.

Paddleboat_ControllerStatus Paddleboat_getControllerStatus(
  const int32_t controllerIndex)

Existen tres funciones para leer información de un control conectado.

Nombre del control

La Paddleboat_getControllerName function toma dos parámetros de entrada: el índice del control, el tamaño del búfer, y un puntero para un búfer a fin de almacenar la string del nombre del control. Esta string tiene el formato de una string C con codificación UTF-8. El nombre del dispositivo se obtiene de manera interna mediante InputDevice.getName().

Si Paddleboat_getControllerName recupera el nombre con éxito, muestra PADDLEBOAT_NO_ERROR; de lo contrario, se muestra un código de error apropiado.

Paddleboat_ErrorCode Paddleboat_getControllerName(const int32_t controllerIndex,
                                                  const size_t bufferSize,
                                                  char *controllerName);
Parámetro Descripción
controllerIndex Índice del controlador que inició la devolución de llamada. Será un valor entre 0 y
PADDLEBOAT_MAX_CONTROLLERS - 1
bufferSize Tamaño en bytes del búfer que pasa controllerName; la string de nombre se truncará si es necesario para que quepa en el búfer.
controllerName Un puntero para un búfer de bufferSize bytes en el que se almacenará el nombre del control. El nombre se almacenará como una string C con codificación UTF-8.

Información del dispositivo de control

La Paddleboat_getControllerInfo function toma dos parámetros de entrada: un índice del control y un puntero para una estructura Paddleboat_Controller_Info.

Si Paddleboat_Controller_Info se propagó con datos de forma correcta, Paddleboat_getControllerInfo muestra PADDLEBOAT_NO_ERROR; de lo contrario, se muestra un código de error adecuado.

Paddleboat_ErrorCode Paddleboat_getControllerInfo(const int32_t controllerIndex,
  Paddleboat_Controller_Info *controllerInfo)

La estructura Paddleboat_Controller_Info contiene información específica del dispositivo de control.

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;

Varios miembros de la estructura se propagan mediante valores tomados del InputDevice asociado con el control:

controllerNumber    -   InputDevice.getControllerNumber()
vendorId              - InputDevice.getVendorId()
productId             - InputDevice.getProductId()
deviceId              - InputDevice.getId()
  • Un valor stickFlat representa la extensión de una posición plana en el centro. Este valor resulta de especial utilidad para calcular la "zona sin cobertura" predeterminada central en dispositivos que se centran solos.
  • Un valor de stickFuzz representa la tolerancia a errores, o cuánto se puede desviar el valor actual del real debido al ruido y a las limitaciones de sensibilidad del dispositivo.

Ambos valores se normalizan en un valor máximo de eje de 1.0 en cualquiera de las dimensiones.

El miembro controllerFlags contiene una combinación de marcas individuales con máscaras de bits y valores de combinación de varios bits.

Realizar una operación lógica AND de controllerFlags con PADDLEBOAT_CONTROLLER_LAYOUT_MASK da como resultado un valor que puede convertirse en la enumeración Paddleboat_ControllerButtonLayout. Esta enumeración especifica el diseño y la iconografía de los botones que usa el control.

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

Las siguientes constantes definen los bits de funciones. A fin de determinar si un control admite una función en particular, realiza una operación lógica AND de la constante correspondiente en controllerFlags. Un resultado distinto de cero significa que el control admite la función.

PADDLEBOAT_CONTROLLER_FLAG_TOUCHPAD

Si se selecciona este bit de marca, el control tiene un panel táctil integrado. Si se presiona el panel táctil, el control establece el bit de PADDLEBOAT_BUTTON_TOUCHPAD en el campo Paddleboat_Controller_Data.buttonsDown.

PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE

Si se selecciona este bit de marca, el control emula un dispositivo apuntador. El miembro virtualPointer de la estructura Paddleboat_Controller_Data se propaga con las coordenadas actuales del puntero virtual.

Datos del control

La función Paddleboat_getControllerData toma dos parámetros de entrada: un índice del control y un puntero para una estructura Paddleboat_Controller_Data. Si Paddleboat_Controller_Data se propagó con datos de forma correcta, Paddleboat_getControllerInfo muestra PADDLEBOAT_NO_ERROR; de lo contrario, se muestra un código de error adecuado.

Paddleboat_ErrorCode Paddleboat_getControllerData(const int32_t controllerIndex,
  Paddleboat_Controller_Data *controllerData)

La estructura Paddleboat_Controller_Data contiene los valores de entrada de control actuales correspondientes al dispositivo de control.

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;

Rangos de valores

Tipo de entrada Rango de valores
Eje de palancas para el pulgar De -1.0 a 1.0
Gatillos De 0.0 a 1.0
Punteros virtuales De 0.0 al ancho o alto de la ventana (en píxeles)

Detalles de la estructura

Miembro de la estructura Descripción
buttonsDown Array de campo de bits con los bits por botón. Las constantes de máscara de bits de los botones se definen en el archivo de encabezado paddleboat.h y comienzan con PADDLEBOAT_BUTTON_.
timestamp. Marca de tiempo del evento de entrada más reciente del control. La marca de tiempo es de microsegundos desde la época.
virtualPointer Ubicación del puntero virtual. Solo es válido si la marca PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE se establece en controllerFlags; de lo contrario, será 0.0, 0.0.