使用游戏手柄库

使用以下函数将游戏手柄支持添加到您的游戏中,使用游戏手柄库。

初始化和销毁游戏手柄库

使用 Paddleboat_init 函数初始化游戏手柄库。

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Paddleboat_init 接受两个参数

Paddleboat_init 如果初始化成功,则返回 PADDLEBOAT_NO_ERROR,否则返回相应的错误代码。

您可以使用 Paddleboat_isInitialized 检查游戏手柄库是否已成功初始化。它返回一个布尔值。如果为真,则 API 可供使用。

bool Paddleboat_isInitialized()

在终止应用程序之前,使用 Paddleboat_destroy 函数关闭游戏手柄库。该函数接受一个参数,即指向附加到当前线程的 JNIEnv 的指针。 Paddleboat_init 可以在 Paddleboat_destroy 之后再次调用。

void Paddleboat_destroy(JNIEnv *env)

通知库生命周期事件

游戏手柄库必须通知 活动生命周期 onStoponStart 事件。从您的停止和启动事件处理代码中调用 Paddleboat_onStopPaddleboat_onStart 函数。这两个函数都接受一个参数:指向附加到当前线程的 JNIEnv 的指针。

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

注册或删除手柄状态回调

游戏手柄库使用手柄状态回调来通知游戏何时连接或断开手柄。它一次只支持一个手柄状态回调。

  • 要注册手柄状态回调或用新回调函数替换任何先前注册的回调函数,请调用 Paddleboat_setControllerStatusCallback 函数。
  • 要删除任何当前注册的回调函数,请传递 NULLnullptr
  • 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)

处理事件

在接收输入事件时,您的游戏需要将这些事件转发给游戏手柄库以供检查。游戏手柄库会评估输入事件是否与它管理的其中一个设备相关联。来自管理设备的事件将被处理和使用。

游戏手柄库支持两种类型的输入事件:AInputEventsGameActivity 输入事件。

AInputEvent 处理

您的游戏应该通过从您的事件处理代码中调用 Paddleboat_processInputEvent 来转发 AInputEvents

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

Paddleboat_processInputEvent 如果事件被忽略,则返回 0;如果事件被游戏手柄库处理和使用,则返回 1

GameActivity 事件处理

如果您的游戏使用 GameActivity,请通过从您的事件处理代码中调用 GameActivityKeyEventGameActivityMotionEvent 事件来转发 Paddleboat_processGameActivityKeyInputEventPaddleboat_processGameActivityMotionInputEvent

int32_t Paddleboat_processGameActivityKeyInputEvent(const void *event,
                                                    const size_t eventSize)
int32_t Paddleboat_processGameActivityMotionInputEvent(const void *event,
                                                       const size_t eventSize)
参数 描述
event 指向 GameActivityKeyEventGameActivityMotionEvent 结构体的指针,具体取决于调用哪个函数。
eventSize 传递给 event 参数的事件结构体的大小(以字节为单位)。

这两个函数如果事件被忽略,则返回 0;如果事件被游戏手柄库处理和使用,则返回 1

GameActivity 需要使用 GameActivityPointerAxes_enableAxis 函数来指定活动运动轴。 Paddleboat_getActiveAxisMask 调用返回一个位掩码,表示连接的控制器当前使用的活动运动轴。

uint64_t Paddleboat_getActiveAxisMask()

有关如何处理此问题的示例,请参阅使用 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;
        }
    }
}

读取控制器

游戏控制器库使用索引值来引用特定控制器。有效的索引值范围从 0PADDLEBOAT_MAX_CONTROLLERS - 1Paddleboat_getControllerStatus 函数确定指定控制器索引的状态。

Paddleboat_ControllerStatus Paddleboat_getControllerStatus(
  const int32_t controllerIndex)

有三个函数用于从连接的控制器读取信息。

控制器名称

Paddleboat_getControllerName 函数 接受两个输入参数:控制器索引、缓冲区大小和指向用于存储控制器名称字符串的缓冲区的指针。名称字符串使用 UTF-8 编码格式化为 C 字符串。设备的名称是使用 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 字节缓冲区的指针,用于存储控制器名称。该名称将以使用 UTF-8 编码的 C 字符串形式存储。

控制器设备信息

Paddleboat_getControllerInfo 函数 接受两个输入参数:控制器索引和指向 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 成员包含单个位掩码标志和多位组合值的组合。

执行 controllerFlagsPADDLEBOAT_CONTROLLER_LAYOUT_MASK 的逻辑 AND 操作会生成一个值,该值可以转换为 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
};

以下常量定义功能位。若要确定控制器是否支持特定功能,请执行相应常量与 controllerFlags 的逻辑 AND 操作。非零结果表示该功能受控制器支持。

PADDLEBOAT_CONTROLLER_FLAG_TOUCHPAD

如果设置了此标志位,则控制器具有集成触控板。如果按下触控板,控制器将在 Paddleboat_Controller_Data.buttonsDown 字段中设置 PADDLEBOAT_BUTTON_TOUCHPAD 位。

PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE

如果设置了此标志位,则控制器模拟指针设备。 Paddleboat_Controller_Data 结构的 virtualPointer 成员将填充有虚拟指针的当前坐标。

控制器数据

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.01.0
扳机 0.01.0
虚拟指针 0.0 到窗口宽度/高度(以像素为单位)

结构细节

结构成员 描述
buttonsDown 每按钮位域数组。按钮位掩码常量在 paddleboat.h 中定义。头文件,并以 PADDLEBOAT_BUTTON_ 开头。
timestamp. 最近控制器输入事件的时间戳。时间戳是自时钟纪元以来的微秒数。
virtualPointer 虚拟指针位置。仅在 controllerFlags 中设置了 PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE 标志时才有效,否则将为 0.0, 0.0