Chapter 206 · 综合实战

实战:游戏 HUD

InventoryGrid + VirtualJoystick + Progress:移动端游戏 HUD 界面。

206

项目概述

构建移动端游戏 HUD:
• 虚拟摇杆:VirtualJoystick 控制角色移动
• 物品栏:InventoryGrid 底部快捷栏
• 血条/蓝条:Progress 显示 HP/MP
• 小地图:Canvas 绘制缩略地图
• 技能按钮:Button 圆形技能图标 + 冷却

技术栈

模块XUI API
摇杆xuiVirtualJoystickCreate(XY 通道)
物品栏xuiInventoryGridCreate(手柄支持)
血条xuiProgressCreate(水平/动画)
小地图xuiCanvasCreate(自定义绘制)
技能xuiButtonCreate(圆形/图标/徽章)

编译本章示例

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

核心代码:摇杆 + 物品栏

// 虚拟摇杆(左下角)
xui_virtual_joystick_desc_t tJoyDesc = { 0 };
xui_widget pJoystick;
xuiVirtualJoystickCreate(pCtx, &pJoystick, &tJoyDesc);
xuiVirtualJoystickSetMetrics(pJoystick,
    60.0f, 24.0f, 0.1f);

// 摇杆回调 → 角色移动
xuiVirtualJoystickSetChange(pJoystick,
    OnJoystickMove, pPlayer);

void OnJoystickMove(float fX, float fY,
    void* pUser) {
    player_t* p = (player_t*)pUser;
    p->fVelX = fX * p->fSpeed;
    p->fVelY = fY * p->fSpeed;
}

// 物品栏(底部 6 格)
xui_inventory_grid_desc_t tInvDesc = { 0 };
tInvDesc.iColumns = 6;
tInvDesc.iRows = 1;
xui_widget pHotbar;
xuiInventoryGridCreate(pCtx, &pHotbar, &tInvDesc);

// 血条
xui_progress_desc_t tHpDesc = { 0 };
tHpDesc.fMax = 100.0f;
xui_widget pHP;
xuiProgressCreate(pCtx, &pHP, &tHpDesc);
xuiProgressSetValue(pHP, 75.0f);

完整代码

将以下代码保存为 ch206_main.c,编译后运行即可看到游戏 HUD(摇杆 + 血条 + 物品栏)效果:

#include "xge.h"
#include "xui.h"

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x0a0a1a);
    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 = 800; d.iHeight = 500;
    d.sTitle = "ch206 - Game HUD";
    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, 800, 500);

    xui_widget pRoot;
xuiPanelCreate(g_pCtx, &pRoot, NULL);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 800, 500});

    /* 虚拟摇杆(左下角) */
    xui_virtual_joystick_desc_t tJoy = {0};
    xui_widget pStick;
    xuiVirtualJoystickCreate(g_pCtx, &pStick, &tJoy);
    xuiWidgetSetRect(pStick, (xui_rect_t){40, 360, 120, 120});

    /* 血条(左上角) */
    xui_progress_desc_t tHp = {0};
    tHp.fMax = 100.0f;
    xui_widget pHP;
    xuiProgressCreate(g_pCtx, &pHP, &tHp);
    xuiWidgetSetRect(pHP, (xui_rect_t){20, 20, 200, 20});
    xuiWidgetSetRect(pHP, (xui_rect_t){0, 0, 200, 20});
    xuiProgressSetValue(pHP, 75.0f);

    /* 物品栏(底部居中) */
    xui_inventory_grid_desc_t tInv = {0};
    tInv.iColumns = 6; tInv.iRows = 1;
    xui_widget pBar;
    xuiInventoryGridCreate(g_pCtx, &pBar, &tInv);
    xuiWidgetSetRect(pBar, (xui_rect_t){250, 440, 480, 120});

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

代码讲解

  • 摇杆:左下角虚拟摇杆,拖动时输出 XY 通道值控制角色移动。
  • 血条:Progress 控件显示 HP,支持动画过渡。
  • 物品栏:6 格快捷栏,支持手柄导航和拖拽交换。
  • 透明背景:HUD 控件背景透明,不遮挡游戏画面。

要点与陷阱

  • 触摸:HUD 控件需响应多点触摸(摇杆 + 技能同时按)。
  • 透明背景:HUD 控件背景透明,不遮挡游戏画面。
  • 适配:不同分辨率下 HUD 锚定边角,不随画面缩放。
  • 手柄:InventoryGrid 支持手柄导航,主机游戏必备。

进阶练习

  1. 技能冷却:Button 上覆盖扇形遮罩动画。
  2. 伤害飘字:Canvas 绘制浮动数字 + 淡出。
实战:游戏 HUD效果
图:实战:游戏 HUD渲染效果