animations
This commit is contained in:
@@ -183,6 +183,113 @@ section('turning is harder at speed than at rest');
|
||||
);
|
||||
}
|
||||
|
||||
section('LT does not spin the body around');
|
||||
{
|
||||
// Facing +X, stick pulled toward −X under LT — should retreat heels-first
|
||||
// without yaw flipping to face the stick.
|
||||
const s = createSkaterState(0, { x: 0, z: 0, yaw: Math.PI / 2 });
|
||||
const startYaw = s.yaw;
|
||||
run(s, 2.5, (st) => {
|
||||
st.ix = -1;
|
||||
st.iz = 0;
|
||||
st.backskate = true;
|
||||
});
|
||||
const yawDrift = Math.abs(wrap(s.yaw - startYaw));
|
||||
ok(yawDrift < 0.45, `facing holds under LT (yaw drift ${yawDrift.toFixed(2)} rad)`);
|
||||
ok(s.bladeSpeed < -1.2, `stick back drives reverse (${s.bladeSpeed.toFixed(2)} m/s)`);
|
||||
ok(s.x < -1.5, `and the body retreats (x ${s.x.toFixed(2)})`);
|
||||
}
|
||||
|
||||
section('LT with stick forward is a crawl, not a rush');
|
||||
{
|
||||
const free = createSkaterState(0, START);
|
||||
run(free, 5, forward);
|
||||
const contain = createSkaterState(1, START);
|
||||
run(contain, 5, (st) => {
|
||||
forward(st);
|
||||
st.backskate = true;
|
||||
});
|
||||
ok(
|
||||
speedOf(free) > speedOf(contain) + 1.2,
|
||||
`contain is much slower than free skate (${speedOf(contain).toFixed(2)} vs ${speedOf(free).toFixed(2)})`,
|
||||
);
|
||||
ok(speedOf(contain) <= SKATE.containForwardSpeed + 0.25, 'under the forward-contain ceiling');
|
||||
ok(contain.bladeSpeed > 0, 'still facing the stick way, not flipped reverse');
|
||||
}
|
||||
|
||||
section('LT reverse and lateral accelerate quickly for gap control');
|
||||
{
|
||||
// Reverse from a standstill under LT should get moving fast.
|
||||
const back = createSkaterState(0, { x: 0, z: 0, yaw: Math.PI / 2 });
|
||||
run(back, 0.45, (st) => {
|
||||
st.ix = -1;
|
||||
st.iz = 0;
|
||||
st.backskate = true;
|
||||
});
|
||||
ok(back.bladeSpeed < -2.5, `quick reverse accel (${back.bladeSpeed.toFixed(2)} m/s in 0.45s)`);
|
||||
ok(Math.abs(back.x) > 0.6, 'and covers ground retreating');
|
||||
|
||||
// Lateral shuffle under LT.
|
||||
const side = createSkaterState(1, { x: 0, z: 0, yaw: Math.PI / 2 });
|
||||
run(side, 0.45, (st) => {
|
||||
st.ix = 0;
|
||||
st.iz = 1; // body right when facing +X
|
||||
st.backskate = true;
|
||||
});
|
||||
ok(Math.abs(side.z) > 0.7, `quick lateral under LT (z ${side.z.toFixed(2)})`);
|
||||
ok(Math.abs(side.x) < Math.abs(side.z), 'mostly sideways relative to facing (+X)');
|
||||
|
||||
// Flip reverse → forward under LT (offense ↔ defense switch).
|
||||
const flip = createSkaterState(2, { x: 0, z: 0, yaw: Math.PI / 2 });
|
||||
run(flip, 0.8, (st) => {
|
||||
st.ix = -1;
|
||||
st.iz = 0;
|
||||
st.backskate = true;
|
||||
});
|
||||
const rev = flip.bladeSpeed;
|
||||
ok(rev < -2, 'was reverse');
|
||||
run(flip, 0.35, (st) => {
|
||||
st.ix = 1;
|
||||
st.iz = 0;
|
||||
st.backskate = true;
|
||||
});
|
||||
ok(flip.bladeSpeed > rev + 2.5, `snaps out of reverse toward forward (${flip.bladeSpeed.toFixed(2)} from ${rev.toFixed(2)})`);
|
||||
}
|
||||
|
||||
section('LT stick neutral bleeds a rush toward neutral');
|
||||
{
|
||||
const s = createSkaterState(0, START);
|
||||
run(s, 5, forward);
|
||||
const entry = speedOf(s);
|
||||
ok(entry > 3.5, 'at cruise');
|
||||
// Hold LT, stick centred — sit in the gap instead of flying.
|
||||
run(s, 1.2, (st) => {
|
||||
st.ix = 0;
|
||||
st.iz = 0;
|
||||
st.backskate = true;
|
||||
});
|
||||
ok(speedOf(s) < entry * 0.55, `bled speed under LT (${speedOf(s).toFixed(2)} of ${entry.toFixed(2)})`);
|
||||
ok(speedOf(s) > 0.15, 'but not a hard snowplow to zero');
|
||||
const yawStill = Math.abs(wrap(s.yaw - Math.PI / 2));
|
||||
ok(yawStill < 0.3, 'and did not spin to face the other way');
|
||||
}
|
||||
|
||||
section('applyIntent accepts backskate');
|
||||
{
|
||||
const s = createSkaterState(0, START);
|
||||
applyIntent(s, { ix: 0, iz: 1, backskate: 1 });
|
||||
ok(s.backskate === true, 'backskate flag is boolean true');
|
||||
applyIntent(s, { ix: 0, iz: 1, backskate: 0 });
|
||||
ok(s.backskate === false, 'and clears');
|
||||
}
|
||||
|
||||
function wrap(a) {
|
||||
let x = a;
|
||||
while (x > Math.PI) x -= Math.PI * 2;
|
||||
while (x <= -Math.PI) x += Math.PI * 2;
|
||||
return x;
|
||||
}
|
||||
|
||||
section('nothing leaves the rink');
|
||||
{
|
||||
// Point skaters at the boards from centre ice and hold it for ten seconds.
|
||||
|
||||
Reference in New Issue
Block a user