利用 Game Controller 库通过以下函数为您的游戏添加游戏控制器支持。
初始化和销毁 Game Controller 库
使用 Paddleboat_init 函数初始化 Game Controller 库。
Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)
Paddleboat_init 接受以下两个参数:
- 指向附加到当前线程的
JNIEnv的指针 - 对
Context派生类的jobjectJNI 对象引用。任何Context派生类对象都有效,包括但不限于:Activity、NativeActivity或GameActivity。
如果初始化成功,Paddleboat_init 会返回 PADDLEBOAT_NO_ERROR,否则会返回相应错误代码。
您可以使用 Paddleboat_isInitialized 检查 Game Controller 库是否已成功初始化。它会返回一个布尔值。如果为 true,则该 API 可供使用。
bool Paddleboat_isInitialized()
在终止应用之前,请使用 Paddleboat_destroy 函数关闭 Game Controller 库。该函数接受一个参数,即指向附加到当前线程的 JNIEnv 的指针。可以在调用 Paddleboat_destroy 之后再次调用 Paddleboat_init。
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
|
指向上次调用 Paddleboat_setControllerStatusCallback 时指定的用户定义数据的可选指针(可以为 NULL)。 |
调用 Game Controller 库更新函数
应为每个游戏帧调用一次 Game Controller 库更新函数 Paddleboat_update,最好是在帧即将开始时调用。该函数接受一个参数,即指向附加到当前线程的 JNIEnv 的指针。
void Paddleboat_update(JNIEnv *env)
处理事件
在接收输入事件时,您的游戏需要将其转发到 Game Controller 库以进行检查。Game Controller 库会评估输入事件是否与它的某个受管设备相关联。Game Controller 库会处理和使用受管设备上的事件。
Game Controller 库支持两种类型的输入事件:AInputEvents 和 GameActivity 输入事件。
AInputEvent 处理
您的游戏应通过调用您的事件处理代码中的 Paddleboat_processInputEvent 来转发 AInputEvents。
int32_t Paddleboat_processInputEvent(const AInputEvent *event)
如果事件被忽略,Paddleboat_processInputEvent 会返回 0;如果事件由 Game Controller 库处理和使用,则返回 1。
GameActivity 事件处理
如果您的游戏使用 GameActivity,则通过调用您的事件处理代码中的 Paddleboat_processGameActivityKeyInputEvent 或 Paddleboat_processGameActivityMotionInputEvent 来转发 GameActivityKeyEvent 和 GameActivityMotionEvent 事件。
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;如果事件由 Game Controller 库处理和使用,则返回 1。
GameActivity 要求使用 GameActivityPointerAxes_enableAxis 函数指定正在使用的动作轴。Paddleboat_getActiveAxisMask 调用会返回由已连接的控制器使用且当前正在使用的动作轴的位掩码。
uint64_t Paddleboat_getActiveAxisMask()
如需通过示例了解如何对此进行处理,请参阅使用 GameActivity 的 Game Controller 库示例。该示例会轮询正在使用的轴的掩码,并且在使用新轴时通知 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函数用于检索控制器设备的名称。Paddleboat_getControllerInfo函数用于检索与控制器设备本身相关的数据。Paddleboat_getControllerData函数用于检索控制器输入的当前状态。
控制器名称
Paddleboat_getControllerName function 接受三个输入参数:控制器索引、缓冲区空间,以及指向用于存储控制器名称字符串的缓冲区的指针。名称字符串的格式为使用 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 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 成员包含以下值的组合:各个采用位掩码的标志和多位组合值。
使用 PADDLEBOAT_CONTROLLER_LAYOUT_MASK 执行 controllerFlags 的逻辑 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.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。 |