More fun
This commit is contained in:
parent
a1fb6755c7
commit
fc9df09ee1
1 changed files with 2012 additions and 252 deletions
80
shared/src/physics/planet-sdf.ts
Normal file
80
shared/src/physics/planet-sdf.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { clamp, clamp01 } from '../helper/clamp';
|
||||
import { settings } from '../settings';
|
||||
|
||||
// Rotate a world point into the planet's own frame: R(-rotation) about the
|
||||
// centre, matching the shader's localTarget = center + R(rotation)*(target-center).
|
||||
// cos/sin are passed in so the server can keep memoising them per angle.
|
||||
export const toPlanetLocalFrame = (
|
||||
target: vec2,
|
||||
center: vec2,
|
||||
cos: number,
|
||||
sin: number,
|
||||
): vec2 => {
|
||||
const dx = target[0] - center[0];
|
||||
const dy = target[1] - center[1];
|
||||
return vec2.fromValues(
|
||||
center[0] + cos * dx - sin * dy,
|
||||
center[1] + sin * dx + cos * dy,
|
||||
);
|
||||
};
|
||||
|
||||
// Signed distance to the (smooth, noise-free) planet polygon, evaluated in the
|
||||
// planet's rotating frame. Extracted verbatim from PlanetPhysical.distance so
|
||||
// the client collides against the exact same outline the server does. Indexed
|
||||
// vector access keeps it independent of the .x/.y prototype plugin.
|
||||
export const planetDistance = (
|
||||
target: vec2,
|
||||
vertices: Array<vec2>,
|
||||
center: vec2,
|
||||
cos: number,
|
||||
sin: number,
|
||||
): number => {
|
||||
const local = toPlanetLocalFrame(target, center, cos, sin);
|
||||
|
||||
const startEnd = vertices[0];
|
||||
let vb = startEnd;
|
||||
|
||||
let d = vec2.dist(local, vb);
|
||||
let sign = 1;
|
||||
|
||||
for (let i = 1; i <= vertices.length; i++) {
|
||||
const va = vb;
|
||||
vb = i === vertices.length ? startEnd : vertices[i];
|
||||
const targetFromDelta = vec2.subtract(vec2.create(), local, va);
|
||||
const toFromDelta = vec2.subtract(vec2.create(), vb, va);
|
||||
const h = clamp01(
|
||||
vec2.dot(targetFromDelta, toFromDelta) / vec2.squaredLength(toFromDelta),
|
||||
);
|
||||
|
||||
const ds = vec2.fromValues(
|
||||
vec2.dist(targetFromDelta, vec2.scale(vec2.create(), toFromDelta, h)),
|
||||
toFromDelta[0] * targetFromDelta[1] - toFromDelta[1] * targetFromDelta[0],
|
||||
);
|
||||
|
||||
if (
|
||||
(local[1] >= va[1] && local[1] < vb[1] && ds[1] > 0) ||
|
||||
(local[1] < va[1] && local[1] >= vb[1] && ds[1] <= 0)
|
||||
) {
|
||||
sign *= -1;
|
||||
}
|
||||
|
||||
d = Math.min(d, ds[0]);
|
||||
}
|
||||
|
||||
return sign * d;
|
||||
};
|
||||
|
||||
// Gravity a planet exerts at a world position. Verbatim from
|
||||
// PlanetPhysical.getForce.
|
||||
export const planetGravity = (center: vec2, radius: number, position: vec2): vec2 => {
|
||||
const diff = vec2.subtract(vec2.create(), center, position);
|
||||
const dist = Math.max(settings.minGravityDistance, vec2.length(diff) - radius);
|
||||
vec2.normalize(diff, diff);
|
||||
const scale = clamp(
|
||||
settings.maxGravityQ * ((settings.maxGravityDistance / dist) ** 1.5 - 1),
|
||||
0,
|
||||
settings.maxGravityStrength,
|
||||
);
|
||||
return vec2.scale(diff, diff, scale);
|
||||
};
|
||||
Loading…
Reference in a new issue