100 行把 UI 接进 raylib:raygui 即时模式控件实战
【免费下载链接】raylibA simple and easy-to-use library to enjoy videogames programming项目地址: https://gitcode.com/GitHub_Trending/ra/raylib
raylib 项目里画 2D、3D 场景的人很多,但要做个设置页、调试面板就卡住了——不想为界面单独引入 Qt 这种重型依赖。raygui 是仓库自带的即时模式 GUI(IMGUI,每帧直接重绘全部控件、不缓存控件状态),单头文件、零额外构建配置,放进行程循环里调用函数就出界面。这篇文章从 20 行可编译的最小例子开始,走到 3D 相机调试面板,最后聊几个真实会踩的坑。
先让一个按钮亮起来
最小目标是:窗口里出现一个按钮,点一下,界面上的计数跟着变。整份代码可以编译运行:
#include "raylib.h" #define RAYGUI_IMPLEMENTATION // 展开 raygui 实现,必须写在 include 之前 #include "raygui.h" int main(void) { InitWindow(800, 450, "raygui 最小示例"); int clicks = 0; // 即时模式:状态就是普通变量,没有控件对象 while (!WindowShouldClose()) { BeginDrawing(); ClearBackground(RAYWHITE); // 点击的那一帧返回值非 0,无需注册回调 if (GuiButton((Rectangle){ 10, 10, 140, 40 }, "点我")) clicks++; DrawText(TextFormat("已点击 %d 次", clicks), 10, 70, 20, BLACK); EndDrawing(); } CloseWindow(); return 0; }和保留模式 UI 的本质区别在这里:raygui 的控件没有生命周期,clicks这种状态完全由你自己声明、自己更新,控件函数只是"画出来 + 本帧检测输入"。为什么这样反而省心?因为不存在控件销毁时忘删回调、状态对象泄漏这类问题,UI 状态和游戏状态是同一批变量。注意#define RAYGUI_IMPLEMENTATION必须出现在#include "raygui.h"之前,且整个工程只允许有一个 .c 文件这样写,否则会重复定义。
3 行让滑块跟手
想让玩家(或你自己)实时调参数,核心就是"把变量的地址传给控件",控件替你处理鼠标拖动逻辑:
float width = 200.0f, roundness = 0.2f; bool fill = true; // 每帧循环内: GuiSliderBar((Rectangle){ 600, 40, 150, 20 }, "Width", TextFormat("%.0f", width), &width, 50, 500); GuiSliderBar((Rectangle){ 600, 70, 150, 20 }, "Roundness", TextFormat("%.2f", roundness), &roundness, 0, 1); GuiCheckBox((Rectangle){ 600, 110, 20, 20 }, "Filled", &fill); if (fill) DrawRectangleRounded((Rectangle){ 100, 150, width, 150 }, roundness, 20, RAYBLUE);GuiSliderBar要求float *,所以width、roundness用 float;如果参数是整数,换GuiValueBox(可键盘输入)或GuiSpinner(带上下箭头)更合适。右边第三个参数是给滑块尾部显示的文字,传NULL就只留左侧标签。官方圆角矩形绘制示例就是这个套路:右侧一排滑块加复选框,实时控制左侧图形的宽、高、圆角和线宽,完整效果长这样:
把调试面板塞进 3D 场景
相机调试面板是 3D 开发里最高频的需求。注意当前仓库的Camera就是Camera3D,字段是position / target / up / fovy / projection(没有旧版文档里的rotation),代码要对准这些字段:
void DrawDebugPanel(Camera *cam) { GuiGroupBox((Rectangle){ 10, 10, 260, 180 }, "Camera"); GuiSliderBar((Rectangle){ 30, 50, 200, 20 }, "FovY", TextFormat("%.0f", cam->fovy), &cam->fovy, 20, 90); GuiSliderBar((Rectangle){ 30, 80, 200, 20 }, "Height", NULL, &cam->position.y, 0, 100); GuiSliderBar((Rectangle){ 30, 110, 200, 20 }, "Dist", NULL, &cam->position.z, -50, 50); // projection 是 int 枚举,用独立 bool 桥接一下 static bool ortho = false; if (GuiCheckBox((Rectangle){ 30, 145, 20, 20 }, "Ortho", &ortho)) cam->projection = ortho ? CAMERA_ORTHOGRAPHIC : CAMERA_PERSPECTIVE; }GuiGroupBox只画一个带标题的边框,真正的控件坐标你自己摆在它内部。GuiCheckBox要bool *而projection是 int,这里用局部 bool 捕获"勾选动作发生"的返回值再同步进相机,比强转指针干净。面板函数放进每帧循环,和场景一起绘制即可——2D 面板画在 3D 场景之后,坐标就是屏幕坐标,不需要投影变换。
2 行改掉控件配色 🎨
默认灰白风格想换成自己的美术风格,用GuiSetStyle按"控件 + 属性"逐条覆盖,颜色直接传 raylib 的 Color 数值:
// 只改按钮的正常态底色和文字色 GuiSetStyle(BUTTON, BASE_COLOR_NORMAL, GREEN); GuiSetStyle(BUTTON, TEXT_COLOR_NORMAL, RAYWHITE); GuiButton((Rectangle){ 10, 10, 120, 30 }, "自定义样式");属性枚举(BASE_COLOR_NORMAL、TEXT_COLOR_PRESSED等)和控件枚举(BUTTON、SLIDER、DEFAULT……)都定义在 raygui.h 里,DEFAULT控件改的是全局默认值,适合开局统一刷一遍圆角、间距、描边宽度。想要一整套主题,可以用官方样式工具生成.rbg样式文件后用GuiLoadStyle("style.rbg")加载,比手写几十条GuiSetStyle省事得多。
三个容易翻车的坑 🕳️
- 下拉框选项是分号字符串。5.0 版
GuiDropdownBox的第二个参数是"Easy;Normal;Hard"这种分号分隔串,不再是旧教程里的字符串数组,传错类型编译就会报错:
int active = 0; // 当前选中项索引 GuiDropdownBox((Rectangle){ 250, 10, 140, 30 }, "Easy;Normal;Hard", &active, false);- 中文会显示成方块。raygui 默认内置字体只有拉丁字形,界面要出中文,先用
LoadFont加载一份覆盖中文字形的 ttf 再应用到 raygui,别指望改样式能解决。 - 控件别出屏。
GetScreenHeight()是窗口内边高,把面板写在窗口高度范围内;窗口动态缩放时把硬编码坐标换成GetScreenWidth() - 面板宽 - 边距这类相对算式,参考圆角矩形示例里滑块坐标的写法。
延伸资源
想往下走,直接看仓库里这些文件,每份都带可运行代码和效果图:
- raygui.h:单头文件实现,所有控件的签名和枚举都在这
- shapes_rounded_rectangle_drawing.c:滑块 + 复选框调参数的完整范例
- core_3d_camera_free.c:3D 相机操作,配合上面的调试面板用
- examples/examples_list.txt:全部示例清单,按目录找带 GUI 的例子
- projects/CMake/:CMake 工程模板,照抄可编译结构
跑通最小按钮只是起点——把参数面板、滚动列表(GuiScrollPanel)、颜色选择器(GuiColorPicker)组合起来,游戏内的配置界面基本就齐了。
【免费下载链接】raylibA simple and easy-to-use library to enjoy videogames programming项目地址: https://gitcode.com/GitHub_Trending/ra/raylib
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考