
本文目录 2 | Raylib 渲染架构 —— 从 Camera2D 踩坑到 RenderTexture2D 1. 问题窗口该多大❌ 2. Phase 1固定窗口 SetWindowSize❌ 3. Phase 2Camera2D —— 理想很丰满️ 坑 1黑边️ 坑 2Camera2D Texture 管线冲突️ 坑 3缩放锯齿✅ 4. Phase 3RenderTexture2D —— 最终方案4.1 核心架构4.2 鼠标坐标转换4.3 背景图的处理 5. Phase 4全屏高清 canvasMult 5.1 问题5.2 解决方案 6. 架构演进总结 下篇预告 系列目录系列第 2 篇· 前面我们讲了扫雷的核心算法现在来看这些内容是怎么渲染到屏幕上的。上一篇项目概览与扫雷核心算法 2 | Raylib 渲染架构 —— 从 Camera2D 踩坑到 RenderTexture2D 1. 问题窗口该多大扫雷的棋盘尺寸是动态的难度棋盘像素40px 格子需要窗口Beginner 9×9360 × 360很小就够了Expert 16×301200 × 640需要大窗口如果每次切难度都SetWindowSize()—— Windows DPI 缩放会干预窗口忽大忽小全屏时布局全乱。解决方案迭代了 4 个阶段。前两个是坑后两个是答案。❌ 2. Phase 1固定窗口 SetWindowSizeintwinWgame.cols*CELL_SIZE2*PADDING;intwinHgame.rows*CELL_SIZEUI_PANEL_HEIGHTPADDING;SetWindowSize(winW,winH);Phase 1 的问题SetWindowSize()每次切难度窗口会跳变。下面是当时记录的典型问题❌ Beginner → Expert窗口从 400×500 跳到 1300×680肉眼可见闪烁❌ Windows DPI 缩放抢夺控制权窗口有时仅 200×200❌ 全屏/窗口切换时布局完全错位问题清单问题严重性Windows DPI 缩放使窗口只有 200×200❌ 致命切难度窗口跳变⚠️ 体验差全屏/窗口切换布局重算⚠️ 不可靠用户不能自由拖拽缩放❌ 不友好教训永远不要让窗口尺寸跟着游戏内容变。用固定画布 自动缩放代替。❌ 3. Phase 2Camera2D —— 理想很丰满改用固定内部画布960×640用 Raylib 的Camera2D把画布坐标自动映射到窗口Camera2D camera{0};camera.zoomfminf((float)screenW/CANVAS_WIDTH,(float)screenH/CANVAS_HEIGHT);BeginMode2D(camera);// 所有绘制用 960×640 坐标EndMode2D();鼠标坐标用GetScreenToWorld2D()转换回画布空间。️ 坑 1黑边Camera2D 只渲染画布区域宽高比不一致时左右/上下全是黑边。背景图填不满。️ 坑 2Camera2D Texture 管线冲突BeginTextureMode(canvasTarget);BeginMode2D(camera);// 嵌套使用渲染管线冲突Raylib 的这两个模式嵌套时缩放行为不可预测。高 DPI 窗口下文字画错位置、点击区域完全偏移。️ 坑 3缩放锯齿Camera2D 用 GL_NEAREST对棋盘像素风格是好事但文字全是锯齿。代价6 个 Fix#77-#82实现 Camera2D 方案又用 6 个 Fix#108-#112全部推翻。✅ 4. Phase 3RenderTexture2D —— 最终方案4.1 核心架构// 1️⃣ 创建固定画布纹理canvasTargetLoadRenderTexture(CANVAS_WIDTH,CANVAS_HEIGHT);// 2️⃣ 每帧先画到纹理BeginTextureMode(canvasTarget);ClearBackground(BLANK);// ... 所有游戏内容用 1280×720 坐标DrawToast();EndTextureMode();// 3️⃣ 等比缩放 居中blit 到窗口floatcanvasScalefminf((float)screenW/CANVAS_WIDTH,(float)screenH/CANVAS_HEIGHT);floatoffsetX(screenW-CANVAS_WIDTH*canvasScale)/2.0f;floatoffsetY(screenH-CANVAS_HEIGHT*canvasScale)/2.0f;// ️ blit 时用 bilinear 过滤避免马赛克SetTextureFilter(canvasTarget.texture,TEXTURE_FILTER_BILINEAR);Rectangle src{0,0,CANVAS_WIDTH,-CANVAS_HEIGHT};Rectangle dst{offsetX,offsetY,CANVAS_WIDTH*canvasScale,CANVAS_HEIGHT*canvasScale};DrawTexturePro(canvasTarget.texture,src,dst,(Vector2){0,0},0.0f,WHITE);️RenderTexture2D 渲染管线每帧渲染循环 游戏逻辑UpdateGame()️ 画到画布BeginTextureMode()1280×720 缩放计算canvasScale min(sW/1280, sH/720)️ Blit 到窗口DrawTexturePro()️ 屏幕显示 鼠标输入ScreenToCanvas()4.2 鼠标坐标转换staticVector2ScreenToCanvas(Vector2 screenPos){return(Vector2){(screenPos.x-canvasOffsetX)/canvasScale,(screenPos.y-canvasOffsetY)/canvasScale};}⚠️对照 Fix #88如果不转换按钮画在画布 (640, 200) 但碰撞检测以为在窗口 (640, 200)。窗口一缩放点击完全错位。4.3 背景图的处理背景图泼墨风格background.png直接画到全屏窗口不在画布内BeginDrawing();ClearBackground(BLACK);// 画背景到全屏窗口坐标系DrawTexturePro(bgTexture,src,(Rectangle){0,0,screenW,screenH},...);// 画遮罩到全屏DrawRectangle(0,0,screenW,screenH,Fade(BLACK,0.7f));// 画游戏到画布画布坐标系BeginTextureMode(canvasTarget);// ...这样窗口宽高比任意变化背景都填满画布永远居中。 5. Phase 4全屏高清 canvasMult 5.1 问题1280×720 画布在全屏2560×1600被放大2 倍以上。即使 bilinear 过滤文字边缘仍有柔化感。中文笔画密集放大后笔画之间模糊粘连Fix #221。canvasMult 要解决的问题全屏时 1280×720 画布被放大到 2~3 倍。修复前中文笔画密集处在放大后互相粘连模糊英文几乎无影响修复后canvasMult 将渲染目标重建为 2560×1440Camera2D 保持 1280×720 布局下采样后中文清晰锐利5.2 解决方案staticvoidUpdateCanvasScale(void){// ... 计算 canvasScale ...if(canvasScale1.0f){intmult(int)ceilf(canvasScale);if(mult1)mult1;if(mult4)mult4;targetWCANVAS_WIDTH*mult;// 1280 → 2560targetHCANVAS_HEIGHT*mult;// 720 → 1440canvasMultmult;}// 重建高分辨率画布if(canvasTarget.texture.width!targetW){UnloadRenderTexture(canvasTarget);canvasTargetLoadRenderTexture(targetW,targetH);SetTextureFilter(...,TEXTURE_FILTER_BILINEAR);}}绘制时用Camera2D.zoom canvasMult映射BeginTextureMode(canvasTarget);Camera2D cam{0};cam.zoom(float)canvasMult;BeginMode2D(cam);// ... 所有 1280×720 布局代码零改动 ...EndMode2D();EndTextureMode();显示器canvasScalemult实际 RT 分辨率1280×7201.011280×7201920×10801.522560×14402560×16002.022560×14403840×2160 (4K)3.033840×2160关键所有现有布局代码零改动。Camera2D 自动把 1280×720 的绘制指令映射到高分辨率画布上下采样回窗口时清晰度远超纯 1280 放大。 6. 架构演进总结️架构演进路线❌ Phase 1固定窗口SetWindowSize❌ Phase 2Camera2D黑边锯齿✅ Phase 3RT BILINEAR1280×720 Phase 4canvasMult高清全屏阶段画布自适应文字清晰度代码复杂度❌ Phase 1 固定窗口随棋盘变❌一般简单❌ Phase 2 Camera2D960×640✅❌ 锯齿多复杂坑多✅ Phase 3 RTBILINEAR1280×720✅✅ 英文清晰适中Phase 4 canvasMult自适应高分辨率✅✅ 中文也清晰稍复杂最终选型RenderTexture2D 固定 1280×720 逻辑画布 TEXTURE_FILTER_BILINEAR 全屏canvasMult高分辨率重建 Camera2Dzoom 自动映射。 下篇预告第 3 篇222 个 Bug 修复教会我的事栈溢出、浮点 UB、字体缺失、异步保存、初始化顺序错误…… 精选 15 个让你看完直呼我也踩过的经典修复故事。可能是全系列最有趣的一篇 系列目录#标题状态1项目概览与扫雷核心算法✅ 已发布2Raylib 渲染架构← 本文✅ 已发布3222 个 Bug 修复教会我的事✅ 已发布4中英文双语的工程实现 待发布5持久化、撤销、提示非核心功能 待发布6200 个单元测试C 项目也能 TDD 待发布7960×640 → 1280×720全局缩放重构实录 待发布如果你觉得有帮助点赞 收藏 关注三连支持作者继续写下去