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";
interface BoxedEntry {
export interface BoxedEntry {
id: string;
dimension: Dimension2D;
center: Coord2D;
@ -170,4 +170,12 @@ export class QuadTree {
private hasChildren() {
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 { PhysicsConstants } from "../config";
import { Entity } from "../entities";
import type { Dimension2D, Velocity2D } from "../interfaces";
import { QuadTree } from "../structures";
import type { Coord2D, Dimension2D, Velocity2D } from "../interfaces";
import { QuadTree, BoxedEntry } from "../structures";
export class Collision extends System {
private static readonly COLLIDABLE_COMPONENT_NAMES = [
@ -41,19 +41,26 @@ export class Collision extends System {
const entitiesToAddToQuadtree: 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;
}
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>(
ComponentNames.BoundingBox,
);
@ -63,18 +70,45 @@ export class Collision extends System {
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,
dimension,
center: boundingBox.center,
center,
});
});
// find colliding entities and perform collisions
const collidingEntities = this.getCollidingEntities(
entitiesToAddToQuadtree,
game,
// set bounds first
if (entities.length > 0) {
this.quadTree.setTopLeft(topLeft);
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]) => {
const [entityA, entityB] = [entityAId, entityBId].map((id) =>
@ -139,8 +173,8 @@ export class Collision extends System {
private getCollidingEntities(
collidableEntities: Entity[],
game: Game,
): [number, number][] {
const collidingEntityIds: [number, number][] = [];
): [string, string][] {
const collidingEntityIds: [string, string][] = [];
for (const entity of collidableEntities) {
const boundingBox = entity.getComponent<BoundingBox>(

View File

@ -11,50 +11,38 @@ import { Miscellaneous } from "../../engine/config";
const TICK_RATE = 60 / 1000;
class Server {
private server: any;
private game: Game;
const game = new Game();
constructor() {
this.game = new Game();
[new Physics(), new Collision(), new WallBounds(Miscellaneous.WIDTH)].forEach(
(system) => game.addSystem(system),
);
[
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.addEntity(entity));
[new Floor(160), new Player()].forEach((entity) =>
this.game.addEntity(entity),
);
game.start();
this.game.start();
setInterval(() => {
this.game.doGameLoop(performance.now());
}, TICK_RATE);
setInterval(() => {
game.doGameLoop(performance.now());
}, TICK_RATE);
this.server = Bun.serve<any>({
websocket: {
open(ws) {
ws.subscribe("the-group-chat");
ws.publish("the-group-chat", msg);
},
message(ws, message) {
// this is a group chat
// 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);
},
const server = Bun.serve({
port: 8080,
fetch(req, server) {
const sessionId = Math.floor(Math.random() * 1e10).toString();
server.upgrade(req, {
headers: {
"Set-Cookie": `SessionId=${sessionId}`,
},
});
}
}
},
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,
"allowImportingTsExtensions": true,
"moduleDetection": "force",
// if TS 4.x or earlier
"moduleResolution": "nodenext",
"jsx": "react-jsx", // support JSX
"allowJs": true, // allow importing `.js` from `.ts`