使用游戏控制器库

使用以下函数通过游戏控制器库为您的游戏添加游戏控制器支持。

初始化和销毁游戏控制器库

使用 Paddleboat_init 函数初始化游戏控制器库。

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Paddleboat_init 接受两个参数:

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

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

bool Paddleboat_isInitialized()

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

void Paddleboat_destroy(JNIEnv *env)

通知库生命周期事件

必须将 activity 生命周期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,请通过从事件处理代码中调用 Paddleboat_processGameActivityKeyInputEventPaddleboat_processGameActivityMotionInputEvent 来转发 GameActivityKeyEventGameActivityMotionEvent 事件。

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