slop game oder so
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { distance, length } from '../../app/static/js/logic/math.js';
|
||||
import {
|
||||
combine,
|
||||
encirclePoint,
|
||||
flankPoint,
|
||||
flee,
|
||||
keepDistance,
|
||||
seek,
|
||||
separation,
|
||||
steerTowards,
|
||||
} from '../../app/static/js/logic/steering.js';
|
||||
|
||||
const close = (actual, expected) => {
|
||||
expect(actual.x).toBeCloseTo(expected.x);
|
||||
expect(actual.y).toBeCloseTo(expected.y);
|
||||
};
|
||||
|
||||
describe('seek / flee', () => {
|
||||
it('bewegt sich mit voller Geschwindigkeit zum Ziel bzw. davon weg', () => {
|
||||
close(seek({ x: 0, y: 0 }, { x: 10, y: 0 }, 5), { x: 5, y: 0 });
|
||||
close(flee({ x: 0, y: 0 }, { x: 0, y: 10 }, 3), { x: 0, y: -3 });
|
||||
});
|
||||
|
||||
it('steht still, wenn es bereits am Ziel ist', () => {
|
||||
expect(seek({ x: 4, y: 4 }, { x: 4, y: 4 }, 100)).toEqual({ x: 0, y: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('separation', () => {
|
||||
it('stößt nahe Nachbarn ab und ignoriert entfernte', () => {
|
||||
const self = { x: 0, y: 0 };
|
||||
const push = separation(self, [self, { x: 10, y: 0 }, { x: 500, y: 0 }], 20);
|
||||
expect(push.x).toBeLessThan(0);
|
||||
expect(push.y).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it('trennt exakt übereinanderliegende Gegner ohne NaN', () => {
|
||||
const push = separation({ x: 5, y: 5 }, [{ x: 5, y: 5 }], 20);
|
||||
expect(Number.isFinite(push.x) && Number.isFinite(push.y)).toBe(true);
|
||||
expect(length(push)).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('drückt stärker, je näher der Nachbar ist', () => {
|
||||
const near = separation({ x: 0, y: 0 }, [{ x: 2, y: 0 }], 20);
|
||||
const far = separation({ x: 0, y: 0 }, [{ x: 18, y: 0 }], 20);
|
||||
expect(length(near)).toBeGreaterThan(length(far));
|
||||
});
|
||||
});
|
||||
|
||||
describe('keepDistance', () => {
|
||||
const band = { min: 200, max: 300 };
|
||||
const target = { x: 0, y: 0 };
|
||||
|
||||
it('nähert sich an, wenn es zu weit weg ist', () => {
|
||||
const v = keepDistance({ x: 500, y: 0 }, target, band, 10, 1);
|
||||
close(v, { x: -10, y: 0 });
|
||||
});
|
||||
|
||||
it('weicht zurück, wenn es zu nah ist', () => {
|
||||
const v = keepDistance({ x: 100, y: 0 }, target, band, 10, 1);
|
||||
close(v, { x: 10, y: 0 });
|
||||
});
|
||||
|
||||
it('weicht im Wohlfühlbereich seitlich aus (senkrecht zur Linie)', () => {
|
||||
const cw = keepDistance({ x: 250, y: 0 }, target, band, 10, 1, 0.5);
|
||||
const ccw = keepDistance({ x: 250, y: 0 }, target, band, 10, -1, 0.5);
|
||||
expect(cw.x).toBeCloseTo(0);
|
||||
expect(Math.abs(cw.y)).toBeCloseTo(5);
|
||||
expect(ccw.y).toBeCloseTo(-cw.y);
|
||||
});
|
||||
});
|
||||
|
||||
describe('flankPoint / encirclePoint', () => {
|
||||
it('liegt im gewünschten Abstand seitlich versetzt', () => {
|
||||
const target = { x: 0, y: 0 };
|
||||
const enemy = { x: 100, y: 0 };
|
||||
const p = flankPoint(target, enemy, Math.PI / 2, 50);
|
||||
expect(distance(p, target)).toBeCloseTo(50);
|
||||
close(p, { x: 0, y: 50 });
|
||||
const other = flankPoint(target, enemy, -Math.PI / 2, 50);
|
||||
close(other, { x: 0, y: -50 });
|
||||
});
|
||||
|
||||
it('verteilt Umzingelungsplätze auf einem Kreis', () => {
|
||||
const target = { x: 10, y: 10 };
|
||||
close(encirclePoint(target, 0, 100), { x: 110, y: 10 });
|
||||
close(encirclePoint(target, Math.PI, 100), { x: -90, y: 10 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('combine / steerTowards', () => {
|
||||
it('gewichtet Anteile und begrenzt auf die Höchstgeschwindigkeit', () => {
|
||||
const v = combine(
|
||||
[
|
||||
{ vector: { x: 10, y: 0 }, weight: 1 },
|
||||
{ vector: { x: 0, y: 10 }, weight: 2 },
|
||||
],
|
||||
15,
|
||||
);
|
||||
expect(length(v)).toBeCloseTo(15);
|
||||
expect(v.y).toBeGreaterThan(v.x);
|
||||
});
|
||||
|
||||
it('nähert sich der Wunschgeschwindigkeit schrittweise an', () => {
|
||||
close(steerTowards({ x: 0, y: 0 }, { x: 10, y: -10 }, 0.25), { x: 2.5, y: -2.5 });
|
||||
close(steerTowards({ x: 3, y: 3 }, { x: 10, y: -10 }, 1), { x: 10, y: -10 });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user