refactor collision methods, rescaffold server

This commit is contained in:
Lizzy Hunt 2023-08-16 15:41:35 -06:00
parent 732fe6f481
commit 1c28e10b86
No known key found for this signature in database
GPG Key ID: E835BD4B08CCAF96
4 changed files with 91 additions and 63 deletions

View File

@ -1,6 +1,6 @@
import type { Coord2D, Dimension2D } from "../interfaces"; import type { Coord2D, Dimension2D } from "../interfaces";
interface BoxedEntry { export interface BoxedEntry {
id: string; id: string;
dimension: Dimension2D; dimension: Dimension2D;
center: Coord2D; center: Coord2D;
@ -170,4 +170,12 @@ export class QuadTree {
private hasChildren() { private hasChildren() {
return this.children && this.children.size > 0; return this.children && this.children.size > 0;
} }
public setTopLeft(topLeft: Coord2D) {
this.topLeft = topLeft;
}
public setDimension(dimension: Dimension2D) {
this.dimension = dimension;
}
} }

View File

@ -10,8 +10,8 @@ import {
import { Game } from "../Game"; import { Game } from "../Game";
import { PhysicsConstants } from "../config"; import { PhysicsConstants } from "../config";
import { Entity } from "../entities"; import { Entity } from "../entities";
import type { Dimension2D, Velocity2D } from "../interfaces"; import type { Coord2D, Dimension2D, Velocity2D } from "../interfaces";
import { QuadTree } from "../structures"; import { QuadTree, BoxedEntry } from "../structures";
export class Collision extends System { export class Collision extends System {
private static readonly COLLIDABLE_COMPONENT_NAMES = [ private static readonly COLLIDABLE_COMPONENT_NAMES = [
@ -41,19 +41,26 @@ export class Collision extends System {
const entitiesToAddToQuadtree: Entity[] = []; const entitiesToAddToQuadtree: Entity[] = [];
Collision.COLLIDABLE_COMPONENT_NAMES.map((componentName) => Collision.COLLIDABLE_COMPONENT_NAMES.map((componentName) =>
game.componentEntities.get(componentName), game.forEachEntityWithComponent(componentName, (entity) => {
).forEach( if (!entity.hasComponent(ComponentNames.BoundingBox)) {
(entityIds?: Set<number>) =>
entityIds?.forEach((id) => {
const entity = game.entities.get(id);
if (!entity || !entity.hasComponent(ComponentNames.BoundingBox)) {
return; return;
} }
entitiesToAddToQuadtree.push(entity); entitiesToAddToQuadtree.push(entity);
}), }),
); );
entitiesToAddToQuadtree.forEach((entity) => { this.insertEntitiesInQuadTreeAndUpdateBounds(entitiesToAddToQuadtree);
this.findCollidingEntitiesAndCollide(entitiesToAddToQuadtree, game);
}
private insertEntitiesInQuadTreeAndUpdateBounds(entities: Entity[]) {
const topLeft: Coord2D = { x: Infinity, y: Infinity };
const bottomRight: Coord2D = { x: -Infinity, y: -Infinity };
const quadTreeInsertions: BoxedEntry[] = [];
entities.forEach((entity) => {
const boundingBox = entity.getComponent<BoundingBox>( const boundingBox = entity.getComponent<BoundingBox>(
ComponentNames.BoundingBox, ComponentNames.BoundingBox,
); );
@ -63,18 +70,45 @@ export class Collision extends System {
dimension = boundingBox.getOutscribedBoxDims(); dimension = boundingBox.getOutscribedBoxDims();
} }
this.quadTree.insert({ const { center } = boundingBox;
const topLeftBoundingBox = {
x: center.x - dimension.width / 2,
y: center.y - dimension.height / 2,
};
const bottomRightBoundingBox = {
x: center.x + dimension.width / 2,
y: center.y + dimension.height / 2,
};
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.min(bottomRightBoundingBox.y, bottomRight.y);
quadTreeInsertions.push({
id: entity.id, id: entity.id,
dimension, dimension,
center: boundingBox.center, center,
}); });
}); });
// find colliding entities and perform collisions // set bounds first
const collidingEntities = this.getCollidingEntities( if (entities.length > 0) {
entitiesToAddToQuadtree, this.quadTree.setTopLeft(topLeft);
game, this.quadTree.setDimension({
width: bottomRight.x - topLeft.x,
height: bottomRight.y - topLeft.y,
});
}
// then, begin insertions
quadTreeInsertions.forEach((boxedEntry: BoxedEntry) =>
this.quadTree.insert(boxedEntry),
); );
}
private findCollidingEntitiesAndCollide(entities: Entity[], game: Game) {
const collidingEntities = this.getCollidingEntities(entities, game);
collidingEntities.forEach(([entityAId, entityBId]) => { collidingEntities.forEach(([entityAId, entityBId]) => {
const [entityA, entityB] = [entityAId, entityBId].map((id) => const [entityA, entityB] = [entityAId, entityBId].map((id) =>
@ -139,8 +173,8 @@ export class Collision extends System {
private getCollidingEntities( private getCollidingEntities(
collidableEntities: Entity[], collidableEntities: Entity[],
game: Game, game: Game,
): [number, number][] { ): [string, string][] {
const collidingEntityIds: [number, number][] = []; const collidingEntityIds: [string, string][] = [];
for (const entity of collidableEntities) { for (const entity of collidableEntities) {
const boundingBox = entity.getComponent<BoundingBox>( const boundingBox = entity.getComponent<BoundingBox>(

View File

@ -11,50 +11,38 @@ import { Miscellaneous } from "../../engine/config";
const TICK_RATE = 60 / 1000; const TICK_RATE = 60 / 1000;
class Server { const game = new Game();
private server: any;
private game: Game;
constructor() { [new Physics(), new Collision(), new WallBounds(Miscellaneous.WIDTH)].forEach(
this.game = new Game(); (system) => game.addSystem(system),
);
[ [new Floor(160), new Player()].forEach((entity) => game.addEntity(entity));
new Physics(),
new Collision({
width: Miscellaneous.WIDTH,
height: Miscellaneous.HEIGHT,
}),
new WallBounds(Miscellaneous.WIDTH),
].forEach((system) => this.game.addSystem(system));
[new Floor(160), new Player()].forEach((entity) => game.start();
this.game.addEntity(entity),
);
this.game.start(); setInterval(() => {
setInterval(() => { game.doGameLoop(performance.now());
this.game.doGameLoop(performance.now()); }, TICK_RATE);
}, TICK_RATE);
this.server = Bun.serve<any>({ const server = Bun.serve({
websocket: { port: 8080,
open(ws) { fetch(req, server) {
ws.subscribe("the-group-chat"); const sessionId = Math.floor(Math.random() * 1e10).toString();
ws.publish("the-group-chat", msg);
}, server.upgrade(req, {
message(ws, message) { headers: {
// this is a group chat "Set-Cookie": `SessionId=${sessionId}`,
// so the server re-broadcasts incoming message to everyone
ws.publish("the-group-chat", `${ws.data.username}: ${message}`);
},
close(ws) {
const msg = `${ws.data.username} has left the chat`;
ws.unsubscribe("the-group-chat");
ws.publish("the-group-chat", msg);
},
}, },
}); });
} },
} websocket: {
open(ws) {},
message(ws, message) {
console.log(message);
},
close(ws) {},
},
});
new Server(); console.log(`Listening on ${server.hostname}:${server.port}`);

View File

@ -13,8 +13,6 @@
"noEmit": true, "noEmit": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"moduleDetection": "force", "moduleDetection": "force",
// if TS 4.x or earlier
"moduleResolution": "nodenext",
"jsx": "react-jsx", // support JSX "jsx": "react-jsx", // support JSX
"allowJs": true, // allow importing `.js` from `.ts` "allowJs": true, // allow importing `.js` from `.ts`