diff --git a/game-runtime/games/wanglanmei-ref/index.html b/game-runtime/games/wanglanmei-ref/index.html index 77fd91c4..6f85a005 100644 --- a/game-runtime/games/wanglanmei-ref/index.html +++ b/game-runtime/games/wanglanmei-ref/index.html @@ -25,29 +25,35 @@ font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif; overflow: hidden; } + /* 收编修(轮1评估段):状态行改浮层、wrap 零内边距——canvas 必须顶在 (0,0) 满幅 390×844。 + 旧 flex 列布局把 canvas 下推 ≈29px:e2e 真输入坐标整体偏移,且 844 视口裁掉 canvas 底部 29px + (真机亲玩底部按钮点不到)。状态行 pointer-events:none 防截触摸。 */ #wrap { - display: flex; - flex-direction: column; - align-items: center; - gap: 6px; - padding: 6px 0; + position: relative; + width: 390px; + margin: 0 auto; } #game { width: 390px; height: 844px; background: #f6e7c9; display: block; - border-radius: 8px; touch-action: none; /* 触摸全交 JS(pointer 桥接),禁浏览器默认手势 */ } #status { + position: absolute; /* 浮层叠于 canvas 顶部,不占布局流 */ + top: 0; + left: 0; + right: 0; + z-index: 2; + pointer-events: none; /* 绝不截触摸 */ font-size: 12px; line-height: 1.4; min-height: 15px; - max-width: 390px; text-align: center; word-break: break-all; opacity: 0.85; + text-shadow: 0 1px 2px rgba(46, 35, 27, 0.8); /* 深底浮字可读性 */ } diff --git a/game-runtime/games/wanglanmei-ref/test/e2e-input.cdp.cjs b/game-runtime/games/wanglanmei-ref/test/e2e-input.cdp.cjs index b4aa953e..19b371af 100644 --- a/game-runtime/games/wanglanmei-ref/test/e2e-input.cdp.cjs +++ b/game-runtime/games/wanglanmei-ref/test/e2e-input.cdp.cjs @@ -103,11 +103,27 @@ async function listZones(phaseTag) { if (phaseTag) evidence.zonesSeenByPhase[phaseTag] = zs.map((z) => z.id); return zs; } -/** CDP 真触摸点按(touchStart→touchEnd 成对;轨迹留痕)。 */ +/* 坐标映射:geometry() 的 zone 坐标在 canvas 逻辑空间(VIEW),CDP dispatch 用页面 CSS 坐标。 + 首跑实翻教训:页面壳曾把 canvas 下推 ≈29px,zone 坐标直发全部偏移 → 一律经 rect 映射换算。 */ +let MAP = { l: 0, t: 0, sx: 1, sy: 1 }; +async function initMapping() { + const m = await cdp.evaluate(`(function(){ + var c = document.getElementById('game'); var r = c.getBoundingClientRect(); + var dpr = window.devicePixelRatio || 1; + return { l: r.left, t: r.top, w: r.width, h: r.height, vw: c.width / dpr, vh: c.height / dpr }; + })()`); + MAP = { l: m.l, t: m.t, sx: m.w / m.vw, sy: m.h / m.vh }; + evidence.meta.coordMap = { rect: m, map: MAP }; + console.log(' · 坐标映射:', JSON.stringify(evidence.meta.coordMap)); +} +const toClient = (x, y) => ({ x: MAP.l + x * MAP.sx, y: MAP.t + y * MAP.sy }); + +/** CDP 真触摸点按(touchStart→touchEnd 成对;轨迹留痕,zone 系与页面系双记)。 */ async function tapAt(x, y, zoneId) { - await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x, y }] }); + const c = toClient(x, y); + await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x: c.x, y: c.y }] }); await cdp.send('Input.dispatchTouchEvent', { type: 'touchEnd', touchPoints: [] }); - trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'tap', zoneId: zoneId || null, x, y }); + trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'tap', zoneId: zoneId || null, x, y, clientX: c.x, clientY: c.y }); await delay(90); // 让真事件经浏览器→输入桥落地 await stepFrames(3); // 推帧消化(反馈注册/状态机流转) } @@ -119,16 +135,17 @@ async function tapZone(id) { await tapAt(z.x, z.y, id); return true; } -/** 真触摸拖拽(touchStart→分段 touchMove→touchEnd;价格滑条用)。 */ +/** 真触摸拖拽(touchStart→分段 touchMove→touchEnd;价格滑条用;坐标同样经 rect 映射)。 */ async function dragTouch(x0, y0, x1, y1, zoneId, steps = 8) { - await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x: x0, y: y0 }] }); + const a = toClient(x0, y0), b = toClient(x1, y1); + await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x: a.x, y: a.y }] }); for (let i = 1; i <= steps; i++) { - const x = x0 + ((x1 - x0) * i) / steps, y = y0 + ((y1 - y0) * i) / steps; + const x = a.x + ((b.x - a.x) * i) / steps, y = a.y + ((b.y - a.y) * i) / steps; await cdp.send('Input.dispatchTouchEvent', { type: 'touchMove', touchPoints: [{ x, y }] }); await delay(16); } await cdp.send('Input.dispatchTouchEvent', { type: 'touchEnd', touchPoints: [] }); - trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'drag', zoneId: zoneId || null, x: x0, y: y0, x1, y1 }); + trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'drag', zoneId: zoneId || null, x: x0, y: y0, x1, y1, clientX: a.x, clientY: a.y }); await delay(90); await stepFrames(3); } @@ -156,6 +173,7 @@ async function shot(name, withHash) { /* 门 A:boot+probe 链(FORENSICS §4-1/2) */ cdp = await connectRef(URL_EVIDENCE); try { + await initMapping(); // zone(canvas 逻辑系)→页面 CSS 系映射,一切真输入坐标经此换算 const probe = await F('FZ.probe()'); fs.writeFileSync(path.join(OUT_DIR, 'probe.jsonl'), (probe.jsonl || '') + '\n'); check(probe.verify && probe.verify.ok === true, `probe 链 verify.ok(实际:${JSON.stringify(probe.verify)})`);