Make physics more fun
This commit is contained in:
parent
155e360c8e
commit
89fafeafd3
6 changed files with 509 additions and 332 deletions
24
backend/src/physics/functions/apply-spring-force.ts
Normal file
24
backend/src/physics/functions/apply-spring-force.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Circle } from 'shared';
|
||||
import { CirclePhysical } from '../../objects/circle-physical';
|
||||
|
||||
export const applySpringForce = (
|
||||
a: CirclePhysical | Circle,
|
||||
b: CirclePhysical | Circle,
|
||||
distance: number,
|
||||
strength: number,
|
||||
deltaTimeInSeconds: number,
|
||||
) => {
|
||||
const length = vec2.dist(a.center, b.center) - distance;
|
||||
|
||||
const abDirection = vec2.subtract(vec2.create(), b.center, a.center);
|
||||
vec2.normalize(abDirection, abDirection);
|
||||
const force = vec2.scale(abDirection, abDirection, strength * length);
|
||||
if (a instanceof CirclePhysical) {
|
||||
a.applyForce(force, deltaTimeInSeconds);
|
||||
}
|
||||
if (b instanceof CirclePhysical) {
|
||||
vec2.scale(force, force, -1);
|
||||
b.applyForce(force, deltaTimeInSeconds);
|
||||
}
|
||||
};
|
||||
7
backend/src/physics/functions/evaluate-sdf.ts
Normal file
7
backend/src/physics/functions/evaluate-sdf.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { PhysicalBase } from '../physicals/physical-base';
|
||||
|
||||
export const evaluateSdf = (target: vec2, objects: Array<PhysicalBase>) =>
|
||||
objects
|
||||
.filter((i) => i.canCollide)
|
||||
.reduce((min, i) => (min = Math.min(min, i.distance(target))), 1000);
|
||||
9
backend/src/physics/functions/force-at-position.ts
Normal file
9
backend/src/physics/functions/force-at-position.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Physical } from '../physicals/physical';
|
||||
|
||||
export const forceAtPosition = (position: vec2, objects: Array<Physical>) =>
|
||||
objects.reduce(
|
||||
(sum: vec2, o: Physical) =>
|
||||
!o.canMove ? vec2.add(sum, sum, o.getForce(position)) : sum,
|
||||
vec2.create(),
|
||||
);
|
||||
10
backend/src/physics/functions/get-bounding-box-of-circle.ts
Normal file
10
backend/src/physics/functions/get-bounding-box-of-circle.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Circle } from 'shared';
|
||||
import { BoundingBoxBase } from '../bounding-boxes/bounding-box-base';
|
||||
|
||||
export const getBoundingBoxOfCircle = (circle: Circle): BoundingBoxBase =>
|
||||
new BoundingBoxBase(
|
||||
circle.center.x - circle.radius,
|
||||
circle.center.x + circle.radius,
|
||||
circle.center.y - circle.radius,
|
||||
circle.center.y + circle.radius,
|
||||
);
|
||||
8
backend/src/physics/functions/is-circle-intersecting.ts
Normal file
8
backend/src/physics/functions/is-circle-intersecting.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { Circle } from 'shared';
|
||||
import { evaluateSdf } from './evaluate-sdf';
|
||||
import { PhysicalBase } from '../physicals/physical-base';
|
||||
|
||||
export const isCircleIntersecting = (
|
||||
circle: Circle,
|
||||
intersectors: Array<PhysicalBase>,
|
||||
): boolean => evaluateSdf(circle.center, intersectors) < circle.radius;
|
||||
70
backend/src/physics/functions/move-circle.ts
Normal file
70
backend/src/physics/functions/move-circle.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Circle, GameObject, rotate90Deg } from 'shared';
|
||||
import { CirclePhysical } from '../../objects/circle-physical';
|
||||
import { reactsToCollision } from '../physicals/reacts-to-collision';
|
||||
import { evaluateSdf } from './evaluate-sdf';
|
||||
import { Physical } from '../physicals/physical';
|
||||
|
||||
export const moveCircle = (
|
||||
circle: CirclePhysical,
|
||||
delta: vec2,
|
||||
possibleIntersectors: Array<Physical>,
|
||||
): {
|
||||
realDelta: vec2;
|
||||
hitSurface: boolean;
|
||||
normal?: vec2;
|
||||
tangent?: vec2;
|
||||
hitObject?: GameObject;
|
||||
} => {
|
||||
const nextCircle = new Circle(vec2.clone(circle.center), circle.radius);
|
||||
vec2.add(nextCircle.center, nextCircle.center, delta);
|
||||
|
||||
possibleIntersectors = possibleIntersectors.filter(
|
||||
(b) => b.gameObject !== circle.gameObject && b.canCollide,
|
||||
);
|
||||
|
||||
const sdfAtCenter = evaluateSdf(nextCircle.center, possibleIntersectors);
|
||||
|
||||
if (sdfAtCenter > nextCircle.radius) {
|
||||
circle.center = vec2.add(circle.center, circle.center, delta);
|
||||
|
||||
return {
|
||||
realDelta: delta,
|
||||
hitSurface: false,
|
||||
};
|
||||
}
|
||||
|
||||
const intersecting = possibleIntersectors.find(
|
||||
(i) => i.distance(nextCircle.center) <= circle.radius,
|
||||
)!;
|
||||
|
||||
if (reactsToCollision(intersecting)) {
|
||||
intersecting.onCollision(circle.gameObject);
|
||||
}
|
||||
|
||||
if (reactsToCollision(circle)) {
|
||||
circle.onCollision(intersecting.gameObject);
|
||||
}
|
||||
|
||||
const dx =
|
||||
evaluateSdf(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0.01, 0)), [
|
||||
intersecting,
|
||||
]) - sdfAtCenter;
|
||||
const dy =
|
||||
evaluateSdf(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0, 0.01)), [
|
||||
intersecting,
|
||||
]) - sdfAtCenter;
|
||||
const normal = vec2.fromValues(dx, dy);
|
||||
vec2.normalize(normal, normal);
|
||||
const rotatedNormal = rotate90Deg(normal);
|
||||
return {
|
||||
realDelta: delta,
|
||||
hitSurface: true,
|
||||
normal,
|
||||
hitObject: intersecting?.gameObject,
|
||||
tangent:
|
||||
vec2.dot(rotatedNormal, delta) < 0
|
||||
? vec2.scale(rotatedNormal, rotatedNormal, -1)
|
||||
: rotatedNormal,
|
||||
};
|
||||
};
|
||||
Loading…
Reference in a new issue