GamepadConnected / GetState / ButtonDown / Axis 支持 Xbox/PS 手柄,含按键、摇杆、扳机全状态。
XGE 手柄 API 支持最多 4 个手柄(索引 0~3):
• 按键:A/B/X/Y、LB/RB、Start/Back、DPad 等
• 摇杆:左/右摇杆 X/Y 轴(-1.0 ~ 1.0)
• 扳机:LT/RT 模拟量(0.0 ~ 1.0)
支持热插拔检测(Connected)和虚拟手柄注入(SetState)。
| 函数 | 说明 |
|---|---|
int xgeGamepadConnected(int iGamepad) | 手柄是否连接 |
int xgeGamepadGetState(int iGamepad, xge_gamepad_state_t* pState) | 获取完整状态 |
int xgeGamepadButtonDown(int iGamepad, uint32_t iButton) | 按键是否按下 |
int xgeGamepadButtonPressed(int iGamepad, uint32_t iButton) | 本帧是否刚按下 |
int xgeGamepadButtonReleased(int iGamepad, uint32_t iButton) | 本帧是否刚释放 |
float xgeGamepadAxis(int iGamepad, int iAxis) | 获取轴值 |
int xgeGamepadSetConnected(int iGamepad, int bConnected) | 模拟连接/断开 |
int xgeGamepadSetState(int iGamepad, const xge_gamepad_state_t* pState) | 注入虚拟状态 |
gcc -O2 -Wall -Wextra -DXGE_DLL -DXGE_DEBUGMODE=0 -I. -o build\ch119_main1.exe examples\tutorial_capture\ch119_main1.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
build\ch119_main1.exe --frames 2
build\ch119_main1.exe --capture tutorial\img\ch119_1.png
void onFrame(void) {
// 检查 1P 手柄
if (!xgeGamepadConnected(0))
return;
// 左摇杆移动(带死区)
float lx = xgeGamepadAxis(0,
0/* 左摇杆 X */);
float ly = xgeGamepadAxis(0,
1/* 左摇杆 Y */);
if (fabsf(lx) < 0.15f) lx = 0;
if (fabsf(ly) < 0.15f) ly = 0;
player.x += lx * 200.0f * xgeGetDelta();
player.y += ly * 200.0f * xgeGetDelta();
// A 键跳跃
if (xgeGamepadButtonPressed(0,
XGE_GAMEPAD_A)) {
player.vy = -400.0f;
}
// RT 扳机射击(模拟量控制射速)
float rt = xgeGamepadAxis(0,
4/* 右扳机 */);
if (rt > 0.5f) {
fireWeapon(rt);
}
// 右摇杆瞄准
float rx = xgeGamepadAxis(0,
2/* 右摇杆 X */);
float ry = xgeGamepadAxis(0,
3/* 右摇杆 Y */);
aimAngle = atan2f(ry, rx);
}本页旧版的按键枚举会随平台映射变化,不再作为权威实现。已验证的完整源码是 examples/tutorial_capture/ch119_main1.c:它在测试模式下调用 xgeGamepadSetState 注入状态,再用 xgeGamepadConnected、xgeGamepadButtonDown、xgeGamepadButtonPressed 与 xgeGamepadAxis 读回并断言。实际游戏应只轮询真实设备;状态注入只用于测试和编辑器工具。
将以下代码保存为 ch119_main.c,编译后运行即可看到手柄控制角色效果:
#include "xge.h"
#include <math.h>
static xge_font g_font = NULL;
static float g_px = 400.0f, g_py = 300.0f;
static float g_aimAngle = 0.0f;
static int onFrame(void* pUser) {
(void)pUser;
xgeClear(0x081114FF);
if (!xgeGamepadConnected(0)) {
xgeTextDraw(g_font, "No gamepad connected",
280, 280, 0xFF6B5EFF);
return XGE_OK;
}
float dt = xgeGetDelta();
// 左摇杆移动(带死区)
float lx = xgeGamepadAxis(0, 0/* 左摇杆 X */);
float ly = xgeGamepadAxis(0, 1/* 左摇杆 Y */);
if (fabsf(lx) < 0.15f) lx = 0;
if (fabsf(ly) < 0.15f) ly = 0;
g_px += lx * 250.0f * dt;
g_py += ly * 250.0f * dt;
// 右摇杆瞒准
float rx = xgeGamepadAxis(0, 2/* 右摇杆 X */);
float ry = xgeGamepadAxis(0, 3/* 右摇杆 Y */);
if (fabsf(rx) > 0.2f || fabsf(ry) > 0.2f)
g_aimAngle = atan2f(ry, rx);
// 绘制角色
xgeShapeCircleFill(g_px, g_py, 18, 0x4FD8C2FF);
// 瞒准方向线
xgeShapeLine(g_px, g_py,
g_px + 40.0f*cosf(g_aimAngle),
g_py + 40.0f*sinf(g_aimAngle),
0xFF6B5EFF, 3);
// A 键跳跃反馈
if (xgeGamepadButtonPressed(0, XGE_GAMEPAD_A))
xgeShapeCircleFill(g_px, g_py, 30, 0xFFB454FF, 2);
// HUD
char buf[128];
sprintf(buf, "LStick(%.2f,%.2f) Aim:%.1f\xc2\xb0",
lx, ly, g_aimAngle * 57.3f);
xgeTextDraw(g_font, buf, 30, 30, 0xFFFFFFFF);
xgeTextDraw(g_font, "Gamepad 0 connected",
30, 65, 0x4FD8C2FF);
return XGE_OK;
}
int main(void) {
xge_desc_t d = {0};
d.iWidth = 800;
d.iHeight = 600;
d.sTitle = "ch119 - Gamepad";
d.iFlags = XGE_INIT_VSYNC;
xgeInit(&d);
g_font = xgeFontLoad("res/font/default.ttf", 24);
xgeRun(onFrame, NULL);
xgeFontFree(g_font);
xgeUnit();
return 0;
}