lili a4dc91c43a feat(shanhai): 有界竞技场+完整背景图,彻底消除背景拼接
- balance.js: ARENA={w:1560,h:2960} 有界竞技场(中心对称原点)
- sim.js: 玩家走位 clamp 到场内(边距含岩壁内沿,贴边不站黑墙/不出屏)
- render.js: 镜头 clampCam + drawPlayer 解耦屏心 + drawGround 一档接整幅背景图(二档视差瓦片兜底)+ 四边自然暗角 + 背景降颗粒
- art.js: 登记 bg-map1-arena-01 + 后台拉起预载 + tiles 降懒载(不增首屏网络字节)
- assets/bg/bg-map1-arena-01.jpg: 矿彩国风裂谷原整图(1560x2960,AI 草图创始人审)
- 墙角死角作为有界竞技场设计保留;⑧win 重跑留下检查点
2026-07-25 01:12:24 -07:00

7.8 KiB
Raw Blame History

round-11 — 竞技场边界 + 接大图 bg-map1-arena-01 + CDP 截实际效果

检查点目标:缩放定稿草图 → 放 assets → 加竞技场边界(玩家+镜头 clamp)→ 接整幅战场背景图 → 真浏览器 CDP 截接图后战场背景。本检查点不重跑⑧win(留下检查点,避免超载)。

  • 机器:lili-mac.local(开发机本地,非 mini-desktop;未 ssh)。
  • 采集时间:2026-07-25T06:4006:41Z。视口 390×844 @ DPR2(截图 780×1688)。seed=777。
  • 采集器:/tmp/arena-e2e.mjs(临时脚本,置 /tmp 不入仓;node 子进程拉起 http.server + headless Chrome,CDP 前台跑到返回,finally 杀进程删 profile)。
  • 诚实红线:背景效果主观,本文只记代码 + 截图事实,美丑交创始人眼验。

一、图处理(任务一)

/tmp/bg-draft/arena-bg_001.jpg(1080×2048,创始人审"还行")
缩放 sips -z 2960 15601560×2960(竖屏,与 ARENA 同尺寸)
格式 jpg(webp 写工具全缺:cwebp 无、ffmpeg 无 libwebp、sips 可读不可写 webp;按任务回退规则用 jpg,quality 82)
产物 assets/bg/bg-map1-arena-01.jpg,1,352,878 字节(1.29 MB)
解码内存 1560×2960×4 = 18,470,400 字节 = 17.61 MB(≤20MB 优 / 硬顶 33MB ✓)
浏览器解码探针 CDP 内 <img> 同 url → ready 1560x2960(确认资产可解码,与 art.js 拉同一资源)

二、加边界 + 接图(任务二,逐处落地)

src/balance.jsPLAYER 后新增 export const ARENA = { w: 1560, h: 2960 }(中心对称原点,玩家 (0,0)=场心;sim 与 render 共用)。

src/sim.js — import 加 ARENA;主循环玩家移动(player.y += ...)后加竞技场 clamp,纯函数不破确定性: player.x = Math.max(-ARENA.w/2 + player.r, Math.min(ARENA.w/2 - player.r, player.x))(y 同理),留 player.r=12 边距。

src/render.js

  • import 加 ARENA;新增 clampCam(cam,world,view);drawGame 镜头由 player - view/2 改为 clampCam(...),下界 -world/2、上界 world/2 - view(竞技场≥视口,镜头不出界)。
  • 耦合修复:drawPlayer 调用点改传 camX,camY;签名同步;函数体 x,y 由恒屏心 viewport.w/2,h/2 改为 v.player.x - camX, v.player.y - camY(否则近边缘玩家脱出精灵位)。
  • drawGround 改三档:一档 = art.hasBg('bg-map1-arena-01')art.drawBg(..., -ARENA.w/2-camX, -ARENA.h/2-camY, ARENA.w, ARENA.h, 1) + 新增 drawArenaBounds(四边 96px 向内渐隐暗带=岩壁/暗角压边)+ drawDeco(...,ARENA)(装饰裁到场内);二档 = 原视差+羽化瓦片+明暗(大图未载兜底);三档 = 无图哈希撒点。装饰循环抽成 drawDeco(g,...,arena),无界时哈希口径逐字沿用旧版(零回归)。

src/art.js

  • BG_ASSET 登记 bg-map1-arena-01(url ./assets/bg/bg-map1-arena-01.jpg)。
  • 预载策略(决策点 A):preloadFirstScreen() 后台拉起 arena 大图(lazyImage,菜单驻留期异步解码;未载完 hasBg=false → 渲染自动落二档,不闪白)。
  • tiles-map1 降级:移出首屏预载,改 ensureTile() 首次 drawTile 需要时懒拉(大图接起后 tiles 仅作二档兜底)。

三、首屏字节(如实,三口径)

口径 字节 是否 ≤2MB 说明
build-report firstScreenBytes(代码 bundle+html,任务指定测此) 379,191(0.362 MB) ✓ PASS 此脚本只测代码,不含图像;接图前后不变
运行时首屏图像(host loadHostAssetsmanifest.json assets[] 预载) 1,799,464 图像 + 379KB 代码 ≈ 2.078 MB ✗(预我改前已 >2MB) 由 manifest.json 决定,本检查点超纲未改;见下"边界说明"
arena 大图(经 art.js lazyImage 异步拉,进 manifest) 1,352,878(1.29 MB) 不计首屏 故意走后台异步,不顶首屏门

边界说明(诚实):真实运行时首屏图像预载由 manifest.jsonassets[]boot-game-host.loadHostAssets() 在 boot 时全量 new Image() 拉起,与 art.js 的 FIRST_SCREEN_PAGES 无关;该 manifest 合计已 ≈2.08MB(本检查点前即超 2MB)。我在 art.js 把 tiles 降为懒载只影响 art.js 的自载兜底路径,不改变 host 网络首屏——要让 tiles 真退出首屏网络、或把 arena 图纳入首屏,须改 manifest.json,而它不在本检查点工作目录白名单(只许 src×4 + assets/bg + dist + evidence/round-11)。我的 arena 图改走 art.js 异步后台拉取,正好满足"init 后台拉起、菜单驻留期解码、不顶首屏门",故接图本身不增加首屏网络字节。

四、加边界正确性(CDP 实测,seed=777)

玩家世界坐标被 clamp 到 ±(world/2 r)= ±768(x)/±1468(y);镜头 clamp 到 [world/2, world/2view];玩家屏幕位 = pos cam,贴边时恰距屏边 12px(=player.r),证明 drawPlayer 的 camX/camY 耦合生效(镜头 clamp 后玩家不再恒在屏心):

截图 世界 pos 镜头 cam 屏幕 sx,sy 亮度比 看到的
01 全景 (0,0) (195,422) (195,422) 屏心 0.582 整幅彩色战场中心,玩家居中
02 右缘 (768,0) (390,422) (378,422) 0.243 右岩壁压边,玩家贴右
03 上缘 (768,1468) (390,1480) (378,12) 0.054 上+右岩壁,玩家贴右上角
04 左缘 (768,1468) (780,1480) (12,12) 0.056 左+上岩壁,玩家贴左上角
05 下缘 (768,1468) (780,636) (12,832) 0.051 左+下岩壁,玩家贴左下角
06 右下角 (768,1468) (390,636) (378,832) 0.122 右+下岩壁 + 角落暗角收口

pageErrors=0(新 render/sim 代码无崩溃)。console 7 条均为良性:1 条 favicon 类 404(非 page error;arena 图本身探针 200 ready)+ 6 条 willReadFrequently(我亮度探针 getImageData 自产,非游戏代码)。

五、需创始人定夺的观察(已眼验截图,非阻断)

  1. 玩家走进岩壁暗带:clamp 边距 = player.r=12px,而岩壁暗带 T=96px,玩家贴边时其碰撞中心距世界边 12px = 落在 96px 暗带内约 84px,视觉上玩家"站进黑墙里"(见 02/06)。三选项交决:① 收薄暗带 T(墙感变弱);② 把 clamp 边距提到≈T(玩家停在墙内沿、不入围合带,但可达区每边缩≈96px,改手感);③ 维持现状。任务原文指定 player.r 边距,故未擅改。
  2. 上缘精灵裁切:玩家贴顶边时,高个主角 sprite 以底部锚定在 ~12px 处、躯体向上延伸出视口,顶边近乎"潜入墙下"(见 03)。根因同①小边距 + 高 sprite。
  3. 背景颗粒/暗边:1080→1560 上采样 + DPR2 二倍绘 → 颗粒感;AI 草图本身顶/底偏暗,叠加岩壁带后边缘偏暗(亮度 0.05)。美丑归创始人。
  4. 有界竞技场的玩法含义:玩家现可被逼到墙角(06 角落 HP=64、敌群贴墙成排)——以前无界世界可无限风筝,加边界后存在"被墙困住"的死角,难度/手感随之变。此为加边界的固有后果,记录供创始人评估是否调整边距或留逃生缓冲。

六、产物 sha256

源码 + 图:

  • src/balance.js 9094f814b1987c4456d45391052d083061a5ce342a2c5a122a90a6f13342086d
  • src/sim.js ed07425784ccd3a1cbfb1c0f1eb7a1b2a6d1fb716ce3f5dccefbe1ef325b45da
  • src/render.js fa04a02e067752507b02c2a188a2f70810ddc3864aae340d4a410afe46488726
  • src/art.js 224e8d09da63a7f65a2e2be69bb42856b9557088cde0ff472a4712694adbfc0e
  • assets/bg/bg-map1-arena-01.jpg aaa42f3a2f2a47e35f2d7f68cf7e64e7a53726983f68081c0d9f86daadec1956

六张截图 sha256 见同目录 00-arena-bg-result.jsonshots[].sha256

七、外部状态变更

无 git add/commit/push;无 staging;未碰 mini-infra;未 ssh mini-desktop;未碰 plugins / game-runtime/src / contracts(本会话零编辑越出 shanhai-xingji;working tree 中 game-runtime/src/*plugins/match3-* 的 M/?? 为既有在飞 WIP,与本检查点无关);本地 serve + headless Chrome 已杀、端口释放、/tmp profile 已删,ps/lsof 复核无孤儿。