Make physics more fun
This commit is contained in:
parent
155e360c8e
commit
89fafeafd3
41 changed files with 511 additions and 334 deletions
131
backend/src/objects/planet-physical.ts
Normal file
131
backend/src/objects/planet-physical.ts
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
|
||||
import {
|
||||
clamp,
|
||||
clamp01,
|
||||
id,
|
||||
rotate90Deg,
|
||||
rotateMinus90Deg,
|
||||
serializesTo,
|
||||
settings,
|
||||
PlanetBase,
|
||||
} from 'shared';
|
||||
|
||||
import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box';
|
||||
import { StaticPhysical } from '../physics/physicals/static-physical';
|
||||
|
||||
@serializesTo(PlanetBase)
|
||||
export class PlanetPhysical extends PlanetBase implements StaticPhysical {
|
||||
public readonly canCollide = true;
|
||||
public readonly canMove = false;
|
||||
private center: vec2;
|
||||
|
||||
private _boundingBox?: ImmutableBoundingBox;
|
||||
|
||||
constructor(vertices: Array<vec2>) {
|
||||
super(id(), vertices);
|
||||
this.center = vertices.reduce((sum, v) => vec2.add(sum, sum, v), vec2.create());
|
||||
vec2.scale(this.center, this.center, 1 / vertices.length);
|
||||
}
|
||||
|
||||
public distance(target: vec2): number {
|
||||
const startEnd = this.vertices[0];
|
||||
let vb = startEnd;
|
||||
|
||||
let d = vec2.squaredDistance(target, vb);
|
||||
let sign = 1;
|
||||
|
||||
for (let i = 1; i <= this.vertices.length; i++) {
|
||||
const va = vb;
|
||||
vb = i === this.vertices.length ? startEnd : this.vertices[i];
|
||||
const targetFromDelta = vec2.subtract(vec2.create(), target, 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.x * targetFromDelta.y - toFromDelta.y * targetFromDelta.x,
|
||||
);
|
||||
|
||||
if (
|
||||
(target.y >= va.y && target.y < vb.y && ds.y > 0) ||
|
||||
(target.y < va.y && target.y >= vb.y && ds.y <= 0)
|
||||
) {
|
||||
sign *= -1;
|
||||
}
|
||||
|
||||
d = Math.min(d, ds.x);
|
||||
}
|
||||
|
||||
return sign * d;
|
||||
}
|
||||
|
||||
public get boundingBox(): ImmutableBoundingBox {
|
||||
if (!this._boundingBox) {
|
||||
const { xMin, xMax, yMin, yMax } = this.vertices.reduce(
|
||||
(extremities, vertex) => ({
|
||||
xMin: Math.min(extremities.xMin, vertex.x),
|
||||
xMax: Math.max(extremities.xMax, vertex.x),
|
||||
yMin: Math.min(extremities.yMin, vertex.y),
|
||||
yMax: Math.max(extremities.yMax, vertex.y),
|
||||
}),
|
||||
{
|
||||
xMin: Infinity,
|
||||
xMax: -Infinity,
|
||||
yMin: Infinity,
|
||||
yMax: -Infinity,
|
||||
},
|
||||
);
|
||||
|
||||
this._boundingBox = new ImmutableBoundingBox(xMin, xMax, yMin, yMax);
|
||||
}
|
||||
|
||||
return this._boundingBox;
|
||||
}
|
||||
|
||||
public getForce(position: vec2): vec2 {
|
||||
const height = this.distance(position);
|
||||
|
||||
let closestIndex = 0;
|
||||
this.vertices.forEach((v, i) => {
|
||||
if (
|
||||
vec2.distance(position, v) < vec2.distance(position, this.vertices[closestIndex])
|
||||
) {
|
||||
closestIndex = i;
|
||||
}
|
||||
});
|
||||
|
||||
const afterClosest = this.vertices[(closestIndex + 1) % this.vertices.length];
|
||||
const closest = this.vertices[closestIndex];
|
||||
const beforeClosest = this.vertices[
|
||||
(closestIndex - 1 + this.vertices.length) % this.vertices.length
|
||||
];
|
||||
|
||||
const diff = vec2.subtract(vec2.create(), position, closest);
|
||||
const edge1 = vec2.subtract(vec2.create(), afterClosest, closest);
|
||||
const edge2 = vec2.subtract(vec2.create(), closest, beforeClosest);
|
||||
const normalizedDiff = vec2.normalize(vec2.create(), diff);
|
||||
|
||||
const currentEdge =
|
||||
vec2.dot(vec2.normalize(vec2.create(), rotate90Deg(edge1)), normalizedDiff) >
|
||||
vec2.dot(vec2.normalize(vec2.create(), rotate90Deg(edge2)), normalizedDiff)
|
||||
? edge1
|
||||
: edge2;
|
||||
|
||||
vec2.normalize(currentEdge, currentEdge);
|
||||
const normal = rotateMinus90Deg(currentEdge);
|
||||
|
||||
const scale = clamp(
|
||||
settings.maxGravityQ * ((settings.maxGravityDistance / height) ** 3 - 1),
|
||||
0,
|
||||
settings.maxGravityStrength,
|
||||
);
|
||||
return vec2.scale(normal, normal, scale);
|
||||
}
|
||||
|
||||
public get gameObject(): this {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue