refactor collision methods, rescaffold server
This commit is contained in:
parent
732fe6f481
commit
1c28e10b86
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>(
|
||||||
|
@ -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}`);
|
||||||
|
@ -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`
|
||||||
|
Loading…
Reference in New Issue
Block a user