Files
NumberSwipe_New/wechat-campaign-200-r2/qa/hints.html
T

56 lines
5.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html><meta charset="utf-8"><title>指路与玩家填色像素回归</title>
<style>body{font:16px sans-serif;background:#eee}#views{display:flex;gap:12px}canvas{width:375px;height:812px;background:white}h1{font-size:20px}</style>
<style>
@font-face{font-family:NumberSwipeSans500;src:url(../fonts/NumberSwipeSans500.ttf)}
@font-face{font-family:NumberSwipeSans600;src:url(../fonts/NumberSwipeSans600.ttf)}
@font-face{font-family:NumberSwipeSans700;src:url(../fonts/NumberSwipeSans700.ttf)}
@font-face{font-family:NumberSwipeDigits800;src:url(../fonts/NumberSwipeDigits800.ttf)}
@font-face{font-family:NumberSwipePlayful;src:url(../fonts/NumberSwipePlayful.ttf)}
</style>
<h1>指路与玩家填色像素回归</h1><p id="result">检查中…</p><div id="views"></div>
<script type="module">
import {solve} from '../src/upstream/rules.mjs';
await Promise.all(['NumberSwipeSans500','NumberSwipeSans600','NumberSwipeSans700','NumberSwipeDigits800','NumberSwipePlayful'].map(f=>document.fonts.load('16px '+f)));
const pack=await(await fetch('../src/upstream/levels.json')).json();
const source=await(await fetch('../game.js')).text();
const levels=pack.playOrder.map(id=>pack.levels.find(l=>l.id===id));
const canvases=[],handlers={},frames=new Map(),storage=new Map();let frameId=0,now=100000;
class Clock extends Date{static now(){return now;}}
const wx={
loadFont:p=>p.split('/').at(-1).replace('.ttf',''),
createCanvas(){const c=document.createElement('canvas');if(!canvases.length)canvases.push(c);return c;},
getWindowInfo:()=>({windowWidth:375,windowHeight:812,pixelRatio:1,safeArea:{top:44,bottom:778}}),
getMenuButtonBoundingClientRect:()=>({bottom:80}),getPerformance:()=>({now:()=>now}),
getStorageSync:k=>storage.get(k)||'',setStorageSync:(k,v)=>storage.set(k,v),removeStorageSync:k=>storage.delete(k),
setInnerAudioOption(){},createInnerAudioContext:()=>({stop(){},onError(){},play(){}}),showModal(){},env:{USER_DATA_PATH:'/user'}
};
for(const n of ['TouchStart','TouchMove','TouchEnd','TouchCancel','Hide','Show','WindowResize'])wx['on'+n]=cb=>handlers[n]=cb;
const global={};
new Function('wx','GameGlobal','requestAnimationFrame','cancelAnimationFrame','setTimeout','clearTimeout','Date',source)(wx,global,cb=>{frames.set(++frameId,cb);return frameId;},id=>frames.delete(id),()=>1,()=>{},Clock);
const api=global.numberSwipeR2;
const tick=(ms=16)=>{now+=ms;const entry=frames.entries().next().value;if(!entry)return;const [id,fn]=entry;frames.delete(id);fn();};tick();
const tap=(x,y)=>{const e={changedTouches:[{identifier:1,clientX:x,clientY:y}],touches:[{identifier:1,clientX:x,clientY:y}]};handlers.TouchStart(e);handlers.TouchEnd(e);tick();};
const button=label=>{const b=api.buttons().find(b=>b.label===label);if(!b||!b.enabled)throw Error('缺少按钮 '+label);tap(b.x+b.w/2,b.y+b.h/2);};
const cell=id=>{const s=api.snapshot(),[x,y]=s.centers[id];tap(x+s.boardRect.x,y+s.boardRect.y);};
const select=i=>{if(api.buttons().some(b=>b.label==='返回游戏'))button('返回游戏');if(api.snapshot().screen!=='select')button('选关');let n=0;while(!api.buttons().some(b=>b.label===String(i+1)||b.label===`${i+1} ✓`)){button(api.snapshot().selection.chapter>Math.floor(i/10)+1?'上一页':'下一页');if(++n>25)throw Error('分页失败');}button(api.buttons().some(b=>b.label===String(i+1))?String(i+1):`${i+1} ✓`);if(api.buttons().some(b=>b.label==='返回游戏'))button('返回游戏');};
const capture=()=>{const c=document.createElement('canvas');c.width=375;c.height=812;c.getContext('2d').drawImage(canvases[0],0,0);return c;};
const samples=(route)=>{const s=api.snapshot(),ctx=canvases[0].getContext('2d');return route.map(id=>{const p=s.centers[id];return Array.from(ctx.getImageData(Math.round(p[0]-s.unit*.08),Math.round(p[1]+s.boardRect.y+s.unit*.18),5,5).data);});};
let checked=0;const result=document.querySelector('#result');
try{
for(let i=0;i<levels.length;i++){
select(i);const route=solve(levels[i])[0],n=Math.min(2,route.length-1);
for(const id of route.slice(0,n))cell(id);tick(1800);
const before=samples(route.slice(0,n));const base=capture();
button('重开');button('指路');for(const id of route.slice(0,n))cell(id);tick(1800);
const after=samples(route.slice(0,n));
if(JSON.stringify(before)!==JSON.stringify(after)){document.querySelector('#views').replaceChildren(base,capture());throw Error('玩家填色像素变化:第 '+(i+1)+' 关');}
button('撤销');cell(route[n-1]);tick(1800);
if(JSON.stringify(before)!==JSON.stringify(samples(route.slice(0,n))))throw Error('撤销后填色变化:'+(i+1));
checked++;
if(i%4===0){result.textContent=`正在检查 ${checked}/200 关…`;await new Promise(resolve=>requestAnimationFrame(resolve));}
if(i===3){document.querySelector('#views').replaceChildren(base,capture());}
}
result.textContent=`PASS:${checked}/200 关,点击指路前后和撤销重画后,玩家已走格子的实际 Canvas 填色像素一致。左图无提示,右图开启高对比提示。`;
}catch(e){result.textContent='FAIL:'+e.message;console.error(e);}
</script>