Chapter 209 · 综合实战

跨平台适配要点

触摸适配、高 DPI 缩放、音频桥接、平台能力查询与后端切换。

209

概念

XGE 跨平台适配关键领域:
• 触摸:移动端多点触摸替代鼠标,控件需支持 Touch 事件
• 高 DPI:Retina/4K 屏幕逻辑坐标 vs 物理像素
• 音频:不同平台音频后端(WASAPI/OpenSL/CoreAudio)
• 后端切换:xgePlatformBackendSet / xgeGraphicsBackendSet
• 能力查询:xgePlatformCapsGet 运行时检测平台特性

适配清单

领域API / 策略
触摸xgeTouchGetCount/Get/Find → XUI DispatchEvent
高 DPIxgeGetWidth/Height(逻辑)vs 物理像素比
音频xgeAudioInit 自动选择平台后端
图形后端xgeGraphicsBackendSet(OpenGL/Vulkan/Metal)
平台能力xgePlatformCapsGet(触摸/手柄/IME 支持)
IMExgeImeSetEnabled(移动端软键盘)

编译本章示例

gcc -O2 -I. -o ch209.exe ch209_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch209.exe

示例:高 DPI + 触摸适配

// 查询平台能力
xge_platform_caps_t tCaps;
xgePlatformCapsGet(&tCaps);

// 高 DPI 缩放
float fDPI = tCaps.fDisplayScale;  // 1.0 / 2.0 / 3.0
xuiSetVirtualDpi(pCtx, fDPI);

// 触摸 → XUI 事件
void OnFrame(void) {
    int iCount = xgeTouchGetCount();
    for (int i = 0; i < iCount; i++) {
        xge_touch_point_t tTouch;
        xgeTouchGet(i, &tTouch);
        xui_event_t ev = { 0 };
        ev.fX = tTouch.fX;
        ev.fY = tTouch.fY;
        ev.iId = tTouch.iId;

        if (tTouch.iPhase == XGE_TOUCH_BEGIN)
            ev.iType = XUI_EVENT_POINTER_DOWN;
        else if (tTouch.iPhase == XGE_TOUCH_END)
            ev.iType = XUI_EVENT_POINTER_UP;
        else
            ev.iType = XUI_EVENT_POINTER_MOVE;

        xuiDispatchEvent(pCtx, &ev);
    }
}

完整代码

将以下代码保存为 ch209_main.c,编译后运行即可看到平台能力查询与 DPI 适配效果:

#include "xge.h"
#include "xui.h"
#include <stdio.h>

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x1a1a2e);
    xui_vec2_t pos;
    xgeMouseGet(&pos.x, &pos.y);
    xuiInputPointerMove(g_pCtx, pos.x, pos.y);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, pos.x, pos.y, 0);
    else
        xuiInputPointerUp(g_pCtx, pos.x, pos.y, 0);
    xuiUpdate(g_pCtx, xgeGetDelta());
    xuiLayout(g_pCtx);
    xuiRender(g_pCtx, NULL, NULL, 0);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth = 640; d.iHeight = 480;
    d.sTitle = "ch209 - Platform Adapt";
    d.iFlags = XGE_INIT_VSYNC;
    xgeInit(&d);
    xuiCreate(&g_pCtx);
    extern const xui_proxy_t tXgeProxy;
    xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
    xuiSetViewportSize(g_pCtx, 640, 480);

    /* 查询平台能力 */
    xge_platform_caps_t tCaps;
    xgePlatformCapsGet(&tCaps);

    xui_widget pRoot;
xuiPanelCreate(g_pCtx, &pRoot, NULL);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 640, 480});

    char buf[128];
    sprintf(buf, "DPI Scale: %.1f", tCaps.fDisplayScale);
    xui_widget pLbl;
xuiLabelCreate(g_pCtx, &pLbl, NULL);
xuiWidgetAddChild(pRoot, pLbl);
    xuiLabelSetText(pLbl, buf);
    xuiWidgetSetRect(pLbl, (xui_rect_t){220, 200, 200, 32});
    xuiWidgetSetRect(pLbl, (xui_rect_t){0, 0, 200, 32});

    xgeRun(onFrame, NULL);
    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • 平台能力:xgePlatformCapsGet 查询 DPI 缩放、触摸支持、手柄等平台特性。
  • 逻辑坐标:XUI 始终使用逻辑坐标,DPI 缩放由引擎处理。
  • 触摸事件:移动端通过 xgeTouchGetCount/Get 获取触摸点并注入 XUI。
  • 后端切换:iOS 用 Metal,Android 用 OpenGL ES,Windows 用 D3D/Vulkan。

要点与陷阱

  • 逻辑坐标:XUI 始终使用逻辑坐标,DPI 缩放由引擎处理。
  • 触摸目标:移动端控件最小触摸区域 44×44pt。
  • IME:移动端文本输入需启用 IME,弹出软键盘。
  • 音频延迟:移动端音频延迟较高,游戏音效需预加载。
  • 后端:iOS 用 Metal,Android 用 OpenGL ES,Windows 用 D3D/Vulkan。

进阶练习

  1. 自适应布局:横竖屏切换时自动调整 UI 布局。
  2. 手柄模式:检测手柄连接时切换 HUD 为手柄导航模式。
跨平台适配要点效果
图:跨平台适配要点渲染效果