13 lines
5.5 KiB
JavaScript
13 lines
5.5 KiB
JavaScript
const test=require('node:test'),assert=require('node:assert/strict'),M=require('matter-js'),C=require('../src/core.js'),{Game}=require('../src/game.js');
|
|
const rect=(id,x=0,w=100,h=100)=>({id:String(id),name:'块'+id,center:[x+w/2,h/2],rings:[[[x,0],[x+w,0],[x+w,h],[x,h]]]});
|
|
const level={id:'test',name:'回正一次',width:1000,height:1000,regions:[rect(0),rect(1,200),rect(2,400)],edges:[]};
|
|
function game(map=level){const g=new Game(map,420,620,4,()=>{},()=>.5,1,0);g.status='playing';g.queue=[];g.engine.gravity.y=0;return g;}
|
|
function depth(a,b){let d=0;for(const x of a.parts.length>1?a.parts.slice(1):[a])for(const y of b.parts.length>1?b.parts.slice(1):[b]){if(!M.Bounds.overlaps(x.bounds,y.bounds))continue;const c=M.Collision.collides(x,y);if(c)d=Math.max(d,c.depth);}return d;}
|
|
test('默认自由转动,不再有自动回正模式或持续控制器',()=>{const g=game(),p=g.createGroup([0],{tx:140,ty:250,angle:.8});assert.equal(g.setAutoUpright,undefined);assert.equal(g.stepAutoUpright,undefined);for(let i=0;i<200;i++)g.tick(1000/60);assert.ok(Math.abs(p.body.angle-.8)<1e-8);assert.equal(g.uprightUsed,false);assert.equal(g.uprightCount,0);g.destroy();});
|
|
test('点击一次将现有地块朝上,停止当下旋转但保留平移冲量',()=>{const g=game();for(let i=0;i<3;i++){const p=g.createGroup([i],{tx:0,ty:0,angle:[.8,-1.7,Math.PI*2-.9][i]});M.Body.setPosition(p.body,{x:90+i*115,y:270});M.Body.setVelocity(p.body,{x:2,y:-1});M.Body.setAngularVelocity(p.body,.015);M.Sleeping.set(p.body,true);}const before=g.groups.map(p=>({...p.body.position}));const out=g.uprightOnce();assert.equal(out.turned,3);for(let i=0;i<3;i++){const b=g.groups[i].body;assert.ok(Math.abs(b.angle)<1e-10);assert.equal(b.angularVelocity,0);assert.equal(b.isSleeping,false);assert.deepEqual(b.position,before[i]);}assert.equal(g.uprightCount,1);assert.equal(g.uprightUsed,true);g.destroy();});
|
|
test('一次回正后可以继续旋转,新生成地块不会被自动修正',()=>{const g=game(),a=g.createGroup([0],{tx:140,ty:250,angle:.8});g.uprightOnce();M.Body.setAngle(a.body,.55);M.Body.setAngularVelocity(a.body,.015);g.tick(1000/60);assert.ok(a.body.angle>.56);M.Body.setAngularVelocity(a.body,0);const angle=a.body.angle,b=g.createGroup([1],{tx:100,ty:400,angle:-.7});for(let i=0;i<120;i++)g.tick(1000/60);assert.ok(Math.abs(a.body.angle-angle)<1e-8);assert.ok(Math.abs(b.body.angle+.7)<1e-8);assert.equal(g.uprightCount,1);g.destroy();});
|
|
test('按下即全部归零,不试算碰撞、不因邻块阻挡而跳过,也不移动中心',()=>{const map={...level,regions:[rect(0,0,180,45),rect(1,0,65,65)]},g=game(map),a=g.createGroup([0],{tx:0,ty:0,angle:.8}),b=g.createGroup([1],{tx:0,ty:0,angle:-.3});M.Body.setPosition(a.body,{x:200,y:280});M.Body.setPosition(b.body,{x:171,y:279});const before=g.groups.map(p=>({...p.body.position}));g.sampledPairBlocked=g.guardPairBlocked=()=>{throw Error('回正不应调用碰撞检查');};assert.equal(g.tryUprightAngle,undefined);assert.equal(g.uprightOnce().turned,2);g.groups.forEach((p,i)=>{assert.equal(p.body.angle,0);assert.equal(p.body.angularVelocity,0);assert.deepEqual(p.body.position,before[i]);});g.destroy();});
|
|
test('贴地横躺的长块直接正向,按钮不试算容器、不挪位置',()=>{const g=game({...level,regions:[rect(0,0,45,180)]}),p=g.createGroup([0],{tx:0,ty:0,angle:Math.PI/2});M.Body.setPosition(p.body,{x:210,y:610});M.Body.setVelocity(p.body,{x:2,y:-1});const before={...p.body.position};assert.equal(g.uprightOnce().turned,1);assert.equal(p.body.angle,0);assert.deepEqual(p.body.position,before);assert.equal(p.body.velocity.x,2);assert.equal(p.body.velocity.y,-1);g.destroy();});
|
|
test('没有落地块、暂停或结束时不执行回正,次数与成绩保留且不改变分数',()=>{const g=game();g.uprightOnce();assert.equal(g.uprightCount,0);const p=g.createGroup([0],{tx:140,ty:250,angle:1});g.score=360;g.status='paused';g.uprightOnce();assert.equal(p.body.angle,1);assert.equal(g.uprightCount,0);g.status='playing';g.uprightOnce();assert.equal(g.score,360);g.resize(360,560);assert.equal(g.uprightCount,1);g.finish();const count=g.uprightCount;g.uprightOnce();assert.equal(g.uprightCount,count);g.destroy();});
|
|
test('真实湖北、成都连续落子晃动和直接回正,物理继续推进且状态有限',()=>{const fs=require('node:fs'),vm=require('node:vm'),box={window:{}};vm.runInNewContext(fs.readFileSync('src/maps.js','utf8'),box);let city;vm.runInNewContext(fs.readFileSync('src/county/510100.js','utf8'),{window:{PuzzleAtlas:{register(l){city=l;}}}});for(const map of [box.window.MAP_DATA.levels.find(l=>l.id==='420000'),city]){let seed=27;const rng=()=>{seed=(seed*1664525+1013904223)>>>0;return seed/4294967296;},g=new Game(map,340,560,4,()=>{},rng,1,0);g.start();let travelled=0,samples=0;for(let i=0;i<1800&&g.status==='playing';i++){if(g.pending&&i%70===0){const serial=g.pending.serial;g.movePending(30+rng()*280,serial);g.holdPending(serial);g.releasePending(serial);}if(i%200===0)g.uprightOnce();if(i%23===0)g.swipe({x:40+rng()*260,y:260+rng()*270},{x:(rng()-.5)*140,y:(rng()-.7)*140},60);const before=new Map(g.groups.map(p=>[p.body.id,{...p.body.position}]));g.tick(1000/60);if(i>600)for(const p of g.groups){const b=before.get(p.body.id);if(b){travelled+=Math.hypot(p.body.position.x-b.x,p.body.position.y-b.y);samples++;}}for(const p of g.groups)assert.ok(Number.isFinite(p.body.position.x)&&Number.isFinite(p.body.position.y)&&Number.isFinite(p.body.angle),map.id+' 应继续正常物理解算');}assert.equal(g.dropped,map.regions.length);assert.ok(travelled/samples>.35,'单次回正后仍须自由运动');assert.ok(g.uprightCount>1);g.destroy();}});
|