Sử dụng thư viện Tay điều khiển trò chơi

Hãy sử dụng các hàm sau để thêm tính năng hỗ trợ tay điều khiển trò chơi bằng cách sử dụng thư viện Tay điều khiển trò chơi.

Khởi động và huỷ bỏ thư viện Tay điều khiển trò chơi

Sử dụng hàm Paddleboat_init để khởi động thư viện Tay điều khiển trò chơi.

Paddleboat_ErrorCode Paddleboat_init(JNIEnv *env, jobject jcontext)

Paddleboat_init nhận hai thông số:

  • Con trỏ trỏ đến JNIEnv được gắn với luồng hiện tại
  • Đối tượng JNI jobject tham chiếu đến lớp cơ sở Context. Mọi đối tượng lớp cơ sở xuất phát từ Context đều hợp lệ, bao gồm nhưng không giới hạn ở Activity, NativeActivity hoặc GameActivity.

Paddleboat_init sẽ trả về PADDLEBOAT_NO_ERROR nếu khởi động thành công, nếu không, một mã lỗi thích hợp sẽ được trả về.

Bạn có thể sử dụng Paddleboat_isInitialized để kiểm tra xem thư viện Tay điều khiển trò chơi đã được khởi động thành công hay chưa. Phương thức này trả về một giá trị boolean. Nếu là đúng (true), thì bạn có thể sử dụng API.

bool Paddleboat_isInitialized()

Trước khi chấm dứt việc chạy ứng dụng, hãy sử dụng hàm Paddleboat_destroy để tắt thư viện Tay điều khiển trò chơi. Hàm này nhận một thông số duy nhất là con trỏ trỏ đến JNIEnv được gắn với luồng hiện tại. Paddleboat_init có thể được gọi lại sau Paddleboat_destroy.

void Paddleboat_destroy(JNIEnv *env)

Thông báo cho thư viện về các sự kiện trong vòng đời

Bạn phải thông báo cho thư viện Tay điều khiển về các sự kiện vòng đời hoạt động onStoponStart. Gọi các hàm Paddleboat_onStopPaddleboat_onStart từ mã xử lý sự kiện dừng và bắt đầu của bạn. Cả hai hàm này đều nhận một thông số duy nhất: con trỏ trỏ đến JNIEnv được gắn với luồng hiện tại.

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

Đăng ký hoặc loại bỏ lệnh gọi lại trạng thái tay điều khiển

Thư viện Tay điều khiển trò chơi sử dụng lệnh gọi lại trạng thái tay điều khiển để thông báo cho trò chơi khi tay điều khiển đã được kết nối hoặc bị ngắt kết nối. Tính năng này chỉ hỗ trợ mỗi lần một lệnh gọi lại trạng thái tay điều khiển.

  • Để đăng ký lệnh gọi lại trạng thái tay điều khiển hoặc thay thế bất kỳ lệnh gọi lại nào đã đăng ký trước đó bằng hàm callback mới, hãy gọi hàm Paddleboat_setControllerStatusCallback.
  • Để loại bỏ bất kỳ lệnh gọi lại nào hiện đã đăng ký, hãy truyền NULL hoặc nullptr.
  • Thông số userData là con trỏ tuỳ chọn trỏ đến dữ liệu do người dùng xác định. Thông số userData sẽ được truyền đến hàm callback. Con trỏ này được duy trì nội bộ cho đến khi được một lệnh gọi tiếp theo thay đổi thành Paddleboat_setControllerStatusCallback.
void Paddleboat_setControllerStatusCallback(Paddleboat_ControllerStatusCallback
  statusCallback, void *userData)

Chữ ký của hàm callback là:

typedef void (*Paddleboat_ControllerStatusCallback)(
  const int32_t controllerIndex,
  const Paddleboat_ControllerStatus controllerStatus,
  void *userData)
Thông số Mô tả
controllerIndex Chỉ mục của tay điều khiển đã khởi tạo lệnh gọi lại. Sẽ là một giá trị nằm trong khoảng từ 0 đến
PADDLEBOAT_MAX_CONTROLLERS - 1
controllerStatus Giá trị enum của PADDLEBOAT_CONTROLLER_JUST_CONNECTED hoặc
PADDLEBOAT_CONTROLLER_JUST_DISCONNECTED.
userData Con trỏ tuỳ chọn (có thể là NULL (RỖNG)) trỏ đến dữ liệu do người dùng xác định được lệnh gọi gần nhất chỉ định cho Paddleboat_setControllerStatusCallback.

Gọi hàm cập nhật thư viện Tay điều khiển trò chơi

Hàm cập nhật thư viện Tay điều khiển trò chơi, Paddleboat_update, phải được gọi một lần cho mỗi khung hình của trò chơi, tốt nhất là ở gần đầu khung hình. Hàm này nhận một tham số duy nhất là con trỏ trỏ đến JNIEnv được gắn với luồng hiện tại.

void Paddleboat_update(JNIEnv *env)

Xử lý sự kiện

Khi nhận được sự kiện nhập, trò chơi cần chuyển tiếp các sự kiện đó đến thư viện Tay điều khiển trò chơi để kiểm tra. Thư viện Tay điều khiển trò chơi sẽ đánh giá xem sự kiện nhập đó có được liên kết với một trong các thiết bị do mình quản lý hay không. Các sự kiện từ thiết bị được quản lý sẽ được xử lý và sử dụng.

Thư viện Tay điều khiển trò chơi hỗ trợ hai loại sự kiện nhập: sự kiện nhập AInputEventsGameActivity.

Xử lý AInputEvent

Trò chơi sẽ chuyển tiếp AInputEvents bằng cách gọi Paddleboat_processInputEvent từ mã xử lý sự kiện.

int32_t Paddleboat_processInputEvent(const AInputEvent *event)

Paddleboat_processInputEvent sẽ trả về 0 nếu sự kiện bị bỏ qua và 1 nếu sự kiện đã được thư viện Tay điều khiển trò chơi xử lý và sử dụng.

Xử lý sự kiện GameActivity

Nếu trò chơi của bạn sử dụng GameActivity, hãy chuyển tiếp sự kiện GameActivityKeyEventGameActivityMotionEvent bằng cách gọi Paddleboat_processGameActivityKeyInputEvent hoặc Paddleboat_processGameActivityMotionInputEvent từ mã xử lý sự kiện.

int32_t Paddleboat_processGameActivityKeyInputEvent(const void *event,
                                                    const size_t eventSize)
int32_t Paddleboat_processGameActivityMotionInputEvent(const void *event,
                                                       const size_t eventSize)
Thông số Mô tả
event Con trỏ trỏ đến cấu trúc GameActivityKeyEvent hoặc GameActivityMotionEvent, tuỳ thuộc vào hàm được gọi.
eventSize Dung lượng tính bằng byte của cấu trúc sự kiện được truyền trong thông số event.

Cả hai hàm sẽ trả về 0 nếu sự kiện bị bỏ qua và 1 nếu sự kiện được thư viện Tay điều khiển trò chơi xử lý và sử dụng.

GameActivity đòi hỏi chỉ định trục chuyển động hoạt động bằng cách sử dụng hàm GameActivityPointerAxes_enableAxis. Lệnh gọi Paddleboat_getActiveAxisMask sẽ trả về một mặt nạ bit của trục chuyển động hiện đang hoạt động do tay điều khiển được kết nối sử dụng.

uint64_t Paddleboat_getActiveAxisMask()

Để biết ví dụ về cách xử lý, hãy xem mẫu thư viện Tay điều khiển trò chơi sử dụng GameActivity. Mẫu này kiểm tra vòng mặt nạ trục hoạt động và thông báo cho GameActivity khi trục mới được sử dụng. Việc này được triển khai trong hàm 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 tay điều khiển

Thư viện Tay điều khiển trò chơi sử dụng một giá trị chỉ mục để tham chiếu đến một tay điều khiển cụ thể. Phạm vi giá trị chỉ mục hợp lệ nằm trong khoảng từ 0 đến PADDLEBOAT_MAX_CONTROLLERS - 1. Hàm Paddleboat_getControllerStatus xác định trạng thái của chỉ mục tay điều khiển đã chỉ định.

Paddleboat_ControllerStatus Paddleboat_getControllerStatus(
  const int32_t controllerIndex)

Có ba hàm để đọc thông tin từ tay điều khiển được kết nối.

Tên tay điều khiển

Paddleboat_getControllerName function nhận hai thông số đầu vào: chỉ mục tay điều khiển, dung lượng vùng đệm và con trỏ trỏ đến vùng đệm để lưu trữ chuỗi tên tay điều khiển. Chuỗi tên được định dạng là chuỗi C bằng cách sử dụng bộ mã hoá UTF-8. Tên thiết bị được thu thập nội bộ bằng InputDevice.getName().

Nếu bạn truy xuất tên thành công, Paddleboat_getControllerName sẽ trả về PADDLEBOAT_NO_ERROR, nếu không, một mã lỗi thích hợp sẽ được trả về.

Paddleboat_ErrorCode Paddleboat_getControllerName(const int32_t controllerIndex,
                                                  const size_t bufferSize,
                                                  char *controllerName);
Thông số Mô tả
controllerIndex Chỉ mục của tay điều khiển đã khởi tạo lệnh gọi lại. Sẽ là một giá trị nằm trong khoảng từ 0 đến
PADDLEBOAT_MAX_CONTROLLERS - 1
bufferSize Dung lượng tính bằng byte của vùng đệm được controllerName truyền, chuỗi tên sẽ được rút ngắn nếu cần để vừa với vùng đệm.
controllerName Con trỏ trỏ đến vùng đệm gồm bufferSize byte để lưu trữ tên tay điều khiển. Tên sẽ được lưu trữ dưới dạng chuỗi C bằng cách sử dụng bộ mã hoá UTF-8.

Thông tin thiết bị điều khiển

Paddleboat_getControllerInfo function nhận hai thông số đầu vào: chỉ mục tay điều khiển và con trỏ trỏ đến cấu trúc Paddleboat_Controller_Info.

Nếu Paddleboat_Controller_Info được điền sẵn dữ liệu thành công, Paddleboat_getControllerInfo sẽ trả về PADDLEBOAT_NO_ERROR, nếu không, một mã lỗi thích hợp sẽ được trả về.

Paddleboat_ErrorCode Paddleboat_getControllerInfo(const int32_t controllerIndex,
  Paddleboat_Controller_Info *controllerInfo)

Cấu trúc Paddleboat_Controller_Info chứa thông tin dành riêng cho từng thiết bị về tay điều khiển.

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;

Một số thành phần cấu trúc được điền sẵn các giá trị lấy từ InputDevice liên kết với tay điều khiển:

controllerNumber    -   InputDevice.getControllerNumber()
vendorId              - InputDevice.getVendorId()
productId             - InputDevice.getProductId()
deviceId              - InputDevice.getId()
  • Giá trị stickFlat thể hiện phạm vi của một vị trí phẳng nằm ở trung tâm. Giá trị này chủ yếu hữu ích cho việc tính toán "vùng không nhận biết" trung tâm mặc định trên các thiết bị tự căn giữa.
  • Giá trị stickFuzz thể hiện khả năng chịu lỗi hoặc khoảng cách mà giá trị hiện tại có thể sai lệch so với giá trị thực tế do các giới hạn về độ nhạy của thiết bị và độ nhiễu.

Cả hai giá trị này đều được chuẩn hoá theo giá trị trục tối đa là 1.0 ở cả hai chiều.

Thành phần controllerFlags kết hợp các cờ mặt nạ bit riêng lẻ và các giá trị kết hợp nhiều bit.

Việc thực hiện thao tác AND logic cho controllerFlags với PADDLEBOAT_CONTROLLER_LAYOUT_MASK dẫn đến một giá trị có thể được truyền đến enum Paddleboat_ControllerButtonLayout. Enum này chỉ định biểu tượng và bố cục nút mà tay điều khiển sử dụng.

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

Các hằng số sau đây xác định các bit chức năng. Để xác định xem một tay điều khiển có hỗ trợ chức năng cụ thể nào đó hay không, hãy thực hiện thao tác AND logic cho hằng số tương ứng so với controllerFlags. Kết quả khác 0 nghĩa là tay điều khiển có hỗ trợ chức năng đó.

PADDLEBOAT_CONTROLLER_FLAG_TOUCHPAD

Nếu bit cờ này được đặt, thì tay điều khiển có bàn di chuột tích hợp. Nếu nhấn vào bàn di chuột, tay điều khiển sẽ đặt bit PADDLEBOAT_BUTTON_TOUCHPAD trong trường Paddleboat_Controller_Data.buttonsDown.

PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE

Nếu bit cờ này được đặt, thì tay điều khiển mô phỏng thiết bị trỏ. Thành phần virtualPointer của cấu trúc Paddleboat_Controller_Data được điền sẵn toạ độ hiện tại của con trỏ ảo.

Dữ liệu tay điều khiển

Hàm Paddleboat_getControllerData nhận hai thông số đầu vào: chỉ mục tay điều khiển và con trỏ trỏ đến cấu trúc Paddleboat_Controller_Data. Nếu Paddleboat_Controller_Data được điền sẵn dữ liệu thành công, Paddleboat_getControllerInfo sẽ trả về PADDLEBOAT_NO_ERROR, nếu không, một mã lỗi thích hợp sẽ được trả về.

Paddleboat_ErrorCode Paddleboat_getControllerData(const int32_t controllerIndex,
  Paddleboat_Controller_Data *controllerData)

Cấu trúc Paddleboat_Controller_Data chứa các giá trị đầu vào điều khiển hiện tại của bộ điều khiển.

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;

Khoảng giá trị

Loại đầu vào Phạm vi giá trị
Trục gậy điều khiển -1.0 đến 1.0
0.0 đến 1.0
Con trỏ ảo 0.0 so với chiều rộng/chiều cao của cửa sổ (tính bằng pixel)

Chi tiết cấu trúc

Thành phần cấu trúc Mô tả
buttonsDown Mảng trường bit bit trên mỗi nút. Hằng số mặt nạ bit của nút được xác định trong tệp tiêu đề paddleboat.h và bắt đầu bằng PADDLEBOAT_BUTTON_.
timestamp. Dấu thời gian của sự kiện nhập tay điều khiển gần đây nhất. Dấu thời gian tính theo micrô giây kể từ thời gian bắt đầu của đồng hồ.
virtualPointer Vị trí con trỏ ảo. Chỉ hợp lệ nếu cờ PADDLEBOAT_CONTROLLER_FLAG_VIRTUAL_MOUSE được đặt trong controllerFlags, nếu không, sẽ là 0.0, 0.0.