quill/val Public Public: anyone can read this; nobody can change it.

forked from benjivers/val

workbenchthis machine
Files 53c9cd79f21c24c95995672b7a3113c152df085c
101 lines · 4.0 KB · ~1.2k tok Raw History
1
/**
2
 * Step and slide, on a grid written out here rather than the real map, so
3
 * the cases are the ones being argued about: a wall, an inner corner, and a
4
 * body already pressed against both.
5
 */
6
7
import { expect, test } from "bun:test";
8
import { BODY_R, circleBlocked, moveSpeed, RUN, slideCircle } from "./glide.ts";
9
10
const TILE = 80;
11
// A room with solid walls, open from (1,1) to (3,3).
12
const room = ["#####", "#...#", "#...#", "#...#", "#####"];
13
const solid = (col: number, row: number): boolean =>
14
  col < 0 || row < 0 || row >= room.length || col >= room[0]!.length || room[row]![col] === "#";
15
16
const slide = (x: number, y: number, dx: number, dy: number) =>
17
  slideCircle(x, y, dx, dy, BODY_R, solid, TILE);
18
19
test("an unobstructed step is the step it was asked for", () => {
20
  const to = slide(200, 200, 12, -7);
21
  expect(to.x).toBeCloseTo(212, 9);
22
  expect(to.y).toBeCloseTo(193, 9);
23
  expect(slide(200, 200, 0, 0)).toEqual({ x: 200, y: 200 });
24
});
25
26
test("a wall keeps the motion along it: running into it still slides", () => {
27
  // Hard against the right-hand wall (x = 320 - 16), running down and right.
28
  const to = slide(300, 160, 10, 10);
29
  expect(to.y).toBeCloseTo(170, 6); // the free axis goes through whole
30
  expect(to.x).toBeLessThanOrEqual(304);
31
  expect(to.x).toBeGreaterThan(300); // and the blocked one creeps up to the wall
32
  expect(circleBlocked(to.x, to.y, BODY_R, solid, TILE)).toBe(false);
33
});
34
35
test("a corner is one place, whichever axis is resolved first", () => {
36
  // The bottom-right inner corner of the room: both walls at once.
37
  const diagonal = slide(280, 280, 40, 40);
38
  // Getting there one axis at a time, either order, lands in the same place.
39
  const alongX = slide(280, 280, 40, 0);
40
  const xThenY = slide(alongX.x, alongX.y, 0, 40);
41
  const alongY = slide(280, 280, 0, 40);
42
  const yThenX = slide(alongY.x, alongY.y, 40, 0);
43
  expect(xThenY.x).toBeCloseTo(diagonal.x, 3);
44
  expect(xThenY.y).toBeCloseTo(diagonal.y, 3);
45
  expect(yThenX.x).toBeCloseTo(diagonal.x, 3);
46
  expect(yThenX.y).toBeCloseTo(diagonal.y, 3);
47
  // And it is the corner: a body's radius from both walls, inside them.
48
  expect(diagonal.x).toBeGreaterThan(320 - BODY_R - 1.5);
49
  expect(diagonal.x).toBeLessThanOrEqual(320 - BODY_R);
50
  expect(diagonal.y).toBeGreaterThan(320 - BODY_R - 1.5);
51
  expect(diagonal.y).toBeLessThanOrEqual(320 - BODY_R);
52
});
53
54
test("a body held against a wall stops moving instead of alternating", () => {
55
  // This is the skip: the old resolution snapped to the tile edge on the
56
  // blocked tick and moved freely on the next, so a player leaning on a
57
  // wall produced a position that changed every tick with no input change.
58
  let at = { x: 300, y: 200 };
59
  const seen: number[] = [];
60
  for (let i = 0; i < 12; i++) {
61
    at = slide(at.x, at.y, 8.3, 0);
62
    seen.push(at.x);
63
  }
64
  const settled = seen.slice(4);
65
  expect(Math.max(...settled) - Math.min(...settled)).toBeLessThan(0.05);
66
  expect(Math.max(...settled)).toBeLessThanOrEqual(320 - BODY_R);
67
});
68
69
test("a corner is a fixed point: pressed into it, nothing moves at all", () => {
70
  let at = { x: 300, y: 300 };
71
  for (let i = 0; i < 6; i++) at = slide(at.x, at.y, 8.3, 8.3);
72
  const settled = slide(at.x, at.y, 8.3, 8.3);
73
  expect(settled.x).toBeCloseTo(at.x, 6);
74
  expect(settled.y).toBeCloseTo(at.y, 6);
75
});
76
77
test("a step never ends inside a wall, from anywhere in the room", () => {
78
  for (let x = 96; x < 320 - 16; x += 7)
79
    for (let y = 96; y < 320 - 16; y += 7)
80
      for (const [dx, dy] of [
81
        [30, 0],
82
        [-30, 0],
83
        [0, 30],
84
        [0, -30],
85
        [24, 24],
86
        [-24, 24],
87
        [24, -24],
88
        [-24, -24],
89
      ] as const) {
90
        const to = slide(x, y, dx, dy);
91
        expect(circleBlocked(to.x, to.y, BODY_R, solid, TILE)).toBe(false);
92
      }
93
});
94
95
test("speed is the one table both sides read", () => {
96
  expect(moveSpeed({})).toBe(RUN);
97
  expect(moveSpeed({ haste: true })).toBeCloseTo(RUN * 1.35, 9);
98
  expect(moveSpeed({ slow: true })).toBeCloseTo(RUN * 0.55, 9);
99
  expect(moveSpeed({ heavy: true })).toBeCloseTo(RUN * 0.86, 9);
100
  expect(moveSpeed({ stopped: true, haste: true })).toBe(0);
101
});
↑↓ navigate ↵ open esc close
↑↓ navigate ↵ open esc close

Keyboard shortcuts