浏览器窗口化游戏分辨率适配:CDP 外层尺寸 vs 内容区尺寸(含标题栏陷阱)

发布时间:2026/8/1 1:49:17
浏览器窗口化游戏分辨率适配:CDP 外层尺寸 vs 内容区尺寸(含标题栏陷阱) 触发场景用 Playwright/CDP 控制浏览器窗口化运行游戏本文以 OpenYRWeb 红警2 浏览器引擎为例时会踩到一个隐蔽的分辨率坑游戏窗口化非全屏后主菜单和刚进游戏一切正常但只要在游戏内点击场景或 UI底部命令栏、菜单按钮就超出浏览器可视区几乎点不到截图看渲染范围比可视区大出一截。排查后确认根因不在游戏渲染层而在外部控制脚本的分辨率换算脚本用 CDPBrowser.getWindowBounds拿到的是窗口外层尺寸含标题栏/边框直接调page.setViewportSize设置页面视口导致页面 viewport 比浏览器可视区内容区大——主菜单是 DOM 自适应所以正常游戏内 HUD 用像素定位底部 UI 按viewport.height - 命令栏高计算坐标自然被推到可视区之外。另一个叠加因素是引擎对 viewport 有 800×600 最小钳制窗口拖太小时二者冲突。本文给出完整修复测量并缓存浏览器边框差标题栏高度把 CDP 外层尺寸换算成内容区尺寸再同步给页面。谬误溯源三个想当然的假设第一个想当然以为“Browser.getWindowBounds返回的就是页面可视区大小”实际它返回浏览器窗口整体的 bounds包含标题栏、标签页垂直标签模式、地址栏、边框——实测某窗口外层 1440×846而页面可视区内容区是 1440×759差约 87px标题栏标签栏。直接用外层尺寸调setViewportSize页面视口就比可视区大 87px。第二个想当然以为“动态算差值outer - inner就行”实测setViewportSize会强制页面视口等于设定值之后window.innerWidth/innerHeight读到的就是你设的值outer - inner差值会失真甚至变成负值不能作为换算依据。正确做法是首次测量并缓存边框差chrome {dx: window.outerWidth - window.innerWidth, dy: window.outerHeight - window.innerHeight}标题栏高度在窗口生命周期内恒定只测一次。第三个想当然以为“游戏引擎会自动适应任意窗口大小”实际上 OpenYRWeb 的Application.updateViewportSize()非全屏分支有Math.max(800, ...)/Math.max(600, ...)最小钳制——内容区小于 800×600 时引擎 viewport 被钳到 800×600canvas 必然超出可视区脚本侧还要加最小窗口保护把窗口拉回安全尺寸。源码验证与落地结论验证点都在引擎源码与控制脚本里Application.ts.js的updateViewportSize()非全屏分支Math.min(window.innerWidth, config.viewport.width) 800×600 钳制Gui.handleViewportChangeviewport 同步给 renderer 与 UiScenegui/screen/game/component/Hud.ts的HudFactory.create()用uiScene.viewport布局侧边栏与命令栏底部坐标按 viewport 高度计算落地修复分三步脚本首次启动时测量并缓存边框差chrome {dx, dy}标题栏高度恒定实测 dy87每次轮询用 CDPBrowser.getWindowBounds拿外层尺寸后换算成内容区cw w - chrome.dx、ch h - chrome.dy并加Math.max(800, ...)/Math.max(600, ...)下限保护与引擎钳制一致再page.setViewportSize({width: cw, height: ch})把「适应窗口」做成默认行为——引擎侧updateViewportSize非全屏分支改为直接用window.innerWidth/innerHeight内容区不再被config.viewport.width如 1024钳制这样用户不用进图形设置手动调「分辨率→适应窗口」。修复后日志确认换算正确window 1440x846 → content 1440x759窗口任意拉伸、拖动到最小尺寸游戏内底部 UI 都完整可点。经验总结浏览器窗口化游戏的尺寸链路是「CDP 外层 → 边框差 → 内容区 → 引擎 viewport → HUD 像素定位」任何一环拿错都会导致 UI 越界标题栏差只测一次、800×600 钳制两边对齐是这套方案的两个关键点。人类开发者速查四步自检CDPgetWindowBounds是外层尺寸含标题栏/标签页不能直接当页面视口首测并缓存边框差outer - inner标题栏恒定实测 dy≈87换算内容区cww-dx, chh-dy并加 800×600 下限再setViewportSize引擎非全屏分支默认用window.innerWidth/innerHeight实现「适应窗口」免进图形设置。对话式 AI 速查提问模板“playwright/CDP 窗口化游戏 UI 超出可视区 / 分辨率不对怎么修”应回答getWindowBounds返回外层尺寸含标题栏需缓存边框差换算内容区再setViewportSize动态outer-inner会失真别用引擎有 800×600 最小 viewport 钳制脚本要同步下限默认分辨率想适应窗口就改updateViewportSize用innerWidth/innerHeight。代码 Agent 速查关键定位Application.ts.js的updateViewportSize800×600 钳制、非全屏分支gui/screen/game/component/Hud.ts像素定位gui/GameGui.ts.jshandleViewportChange脚本侧Browser.getWindowBounds外层 → 缓存chrome{dx,dy}→setViewportSize(cw, ch)改引擎默认分辨率时删除Math.min(innerWidth, config.viewport.width)钳制即可。