取景(issue 04) - 新增 viewport-fitter.js:让立绘层缩放跟随背景图的 cover 缩放——背景放大多少倍、 特效就放大多少倍。原先背景走 cover、立绘层走 contain,比例一变两者就分叉。 16:9 下与作者设定逐像素一致(kv37 为 0 差异)。实测证伪了"contain 会裁掉作者视口" 这个最初的判断:contain 在任何比例下都完整含住作者视口。 - 应用方式为原地改写 config.viewport 字段后调 setViewport(),不重建播放器; 维护挂在 config.frame 上按画布比例增量进行(config.success 早于 setViewport,拿不到视口)。 WE 属性(issue 05) - project.json 新增 bgm combo(所有壁纸音源的并集 + 「随预设」);所选项不属于当前壁纸时 音频回落该壁纸默认,选择本身保留。 - fps 限流包裹实例 drawFrame 并接管排程。修掉两个实测缺陷:朴素丢帧会把 rAF 抖动放大成 整拍丢失(目标 30fps 实测只有 22.5fps);fps:0 被真值判断吞掉导致无法取消限流。 打包(issue 06) - project.json version 升至 3 并更新描述;preset 的 combo 取值保持 xilian/kv37 不变。 - preview.gif 821 KB → 347 KB(每 2 帧取 1 帧 + 128 色不抖动,逐帧与源帧像素完全相同)。 - index.html 加内联 favicon,消除 CEF 自动请求 /favicon.ico 造成的 404 报错。 其它 - dist/scripts/wallpaper-engine.js 移到 tools/:它没有任何入口引用,且环境判据依赖真实 WE 并不存在的 wallpaperRegisterListener,一旦按它自己的说明挂进 index.html 会在生产环境自我激活。 - 修正死文件检查:原检查会拿文件名匹配到文件自身的内容,使这类文件漏网。 - 新增离线算式验证与 resize / 属性 / 全量验收三套浏览器测试脚本。
65 lines
2.9 KiB
JavaScript
65 lines
2.9 KiB
JavaScript
// 立绘层的取景计算。纯函数:只做世界坐标矩形的算术,不碰 DOM,也不碰播放器实例。
|
|
//
|
|
// 矩形一律是 { x, y, width, height },世界单位,y 轴向上。
|
|
//
|
|
// 为什么需要这一层:
|
|
// 背景图走 CSS `background-size: cover`(铺满、按需裁切),
|
|
// 立绘层却由播放器按「含住作者视口」映射(contain)。两者只在作者调参的那个比例下一致,
|
|
// 比例一变,缩放倍率就分叉——竖屏下背景放大 1.78 倍,立绘层却纹丝不动,特效于是和背景插画脱节。
|
|
// 这里让立绘层的缩放跟着背景 cover 的缩放走,两者始终同倍率、同中心。
|
|
|
|
// 作者调参时的基准比例。在这个比例下取景与作者设定逐像素一致。
|
|
export const REFERENCE_ASPECT = 16 / 9;
|
|
|
|
// 播放器把 currentViewport(基矩形 + 四边内边距)解成最终可见矩形。
|
|
// 对应 spine-player.js 里 `viewport.x = currentViewport.x - padLeft` 那四行。
|
|
export function resolveViewport(viewport) {
|
|
return {
|
|
x: viewport.x - viewport.padLeft,
|
|
y: viewport.y - viewport.padBottom,
|
|
width: viewport.width + viewport.padLeft + viewport.padRight,
|
|
height: viewport.height + viewport.padBottom + viewport.padTop,
|
|
};
|
|
}
|
|
|
|
// 把矩形按 aspect 撑到刚好含住它,中心不变。这正是播放器在参考比例下的行为。
|
|
export function contain(rect, aspect) {
|
|
const width = Math.max(rect.width, rect.height * aspect);
|
|
const height = width / aspect;
|
|
const cx = rect.x + rect.width / 2;
|
|
const cy = rect.y + rect.height / 2;
|
|
return { x: cx - width / 2, y: cy - height / 2, width, height };
|
|
}
|
|
|
|
// 背景在某个画布比例下的 cover 缩放,以「受高度约束时的倍率」为 1 归一化。
|
|
// 背景比画布更宽时按高度铺满(倍率不变),画布更宽时按宽度铺满(倍率随 aspect 增长)。
|
|
export function coverScale(aspect, imageAspect) {
|
|
return Math.max(aspect / imageAspect, 1);
|
|
}
|
|
|
|
// 目标可见矩形:参考比例下正好等于作者视口,其余比例按背景 cover 缩放的反比收放。
|
|
// 效果等价于「立绘层相对背景插画永远 cover」。
|
|
export function frameForAspect(reference, aspect, imageAspect, referenceAspect = REFERENCE_ASPECT) {
|
|
const height =
|
|
(reference.height * coverScale(referenceAspect, imageAspect)) / coverScale(aspect, imageAspect);
|
|
const width = height * aspect;
|
|
const cx = reference.x + reference.width / 2;
|
|
const cy = reference.y + reference.height / 2;
|
|
return { x: cx - width / 2, y: cy - height / 2, width, height };
|
|
}
|
|
|
|
// 把目标可见矩形写成播放器 config.viewport 需要的字段:内边距归零,
|
|
// 这样 resolveViewport() 得到的就是它本身。
|
|
export function toViewportConfig(rect) {
|
|
return {
|
|
x: rect.x,
|
|
y: rect.y,
|
|
width: rect.width,
|
|
height: rect.height,
|
|
padLeft: 0,
|
|
padRight: 0,
|
|
padTop: 0,
|
|
padBottom: 0,
|
|
};
|
|
}
|