summaryrefslogtreecommitdiff
path: root/client/lib/systems
diff options
context:
space:
mode:
Diffstat (limited to 'client/lib/systems')
-rw-r--r--client/lib/systems/Collision.ts214
-rw-r--r--client/lib/systems/FacingDirection.ts39
-rw-r--r--client/lib/systems/Input.ts86
-rw-r--r--client/lib/systems/Physics.ts94
-rw-r--r--client/lib/systems/Render.ts41
-rw-r--r--client/lib/systems/System.ts15
-rw-r--r--client/lib/systems/WallBounds.ts35
-rw-r--r--client/lib/systems/index.ts8
-rw-r--r--client/lib/systems/names.ts8
9 files changed, 0 insertions, 540 deletions
diff --git a/client/lib/systems/Collision.ts b/client/lib/systems/Collision.ts
deleted file mode 100644
index 16ad8c6..0000000
--- a/client/lib/systems/Collision.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-import { SystemNames, System } from ".";
-import {
- Mass,
- BoundingBox,
- ComponentNames,
- Jump,
- Velocity,
- Moment,
-} from "../components";
-import { PhysicsConstants } from "../config";
-import { Entity } from "../entities";
-import type { Dimension2D } from "../interfaces";
-import { QuadTree } from "../structures";
-
-export class Collision extends System {
- private static readonly COLLIDABLE_COMPONENTS = [
- ComponentNames.Collide,
- ComponentNames.TopCollidable,
- ];
- private static readonly QUADTREE_MAX_LEVELS = 10;
- private static readonly QUADTREE_SPLIT_THRESHOLD = 10;
-
- private quadTree: QuadTree;
-
- constructor(screenDimensions: Dimension2D) {
- super(SystemNames.Collision);
-
- this.quadTree = new QuadTree(
- { x: 0, y: 0 },
- screenDimensions,
- Collision.QUADTREE_MAX_LEVELS,
- Collision.QUADTREE_SPLIT_THRESHOLD
- );
- }
-
- public update(
- dt: number,
- entityMap: Map<number, Entity>,
- entityComponents: Map<string, Set<number>>
- ) {
- this.quadTree.clear();
-
- const entitiesToAddToQuadtree: Entity[] = [];
- Collision.COLLIDABLE_COMPONENTS.map((componentName) =>
- entityComponents.get(componentName)
- ).forEach((entityIds: Set<number>) =>
- entityIds.forEach((id) => {
- const entity = entityMap.get(id);
- if (!entity.hasComponent(ComponentNames.BoundingBox)) {
- return;
- }
- entitiesToAddToQuadtree.push(entity);
- })
- );
-
- entitiesToAddToQuadtree.forEach((entity) => {
- const boundingBox = entity.getComponent<BoundingBox>(
- ComponentNames.BoundingBox
- );
-
- this.quadTree.insert(
- entity.id,
- boundingBox.dimension,
- boundingBox.center
- );
- });
-
- const collidingEntities = this.getCollidingEntities(
- entitiesToAddToQuadtree,
- entityMap
- );
- collidingEntities.forEach(([entityAId, entityBId]) => {
- const [entityA, entityB] = [entityAId, entityBId].map((id) =>
- entityMap.get(id)
- );
- this.performCollision(entityA, entityB);
- });
- }
-
- private performCollision(entityA: Entity, entityB: Entity) {
- const [entityABoundingBox, entityBBoundingBox] = [entityA, entityB].map(
- (entity) => entity.getComponent<BoundingBox>(ComponentNames.BoundingBox)
- );
-
- let velocity: Velocity;
- if (entityA.hasComponent(ComponentNames.Velocity)) {
- velocity = entityA.getComponent<Velocity>(ComponentNames.Velocity);
- }
-
- if (
- entityA.hasComponent(ComponentNames.Collide) &&
- entityB.hasComponent(ComponentNames.TopCollidable) &&
- entityABoundingBox.center.y <= entityBBoundingBox.center.y &&
- velocity &&
- velocity.dCartesian.dy >= 0 // don't apply floor logic when coming through the bottom
- ) {
- if (entityBBoundingBox.rotation != 0) {
- throw new Error(
- `entity with id ${entityB.id} has TopCollidable component and a non-zero rotation. that is not (yet) supported.`
- );
- }
-
- // remove previous velocity in the y axis
- velocity.dCartesian.dy = 0;
-
- // apply normal force
- if (entityA.hasComponent(ComponentNames.Gravity)) {
- const mass = entityA.getComponent<Mass>(ComponentNames.Mass).mass;
- const F_n = -mass * PhysicsConstants.GRAVITY;
-
- entityA.getComponent<Forces>(ComponentNames.Forces).forces.push({
- fCartesian: { fy: F_n },
- });
- }
-
- // reset the entities' jump
- if (entityA.hasComponent(ComponentNames.Jump)) {
- entityA.getComponent<Jump>(ComponentNames.Jump).canJump = true;
- }
-
- entityABoundingBox.center.y =
- entityBBoundingBox.center.y -
- entityBBoundingBox.dimension.height / 2 -
- this.getDyToPushOutOfFloor(entityABoundingBox, entityBBoundingBox);
- }
- }
-
- private getCollidingEntities(
- collidableEntities: Entity[],
- entityMap: Map<number, Entity>
- ): [number, number][] {
- const collidingEntityIds: [number, number] = [];
-
- for (const entity of collidableEntities) {
- const boundingBox = entity.getComponent<BoundingBox>(
- ComponentNames.BoundingBox
- );
-
- this.quadTree
- .getNeighborIds({
- id: entity.id,
- dimension: boundingBox.dimension,
- center: boundingBox.center,
- })
- .filter((neighborId) => neighborId != entity.id)
- .forEach((neighborId) => {
- const neighborBoundingBox = entityMap
- .get(neighborId)
- .getComponent<BoundingBox>(ComponentNames.BoundingBox);
-
- if (boundingBox.isCollidingWith(neighborBoundingBox)) {
- collidingEntityIds.push([entity.id, neighborId]);
- }
- });
- }
-
- return collidingEntityIds;
- }
-
- private getDyToPushOutOfFloor(
- entityBoundingBox: BoundingBox,
- floorBoundingBox: BoundingBox
- ): number {
- // ramblings: https://excalidraw.com/#json=z-xD86Za4a3duZuV2Oky0,KaGe-5iHJu1Si8inEo4GLQ
- const {
- rotation,
- center: { x, y },
- dimension: { width, height },
- } = entityBoundingBox;
-
- let rads = rotation * (Math.PI / 180);
- if (rads >= Math.PI) {
- rads -= Math.PI; // we have symmetry so we can skip two cases
- }
-
- let boundedCollisionX = 0; // bounded x on the surface from width
- let clippedX = 0; // x coordinate of the vertex below the surface
- let outScribedRectangleHeight, dy, dx;
-
- if (rads <= Math.PI / 2) {
- dx = (width * Math.cos(rads) - height * Math.sin(rads)) / 2;
- outScribedRectangleHeight =
- width * Math.sin(rads) + height * Math.cos(rads);
- } else if (rads <= Math.PI) {
- rads -= Math.PI / 2;
- dx = (height * Math.cos(rads) - width * Math.sin(rads)) / 2;
- outScribedRectangleHeight =
- width * Math.cos(rads) + height * Math.sin(rads);
- }
-
- if (x >= floorBoundingBox.center.x) {
- clippedX = x + dx;
- boundedCollisionX = Math.min(
- floorBoundingBox.center.x + floorBoundingBox.dimension.width / 2,
- clippedX
- );
- return (
- outScribedRectangleHeight / 2 -
- Math.max((clippedX - boundedCollisionX) * Math.tan(rads), 0)
- );
- }
-
- clippedX = x - dx;
- boundedCollisionX = Math.max(
- floorBoundingBox.center.x - floorBoundingBox.dimension.width / 2,
- clippedX
- );
-
- return (
- outScribedRectangleHeight / 2 -
- Math.max((boundedCollisionX - clippedX) * Math.tan(rads), 0)
- );
- }
-}
diff --git a/client/lib/systems/FacingDirection.ts b/client/lib/systems/FacingDirection.ts
deleted file mode 100644
index fbb4c7c..0000000
--- a/client/lib/systems/FacingDirection.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import {
- ComponentNames,
- Velocity,
- FacingDirection as FacingDirectionComponent,
-} from "../components";
-import type { Entity } from "../entities";
-import { System, SystemNames } from "./";
-
-export class FacingDirection extends System {
- constructor() {
- super(SystemNames.FacingDirection);
- }
-
- public update(
- _dt: number,
- entityMap: Map<number, Entity>,
- componentEntities: Map<string, Set<number>>
- ) {
- componentEntities
- .get(ComponentNames.FacingDirection)
- ?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
- if (!entity.hasComponent(ComponentNames.Velocity)) {
- return;
- }
-
- const velocity = entity.getComponent<Velocity>(ComponentNames.Velocity);
- const facingDirection = entity.getComponent<FacingDirectionComponent>(
- ComponentNames.FacingDirection
- );
-
- if (velocity.dCartesian.dx > 0) {
- entity.addComponent(facingDirection.facingRightSprite);
- } else if (velocity.dCartesian.dx < 0) {
- entity.addComponent(facingDirection.facingLeftSprite);
- }
- });
- }
-}
diff --git a/client/lib/systems/Input.ts b/client/lib/systems/Input.ts
deleted file mode 100644
index 92932dd..0000000
--- a/client/lib/systems/Input.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import {
- Jump,
- Forces,
- Acceleration,
- ComponentNames,
- Velocity,
- Mass,
-} from "../components";
-import { KeyConstants, PhysicsConstants } from "../config";
-import type { Entity } from "../entities";
-import { Action } from "../interfaces";
-import { System, SystemNames } from "./";
-
-export class Input extends System {
- private keys: Set<string>;
- private actionTimeStamps: Map<Action, number>;
-
- constructor() {
- super(SystemNames.Input);
-
- this.keys = new Set<number>();
- this.actionTimeStamps = new Map<Action, number>();
- }
-
- public keyPressed(key: string) {
- this.keys.add(key);
- }
-
- public keyReleased(key: string) {
- this.keys.delete(key);
- }
-
- private hasSomeKey(keys: string[]): boolean {
- return keys.some((key) => this.keys.has(key));
- }
-
- public update(
- dt: number,
- entityMap: Map<number, Entity>,
- componentEntities: Map<string, Set<number>>
- ) {
- componentEntities.get(ComponentNames.Control)?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
- if (!entity.hasComponent(ComponentNames.Velocity)) {
- return;
- }
-
- const velocity = entity.getComponent<Velocity>(ComponentNames.Velocity);
-
- if (this.hasSomeKey(KeyConstants.ActionKeys.get(Action.MOVE_RIGHT))) {
- velocity.dCartesian.dx = PhysicsConstants.PLAYER_MOVE_VEL;
- } else if (
- this.hasSomeKey(KeyConstants.ActionKeys.get(Action.MOVE_LEFT))
- ) {
- velocity.dCartesian.dx = -PhysicsConstants.PLAYER_MOVE_VEL;
- } else {
- velocity.dCartesian.dx = 0;
- }
- });
-
- componentEntities.get(ComponentNames.Jump)?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
- const jump = entity.getComponent<Jump>(ComponentNames.Jump);
- const velocity = entity.getComponent<Velocity>(ComponentNames.Velocity);
-
- if (this.hasSomeKey(KeyConstants.ActionKeys.get(Action.JUMP))) {
- if (jump.canJump) {
- this.actionTimeStamps.set(Action.JUMP, performance.now());
-
- velocity.dCartesian.dy = PhysicsConstants.PLAYER_JUMP_INITIAL_VEL;
- jump.canJump = false;
- }
-
- if (
- performance.now() - this.actionTimeStamps.get(Action.JUMP) <
- PhysicsConstants.MAX_JUMP_TIME_MS
- ) {
- const mass = entity.getComponent<Mass>(ComponentNames.Mass).mass;
- entity.getComponent<Forces>(ComponentNames.Forces)?.forces.push({
- fCartesian: { fy: mass * PhysicsConstants.PLAYER_JUMP_ACC },
- });
- }
- }
- });
- }
-}
diff --git a/client/lib/systems/Physics.ts b/client/lib/systems/Physics.ts
deleted file mode 100644
index 319ae29..0000000
--- a/client/lib/systems/Physics.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { System, SystemNames } from ".";
-import {
- Acceleration,
- BoundingBox,
- ComponentNames,
- Forces,
- Gravity,
- Velocity,
- Mass,
- Jump,
-} from "../components";
-import { PhysicsConstants } from "../config";
-import type { Entity } from "../entities";
-import type { Force2D } from "../interfaces";
-
-export class Physics extends System {
- constructor() {
- super(SystemNames.Physics);
- }
-
- public update(
- dt: number,
- entityMap: Map<number, Entity>,
- componentEntities: Map<string, Set<number>>
- ): void {
- componentEntities.get(ComponentNames.Forces)?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
-
- const mass = entity.getComponent<Mass>(ComponentNames.Mass).mass;
- const forces = entity.getComponent<Forces>(ComponentNames.Forces).forces;
- const velocity = entity.getComponent<Velocity>(ComponentNames.Velocity);
- const inertia = entity.getComponent<Moment>(
- ComponentNames.Moment
- ).inertia;
-
- // F_g = mg, applied only until terminal velocity is reached
- if (entity.hasComponent(ComponentNames.Gravity)) {
- const gravity = entity.getComponent<Gravity>(ComponentNames.Gravity);
- if (velocity.dCartesian.dy <= gravity.terminalVelocity) {
- forces.push({
- fCartesian: {
- fy: mass * PhysicsConstants.GRAVITY,
- },
- });
- }
- }
-
- // ma = Σ(F), Iα = Σ(T)
- const sumOfForces = forces.reduce(
- (accum: Force2D, { fCartesian, torque }: Force2D) => ({
- fCartesian: {
- fx: accum.fCartesian.fx + (fCartesian?.fx ?? 0),
- fy: accum.fCartesian.fy + (fCartesian?.fy ?? 0),
- },
- torque: accum.torque + (torque ?? 0),
- }),
- { fCartesian: { fx: 0, fy: 0 }, torque: 0 }
- );
-
- // integrate accelerations
- const [ddy, ddx] = [
- sumOfForces.fCartesian.fy,
- sumOfForces.fCartesian.fx,
- ].map((x) => x / mass);
- velocity.dCartesian.dx += ddx * dt;
- velocity.dCartesian.dy += ddy * dt;
- velocity.dTheta += (sumOfForces.torque * dt) / inertia;
- // clear the forces
- entity.getComponent<Forces>(ComponentNames.Forces).forces = [];
-
- // maybe we fell off the floor
- if (ddy > 0 && entity.hasComponent(ComponentNames.Jump)) {
- entity.getComponent<Jump>(ComponentNames.Jump).canJump = false;
- }
- });
-
- componentEntities.get(ComponentNames.Velocity)?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
- const velocity = entity.getComponent<Velocity>(ComponentNames.Velocity);
- const boundingBox = entity.getComponent<BoundingBox>(
- ComponentNames.BoundingBox
- );
-
- // integrate velocity
- boundingBox.center.x += velocity.dCartesian.dx * dt;
- boundingBox.center.y += velocity.dCartesian.dy * dt;
- boundingBox.rotation += velocity.dTheta * dt;
- boundingBox.rotation =
- (boundingBox.rotation < 0
- ? 360 + boundingBox.rotation
- : boundingBox.rotation) % 360;
- });
- }
-}
diff --git a/client/lib/systems/Render.ts b/client/lib/systems/Render.ts
deleted file mode 100644
index 0c76b00..0000000
--- a/client/lib/systems/Render.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { System, SystemNames } from ".";
-import { BoundingBox, ComponentNames, Sprite } from "../components";
-import type { Entity } from "../entities";
-import type { DrawArgs } from "../interfaces";
-
-export class Render extends System {
- private ctx: CanvasRenderingContext2D;
-
- constructor(ctx: CanvasRenderingContext2D) {
- super(SystemNames.Render);
- this.ctx = ctx;
- }
-
- public update(
- dt: number,
- entityMap: Map<number, Entity>,
- componentEntities: Map<string, Set<number>>
- ) {
- this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
-
- componentEntities.get(ComponentNames.Sprite)?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
- const sprite = entity.getComponent<Sprite>(ComponentNames.Sprite);
- sprite.update(dt);
-
- let drawArgs: DrawArgs;
- if (entity.hasComponent(ComponentNames.BoundingBox)) {
- const boundingBox = entity.getComponent<BoundingBox>(
- ComponentNames.BoundingBox
- );
-
- drawArgs = {
- center: boundingBox.center,
- dimension: boundingBox.dimension,
- rotation: boundingBox.rotation,
- };
- }
- sprite.draw(this.ctx, drawArgs);
- });
- }
-}
diff --git a/client/lib/systems/System.ts b/client/lib/systems/System.ts
deleted file mode 100644
index 2accc97..0000000
--- a/client/lib/systems/System.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Entity } from "../entities";
-
-export abstract class System {
- public readonly name: string;
-
- constructor(name: string) {
- this.name = name;
- }
-
- abstract update(
- dt: number,
- entityMap: Map<number, Entity>,
- componentEntities: Map<string, Set<number>>
- ): void;
-}
diff --git a/client/lib/systems/WallBounds.ts b/client/lib/systems/WallBounds.ts
deleted file mode 100644
index 3fd5dc4..0000000
--- a/client/lib/systems/WallBounds.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { System, SystemNames } from ".";
-import { BoundingBox, ComponentNames } from "../components";
-import type { Entity } from "../entities";
-
-export class WallBounds extends System {
- private screenWidth: number;
-
- constructor(screenWidth: number) {
- super(SystemNames.WallBounds);
-
- this.screenWidth = screenWidth;
- }
-
- public update(
- _dt: number,
- entityMap: Map<number, Entity>,
- componentEntities: Map<string, Set<number>>
- ) {
- componentEntities.get(ComponentNames.WallBounded)?.forEach((entityId) => {
- const entity = entityMap.get(entityId);
- if (!entity.hasComponent(ComponentNames.BoundingBox)) {
- return;
- }
-
- const boundingBox = entity.getComponent<BoundingBox>(
- ComponentNames.BoundingBox
- );
-
- boundingBox.center.x = Math.min(
- this.screenWidth - boundingBox.dimension.width / 2,
- Math.max(boundingBox.dimension.width / 2, boundingBox.center.x)
- );
- });
- }
-}
diff --git a/client/lib/systems/index.ts b/client/lib/systems/index.ts
deleted file mode 100644
index 6cb6f35..0000000
--- a/client/lib/systems/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export * from "./names";
-export * from "./System";
-export * from "./Render";
-export * from "./Physics";
-export * from "./Input";
-export * from "./FacingDirection";
-export * from "./Collision";
-export * from "./WallBounds";
diff --git a/client/lib/systems/names.ts b/client/lib/systems/names.ts
deleted file mode 100644
index 23f31fc..0000000
--- a/client/lib/systems/names.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export namespace SystemNames {
- export const Render = "Render";
- export const Physics = "Physics";
- export const FacingDirection = "FacingDirection";
- export const Input = "Input";
- export const Collision = "Collision";
- export const WallBounds = "WallBounds";
-}