diff options
author | Elizabeth (Lizzy) Hunt <elizabeth.hunt@simponic.xyz> | 2023-08-26 17:57:05 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-26 17:57:05 -0600 |
commit | 8a4ab8d79b5ce1dabb431168398b5d5111fe326c (patch) | |
tree | e60767dc5295edf379cf421e20171dc418e548b7 /engine/systems/Collision.ts | |
parent | c6e9baa0009f7cce0f6ff156a3957ef04a8cb684 (diff) | |
parent | 6ce6946a4401d2ee6fa5cb747fab7d4c658a63c8 (diff) | |
download | jumpstorm-8a4ab8d79b5ce1dabb431168398b5d5111fe326c.tar.gz jumpstorm-8a4ab8d79b5ce1dabb431168398b5d5111fe326c.zip |
Merge pull request #1 from Simponic/network
Network
Diffstat (limited to 'engine/systems/Collision.ts')
-rw-r--r-- | engine/systems/Collision.ts | 149 |
1 files changed, 86 insertions, 63 deletions
diff --git a/engine/systems/Collision.ts b/engine/systems/Collision.ts index 2bba03b..4a838dd 100644 --- a/engine/systems/Collision.ts +++ b/engine/systems/Collision.ts @@ -1,61 +1,59 @@ -import { SystemNames, System } from "."; +import { SystemNames, System } from '.'; import { Mass, BoundingBox, ComponentNames, Jump, Velocity, - Forces, -} from "../components"; -import { Game } from "../Game"; -import { PhysicsConstants } from "../config"; -import { Entity } from "../entities"; -import type { Dimension2D } from "../interfaces"; -import { QuadTree } from "../structures"; + Forces +} from '../components'; +import { Game } from '../Game'; +import { Miscellaneous, PhysicsConstants } from '../config'; +import { Entity } from '../entities'; +import type { Coord2D, Dimension2D, Velocity2D } from '../interfaces'; +import { BoxedEntry, RefreshingCollisionFinderBehavior } from '../structures'; export class Collision extends System { private static readonly COLLIDABLE_COMPONENT_NAMES = [ ComponentNames.Collide, - ComponentNames.TopCollidable, + ComponentNames.TopCollidable ]; - private static readonly QUADTREE_MAX_LEVELS = 10; - private static readonly QUADTREE_SPLIT_THRESHOLD = 10; - private quadTree: QuadTree; + private collisionFinder: RefreshingCollisionFinderBehavior; - constructor(screenDimensions: Dimension2D) { + constructor(refreshingCollisionFinder: RefreshingCollisionFinderBehavior) { super(SystemNames.Collision); - this.quadTree = new QuadTree( - { x: 0, y: 0 }, - screenDimensions, - Collision.QUADTREE_MAX_LEVELS, - Collision.QUADTREE_SPLIT_THRESHOLD, - ); + this.collisionFinder = refreshingCollisionFinder; } public update(_dt: number, game: Game) { - // rebuild the quadtree - this.quadTree.clear(); + this.collisionFinder.clear(); - const entitiesToAddToQuadtree: Entity[] = []; + const entitiesToAddToCollisionFinder: Entity[] = []; Collision.COLLIDABLE_COMPONENT_NAMES.map((componentName) => - game.componentEntities.get(componentName), - ).forEach( - (entityIds?: Set<number>) => - entityIds?.forEach((id) => { - const entity = game.entities.get(id); - if (!entity || !entity.hasComponent(ComponentNames.BoundingBox)) { - return; - } - entitiesToAddToQuadtree.push(entity); - }), + game.forEachEntityWithComponent(componentName, (entity) => { + if (!entity.hasComponent(ComponentNames.BoundingBox)) { + return; + } + entitiesToAddToCollisionFinder.push(entity); + }) ); - entitiesToAddToQuadtree.forEach((entity) => { + this.insertEntitiesAndUpdateBounds(entitiesToAddToCollisionFinder); + this.findCollidingEntitiesAndCollide(entitiesToAddToCollisionFinder, game); + } + + private insertEntitiesAndUpdateBounds(entities: Entity[]) { + const collisionFinderInsertions: BoxedEntry[] = []; + + const topLeft: Coord2D = { x: Infinity, y: Infinity }; + const bottomRight: Coord2D = { x: -Infinity, y: -Infinity }; + + entities.forEach((entity) => { const boundingBox = entity.getComponent<BoundingBox>( - ComponentNames.BoundingBox, + ComponentNames.BoundingBox ); let dimension = { ...boundingBox.dimension }; @@ -63,18 +61,43 @@ export class Collision extends System { dimension = boundingBox.getOutscribedBoxDims(); } - this.quadTree.insert(entity.id, dimension, boundingBox.center); + const { center } = boundingBox; + const topLeftBoundingBox = boundingBox.getTopLeft(); + const bottomRightBoundingBox = boundingBox.getBottomRight(); + + topLeft.x = Math.min(topLeftBoundingBox.x, topLeft.x); + topLeft.y = Math.min(topLeftBoundingBox.y, topLeft.y); + bottomRight.x = Math.max(bottomRightBoundingBox.x, bottomRight.x); + bottomRight.y = Math.max(bottomRightBoundingBox.y, bottomRight.y); + + collisionFinderInsertions.push({ + id: entity.id, + dimension, + center + }); }); - // find colliding entities and perform collisions - const collidingEntities = this.getCollidingEntities( - entitiesToAddToQuadtree, - game, + // set bounds first + if (entities.length > 0) { + this.collisionFinder.setTopLeft(topLeft); + this.collisionFinder.setDimension({ + width: bottomRight.x - topLeft.x, + height: bottomRight.y - topLeft.y + }); + } + + // then, begin insertions + collisionFinderInsertions.forEach((boxedEntry: BoxedEntry) => + this.collisionFinder.insert(boxedEntry) ); + } + + private findCollidingEntitiesAndCollide(entities: Entity[], game: Game) { + const collidingEntities = this.getCollidingEntities(entities, game); collidingEntities.forEach(([entityAId, entityBId]) => { const [entityA, entityB] = [entityAId, entityBId].map((id) => - game.entities.get(id), + game.entities.get(id) ); if (entityA && entityB) { this.performCollision(entityA, entityB); @@ -84,12 +107,14 @@ export class Collision extends System { private performCollision(entityA: Entity, entityB: Entity) { const [entityABoundingBox, entityBBoundingBox] = [entityA, entityB].map( - (entity) => entity.getComponent<BoundingBox>(ComponentNames.BoundingBox), + (entity) => entity.getComponent<BoundingBox>(ComponentNames.BoundingBox) ); - let velocity = new Velocity(); + let velocity: Velocity2D = { dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }; if (entityA.hasComponent(ComponentNames.Velocity)) { - velocity = entityA.getComponent<Velocity>(ComponentNames.Velocity); + velocity = entityA.getComponent<Velocity>( + ComponentNames.Velocity + ).velocity; } if ( @@ -100,7 +125,7 @@ export class Collision extends System { ) { 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.`, + `entity with id ${entityB.id} has TopCollidable component and a non-zero rotation. that is not (yet) supported.` ); } @@ -114,7 +139,7 @@ export class Collision extends System { entityA.getComponent<Forces>(ComponentNames.Forces).forces.push({ fCartesian: { fy: F_n, fx: 0 }, - torque: 0, + torque: 0 }); } @@ -132,35 +157,33 @@ export class Collision extends System { private getCollidingEntities( collidableEntities: Entity[], - game: Game, - ): [number, number][] { - const collidingEntityIds: [number, number][] = []; + game: Game + ): [string, string][] { + const collidingEntityIds: [string, string][] = []; for (const entity of collidableEntities) { const boundingBox = entity.getComponent<BoundingBox>( - ComponentNames.BoundingBox, + ComponentNames.BoundingBox ); - const neighborIds = this.quadTree - .getNeighborIds({ - id: entity.id, - dimension: boundingBox.dimension, - center: boundingBox.center, - }) - .filter((neighborId) => neighborId != entity.id); + const neighborIds = this.collisionFinder.getNeighborIds({ + id: entity.id, + dimension: boundingBox.dimension, + center: boundingBox.center + }); - neighborIds.forEach((neighborId) => { + for (const neighborId of neighborIds) { const neighbor = game.getEntity(neighborId); if (!neighbor) return; const neighborBoundingBox = neighbor.getComponent<BoundingBox>( - ComponentNames.BoundingBox, + ComponentNames.BoundingBox ); if (boundingBox.isCollidingWith(neighborBoundingBox)) { collidingEntityIds.push([entity.id, neighborId]); } - }); + } } return collidingEntityIds; @@ -169,11 +192,11 @@ export class Collision extends System { // ramblings: https://excalidraw.com/#json=z-xD86Za4a3duZuV2Oky0,KaGe-5iHJu1Si8inEo4GLQ private getDyToPushOutOfFloor( entityBoundingBox: BoundingBox, - floorBoundingBox: BoundingBox, + floorBoundingBox: BoundingBox ): number { const { dimension: { width, height }, - center: { x }, + center: { x } } = entityBoundingBox; const outScribedRectangle = entityBoundingBox.getOutscribedBoxDims(); @@ -192,7 +215,7 @@ export class Collision extends System { if (x >= floorBoundingBox.center.x) { boundedCollisionX = Math.min( floorBoundingBox.center.x + floorBoundingBox.dimension.width / 2, - clippedX, + clippedX ); return ( outScribedRectangle.height / 2 - @@ -202,7 +225,7 @@ export class Collision extends System { boundedCollisionX = Math.max( floorBoundingBox.center.x - floorBoundingBox.dimension.width / 2, - clippedX, + clippedX ); return ( |