Initial commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import * as THREE from 'three';
|
||||
import { createPhysicsWorld, initPhysics } from '../src/physics/world.js';
|
||||
import { createMatch } from '../src/game/match.js';
|
||||
import { describeHit } from '../src/game/hits.js';
|
||||
|
||||
/**
|
||||
* Fire skaters at each other from various run-ups and angles and print what
|
||||
* comes out. A tuning aid, not a test: the numbers below are the ones you stare
|
||||
* at when deciding what should count as a bump, a stagger and a knockdown.
|
||||
*
|
||||
* node tools/hitprobe.mjs
|
||||
*/
|
||||
|
||||
const DT = 1 / 60;
|
||||
await initPhysics();
|
||||
|
||||
/**
|
||||
* @param {'stationary'|'full'} mode is the victim skating into it too
|
||||
* @param {number} gap metres between them at the start
|
||||
* @param {number} offsetZ lateral offset — 0 is dead centre
|
||||
*/
|
||||
function probe(mode, gap, offsetZ = 0) {
|
||||
const physics = createPhysicsWorld();
|
||||
const match = createMatch({ scene: new THREE.Group(), physics, perTeam: 1, teams: 2 });
|
||||
const [a, b] = match.states;
|
||||
a.x = -gap / 2; a.z = 0; a.yaw = Math.PI / 2;
|
||||
b.x = gap / 2; b.z = offsetZ; b.yaw = mode === 'full' ? -Math.PI / 2 : Math.PI / 2;
|
||||
match.skaters[0].proxy.teleport(a.x, a.z);
|
||||
match.skaters[1].proxy.teleport(b.x, b.z);
|
||||
match.setControl(0, { x: 1, y: 0, sprint: true, brake: false, cameraYaw: 0 });
|
||||
match.setControl(1, mode === 'full'
|
||||
? { x: -1, y: 0, sprint: true, brake: false, cameraYaw: 0 }
|
||||
: { x: 0, y: 0, sprint: false, brake: false, cameraYaw: 0 });
|
||||
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (let n = 0; n < 6 / DT; n++) {
|
||||
match.update(DT);
|
||||
for (const h of match.recentHits) {
|
||||
const id = `${h.at}|${h.attacker}`;
|
||||
if (!seen.has(id)) {
|
||||
seen.add(id);
|
||||
out.push(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
physics.destroy();
|
||||
return out;
|
||||
}
|
||||
|
||||
const rows = [
|
||||
['stationary', 2.5, 0],
|
||||
['stationary', 5, 0],
|
||||
['stationary', 10, 0],
|
||||
['stationary', 22, 0],
|
||||
['stationary', 22, 0.45],
|
||||
['stationary', 22, -0.45],
|
||||
['full', 10, 0],
|
||||
['full', 24, 0],
|
||||
['full', 24, 0.5],
|
||||
];
|
||||
|
||||
console.log('mode gap offZ | outcome m/s sev limbs description');
|
||||
console.log('-'.repeat(96));
|
||||
for (const [mode, gap, off] of rows) {
|
||||
const hits = probe(mode, gap, off);
|
||||
if (!hits.length) {
|
||||
console.log(`${mode.padEnd(11)} ${String(gap).padStart(4)} ${String(off).padStart(5)} | (no hit)`);
|
||||
continue;
|
||||
}
|
||||
for (const h of hits) {
|
||||
console.log(
|
||||
`${mode.padEnd(11)} ${String(gap).padStart(4)} ${String(off).padStart(5)} | `
|
||||
+ `${h.outcome.padEnd(10)} ${h.speed.toFixed(1).padStart(4)} ${h.severity.toFixed(1).padStart(5)} `
|
||||
+ `${(h.attackerPart + '→' + h.victimPart).padEnd(24)} ${describeHit(h)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user