恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Cocos Creator 的 Web 屏幕适配链路:DPR 钳制、安全区域 CSS 变量与旋转帧的源码拆解

  • 首页
  • 资讯中心
  • /
  • Cocos Creator 的 Web 屏幕适配链路:DPR 钳制、安全区域 CSS 变量与旋转帧的源码拆解

相关资讯

WebToApp 运行时管理详解:手机端 PHP / Node.js / Python / Go / WordPress 运行时二进制下载、镜像与缓存机制 2026/9/17 20:35:20
公司请假审批系统-Django sqlite 2026/9/17 20:35:20
工业工程课件的数字化落地:从PPTX到可执行工具链 2026/9/17 20:35:20

最新资讯

Blender模型导出FBX到UE/Unity全流程:贴图丢失、材质变黑、法线翻转排查指南
智能工具如何革新学术写作与出版流程
window.postMessage 跨域通信实战指南:从参数详解到安全避坑
Blender中MMD模型导出FBX与烘焙动画全流程避坑
FUI Element自定义血条:数据绑定与生命周期管理实践
ik_llama.cpp 离线 Repack 实战指南:将已有 GGUF 重新打包为行交错 R4 变体,摆脱 --run-time-repack 并启用 mmap

今日推荐

2026年AI设计工具在PPT制作中的核心应用与评测
Matlab手写逻辑回归:从数学原理到多变量概率预测模型实现
高值医用耗材研报PDF:用Python完成字段抽取、清洗与趋势预测

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Cocos Creator 的 Web 屏幕适配链路:DPR 钳制、安全区域 CSS 变量与旋转帧的源码拆解

发布时间:2026/9/17 20:35:20
Cocos Creator 的 Web 屏幕适配链路:DPR 钳制、安全区域 CSS 变量与旋转帧的源码拆解 Cocos Creator 的 Web 屏幕适配链路DPR 钳制、安全区域 CSS 变量与旋转帧的源码拆解【免费下载链接】cocos-engineCocos simplifies game creation and distribution with Cocos Creator, a free, open-source, cross-platform game engine. Empowering millions of developers to create high-performance, engaging 2D/3D games and instant web entertainment.项目地址: https://gitcode.com/GitHub_Trending/co/cocos-engine在 iPhone 13 Pro 上跑一份 720×1280 的画布把手机横过来 90 度游戏框换了宽高window.resize却没有触发刘海屏的安全内边距只有顶部有引擎却把上下补齐成对称矩形。Cocos Creator 的屏幕适配链路就埋着这样的取舍全在 pal/screen-adapter/web/screen-adapter.ts 一个文件里。下面拆开它的 DPR 钳制、安全区域变量和旋转帧三段实现看每个决定背后放弃了什么。核心链路在哪整条 Web 端适配只落在一个类上ScreenAdapter在 pal/screen-adapter/web/screen-adapter.ts 里接管窗口事件、全屏状态和方向变化输出是给#GameDiv和#Cocos3dGameContainer这两个 DOM 节点写样式。适配容器的核心逻辑本质上就是在算一个谁先撑满的比值const designedResolution legacyCC.view.getDesignResolutionSize() as Size; const frameW frame.clientWidth; const frameH frame.clientHeight; const designW designedResolution.width; const designH designedResolution.height; const scaleX frameW / designW; const scaleY frameH / designH; // ... 省略 3 行 if (scaleX scaleY) { containerW frameW; containerH designH * scaleX; } else { containerW designW * scaleY; containerH frameH; }横向或纵向先撑满窗口另一边就按同一比例回缩——这是等比缩放不出变形的全部秘密后面所有设计决策都是围绕它展开的。设计决策拆解DPR 上限为什么卡在 2 而不是直接透传现象3x 设备iPhone 13 Pro 的window.devicePixelRatio是 3上screen.devicePixelRatio返回 2screen.windowSize比真实物理像素小三分之一UI 文字和系统界面比会显得略微发虚。源码指向pal/screen-adapter/web/screen-adapter.ts 第 100~103 行的 getter。public get devicePixelRatio (): number { // TODO: remove the down sampling operation in DPR after supporting resolutionScale return Math.min(window.devicePixelRatio ?? 1, 2); }?? 1是给老浏览器的兜底真正的决定是Math.min这个上限canvas 缓冲区的物理像素数等于 CSS 像素乘 DPR3x 全屏渲染意味着过绘制面积接近翻倍中端机直接掉帧所以引擎统一降采样到 2。代价是写死在 getter 里没有出口——cocos/core/platform/screen.ts 里resolutionScale的 setter 整段被注释掉第 103~108 行项目侧目前无法调回 3x高 DPI 设备永远是用清晰度换帧率的方案 A。安全区域为什么读 CSS 变量而不是 JS API现象刘海屏上safeAreaEdge能拿到顶部 inset但一旦构建模板没配置viewport-fitcover四个方向静默全部为 0SafeArea组件形同虚设且没有任何报错。源码指向读取端在 pal/screen-adapter/web/screen-adapter.ts 第 152~165 行变量定义在 templates/web-mobile/style.css 第 56~61 行的:root。:root { --safe-top: env(safe-area-inset-top); --safe-right: env(safe-area-inset-right); --safe-bottom: env(safe-area-inset-bottom); --safe-left: env(safe-area-inset-left); }public get safeAreaEdge (): SafeAreaEdge { const dpr this.devicePixelRatio; const _top parseInt(getComputedStyle(document.documentElement).getPropertyValue(--safe-top) || 0) * dpr; // ... 省略 3 行bottom/left/right 同 top 的处理 return { top: _top, bottom: _bottom, left: _left, right: _right }; }走 CSS 变量中转是因为env(safe-area-inset-*)是浏览器在样式层计算的JS 在非 CSS 上下文里根本没有 API 能读到它——CSS 变量是当前唯一跨浏览器的通道。乘dpr是把 CSS 像素换算成物理像素与windowSize的单位对齐|| 0防的是变量未定义时parseInt出NaN。取舍在于引擎放弃了一个标准 JS API的体面换取了 iOS/Android/微信容器都能工作的兼容面代价是整条链路完全寄生在构建模板上——模板被改坏引擎只会安静地返回 0。横屏游戏在竖屏手机上怎么转正现象配置为竖屏的项目被用户横着拿手机画面不会被拉宽而是整个游戏框直立着占住屏幕中央两侧留黑边就像外层 div 被写了rotate(90deg)。源码指向判定在_updateFrameState第 595~603 行执行在_resizeFrame第 538~545 行同一文件。// 判定配置方向与物理方向冲突且只针对移动端 this.isFrameRotated systemInfo.isMobile ((isBrowserLandscape orientation Orientation.PORTRAIT) || (!isBrowserLandscape orientation Orientation.LANDSCAPE)); // 执行frame 宽高互换、旋转 90 度margin 把转出去的框挪回视口 // ... 省略 2 行-webkit- 前缀的同款 transform if (this.isFrameRotated) { this._gameFrame.style.transform rotate(90deg); this._gameFrame.style.transformOrigin 0px 0px 0px; this._gameFrame.style.margin 0 0 0 ${winWidth}px; this._gameFrame.style.width ${winHeight}px; this._gameFrame.style.height ${winWidth}px; }方向位定义在 pal/screen-adapter/enum-type/orientation.ts 第 25~32 行用位运算让AUTO 15能覆盖所有方向组合orientation比较天然支持横屏左右皆可这类配置。选 DOM transform 而不是重排 canvas是因为旋转发生在合成层引擎侧零拷贝成本2D/3D 场景内容完全无感。但这个技巧在移动端全屏下会失效——_getFullscreenTarget第 569~571 行直接返回document.body做全屏目标注释写明 the transform of game frame doesnt work when its on fullscreen于是旋转帧逻辑被整条绕过这就是下面第一个坑的来源。落到项目里 顶部栏/底部栏这种必须避开刘海和 Home 指示条的组件不要自己读env()直接消费引擎已经换算好的物理像素数据import { _decorator, Component, screen, sys, view, UITransform } from cc; const { ccclass } _decorator; ccclass(SafeTopBar) export class SafeTopBar extends Component { onLoad (): void { // 引擎的 window-resize 已在方向变化防抖后才派发不必自己再监听 matchMedia screen.on(window-resize, this.refresh, this); screen.on(orientation-change, this.refresh, this); this.refresh(); } onDestroy (): void { screen.off(window-resize, this.refresh, this); screen.off(orientation-change, this.refresh, this); } refresh (): void { const visible view.getVisibleSize(); // symmetricfalse 保留真实上下 inset只算顶部偏移 const safeRect sys.getSafeAreaRect(false); const topInset Math.max(visible.height - safeRect.y - safeRect.height, 0); const ui this.node.getComponent(UITransform)!; ui.setContentSize(ui.width, ui.height - topInset); } }适用边界H5 里顶栏、血条、返回键这类贴边组件可以直接用微信/字节小游戏容器里 CSS 变量不一定被填充小游戏走 pal/screen-adapter/minigame/screen-adapter.ts 的独立实现贴边组件建议改用平台自带的安全区 API 双通道取值。多分辨率适配的另一半在设计分辨率映射上一行即可声明策略import { view, ResolutionPolicy } from cc; // 设计分辨率 720×1280按最小边缩放保证内容完整显示SHOW_ALL view.setDesignResolutionSize(720, 1280, ResolutionPolicy.SHOW_ALL);适用边界SHOW_ALL在任何宽高比下不裁切内容是默认安全选项但在 18:9 长屏上左右黑边会明显偏宽想撑满画面应切到FIXED_HEIGHT再手动处理左右超出区域的 UI 裁切——策略清单和各自实现见 cocos/ui/view.ts 第 94~99 行。边界与翻车记录⚠️旋转后 UI 刷新慢半拍前 200ms 布局用的还是旧尺寸。根因方向变化回调被EVENT_TIMEOUT防抖Web 200ms、编辑器内 5ms第 41 行与第 431~433 行pal/screen-adapter/web/screen-adapter.ts因为orientationchange事件触发时window.innerWidth/innerHeight尚未更新。处理布局逻辑挂在引擎的orientation-change/window-resize上别自己再写matchMedia双份监听否则会用旧尺寸先刷一次错版。⚠️进全屏后竖屏游戏在横拿的手机上不再转正画面被拉宽。根因移动端全屏时 frame 的 transform 不生效_getFullscreenTarget回退到document.body第 569~571 行旋转帧那套样式写到了不会被全屏命中的节点上。处理全屏场景下别依赖isFrameRotated一律以sys.windowSize为准重算布局产品上要么限制全屏入口只出现在同方向设备要么接受全屏内画面拉伸。⚠️刘海只在顶部布局却把底部也顶下来一截。根因sys.getSafeAreaRect默认symmetrictrue会把上下或左右取大值补齐成对称矩形cocos/core/platform/sys.ts 第 374~386 行。这是有意为之的保守策略——横竖切换后刘海位置会变对称值最不容易把内容顶进裁切区。处理确实需要真实非对称 inset 时传getSafeAreaRect(false)或直接读screenAdapter.safeAreaEdge原始值。往哪走想看设计分辨率到可见区的完整映射EXACT_FIT/SHOW_ALL/FIXED_HEIGHT五种策略的实现差异入口在 cocos/ui/view.ts 的ResolutionPolicy族想看引擎官方怎么把安全区域数据喂给布局系统SafeArea组件cocos/ui/safe-area.ts演示了getSafeAreaRect与Widget的对齐联动。如果你手上某个具体机型出现了适配问题欢迎在项目 issue 里贴复现步骤机型、浏览器/容器版本、物理朝向三段信息齐了就能直接定位到上面哪一环。【免费下载链接】cocos-engineCocos simplifies game creation and distribution with Cocos Creator, a free, open-source, cross-platform game engine. Empowering millions of developers to create high-performance, engaging 2D/3D games and instant web entertainment.项目地址: https://gitcode.com/GitHub_Trending/co/cocos-engine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号