prettier formatting
This commit is contained in:
parent
dec7b614d8
commit
773ce84f4b
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
// add more generic rule sets here, such as:
|
||||
"eslint:recommended",
|
||||
"plugin:svelte/recommended",
|
||||
'eslint:recommended',
|
||||
'plugin:svelte/recommended'
|
||||
],
|
||||
rules: {
|
||||
// override/add rules settings here, such as:
|
||||
// 'svelte/rule-name': 'error'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
@ -10,7 +10,7 @@
|
||||
--orange: #af3a03;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
--bg: #282828;
|
||||
--text: #f9f5d7;
|
||||
--red: #fb4934;
|
||||
|
@ -1,15 +1,15 @@
|
||||
@import url("./theme.css");
|
||||
@import url("./tf.css");
|
||||
@import url('./theme.css');
|
||||
@import url('./tf.css');
|
||||
|
||||
@font-face {
|
||||
font-family: "scientifica";
|
||||
src: url("/fonts/scientifica.ttf");
|
||||
font-family: 'scientifica';
|
||||
src: url('/fonts/scientifica.ttf');
|
||||
}
|
||||
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: "scientifica", monospace;
|
||||
font-family: 'scientifica', monospace;
|
||||
transition: background 0.2s ease-in-out;
|
||||
font-smooth: never;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
rgba(162, 254, 254, 1) 100%
|
||||
);
|
||||
|
||||
content: "";
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import url("./colors.css");
|
||||
@import url('./colors.css');
|
||||
|
||||
.primary {
|
||||
color: var(--aqua);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Game } from "@engine/Game";
|
||||
import { Entity } from "@engine/entities";
|
||||
import { Grid } from "@engine/structures";
|
||||
import { Game } from '@engine/Game';
|
||||
import { Entity, Floor } from '@engine/entities';
|
||||
import { Grid } from '@engine/structures';
|
||||
import {
|
||||
WallBounds,
|
||||
FacingDirection,
|
||||
@ -8,17 +8,19 @@ import {
|
||||
Physics,
|
||||
Input,
|
||||
Collision,
|
||||
NetworkUpdate,
|
||||
} from "@engine/systems";
|
||||
NetworkUpdate
|
||||
} from '@engine/systems';
|
||||
import {
|
||||
type MessageQueueProvider,
|
||||
type MessagePublisher,
|
||||
type MessageProcessor,
|
||||
type Message,
|
||||
type EntityAddBody,
|
||||
MessageType,
|
||||
} from "@engine/network";
|
||||
import { stringify, parse } from "@engine/utils";
|
||||
MessageType
|
||||
} from '@engine/network';
|
||||
import { stringify, parse } from '@engine/utils';
|
||||
import { BoundingBox, Sprite } from '@engine/components';
|
||||
import { Miscellaneous } from '@engine/config';
|
||||
|
||||
class ClientMessageProcessor implements MessageProcessor {
|
||||
private game: Game;
|
||||
@ -29,14 +31,19 @@ class ClientMessageProcessor implements MessageProcessor {
|
||||
|
||||
public process(message: Message) {
|
||||
switch (message.type) {
|
||||
case MessageType.NEW_ENTITY:
|
||||
const entityAddBody = message.body as unknown as EntityAddBody;
|
||||
this.game.addEntity(
|
||||
Entity.from(entityAddBody.entityName, entityAddBody.args),
|
||||
case MessageType.NEW_ENTITIES:
|
||||
const entityAdditions = message.body as unknown as EntityAddBody[];
|
||||
entityAdditions.forEach((addBody) =>
|
||||
this.game.addEntity(Entity.from(addBody.entityName, addBody.args))
|
||||
);
|
||||
break;
|
||||
case MessageType.REMOVE_ENTITIES:
|
||||
const ids = message.body as unknown as string[];
|
||||
ids.forEach((id) => this.game.removeEntity(id));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
@ -49,9 +56,9 @@ class ClientSocketMessageQueueProvider implements MessageQueueProvider {
|
||||
this.socket = socket;
|
||||
this.messages = [];
|
||||
|
||||
this.socket.addEventListener("message", (e) => {
|
||||
const message = parse<Message>(e.data);
|
||||
this.messages.push(message);
|
||||
this.socket.addEventListener('message', (e) => {
|
||||
const messages = parse<Message[]>(e.data);
|
||||
this.messages = this.messages.concat(messages);
|
||||
});
|
||||
}
|
||||
|
||||
@ -79,7 +86,7 @@ class ClientSocketMessagePublisher implements MessagePublisher {
|
||||
|
||||
public publish() {
|
||||
this.messages.forEach((message: Message) =>
|
||||
this.socket.send(stringify(message)),
|
||||
this.socket.send(stringify(message))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -96,7 +103,7 @@ export class JumpStorm {
|
||||
ctx: CanvasRenderingContext2D,
|
||||
httpMethod: string,
|
||||
wsMethod: string,
|
||||
host: string,
|
||||
host: string
|
||||
) {
|
||||
await fetch(`${httpMethod}://${host}/assign`)
|
||||
.then((resp) => {
|
||||
@ -115,7 +122,7 @@ export class JumpStorm {
|
||||
const clientSocketMessageQueueProvider =
|
||||
new ClientSocketMessageQueueProvider(socket);
|
||||
const clientSocketMessagePublisher = new ClientSocketMessagePublisher(
|
||||
socket,
|
||||
socket
|
||||
);
|
||||
const clientMessageProcessor = new ClientMessageProcessor(this.game);
|
||||
[
|
||||
@ -123,14 +130,28 @@ export class JumpStorm {
|
||||
new FacingDirection(),
|
||||
new Physics(),
|
||||
new Collision(grid),
|
||||
new WallBounds(ctx.canvas.width),
|
||||
new WallBounds(),
|
||||
new NetworkUpdate(
|
||||
clientSocketMessageQueueProvider,
|
||||
clientSocketMessagePublisher,
|
||||
clientMessageProcessor,
|
||||
clientMessageProcessor
|
||||
),
|
||||
new Render(ctx),
|
||||
new Render(ctx)
|
||||
].forEach((system) => this.game.addSystem(system));
|
||||
|
||||
const floor = new Floor(160);
|
||||
const floorHeight = 40;
|
||||
|
||||
floor.addComponent(
|
||||
new BoundingBox(
|
||||
{
|
||||
x: Miscellaneous.WIDTH / 2,
|
||||
y: Miscellaneous.HEIGHT - floorHeight / 2
|
||||
},
|
||||
{ width: Miscellaneous.WIDTH, height: floorHeight }
|
||||
)
|
||||
);
|
||||
this.game.addEntity(floor);
|
||||
}
|
||||
|
||||
public play() {
|
||||
@ -146,13 +167,13 @@ export class JumpStorm {
|
||||
private createInputSystem(): Input {
|
||||
const inputSystem = new Input(this.clientId);
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (!e.repeat) {
|
||||
inputSystem.keyPressed(e.key);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("keyup", (e) => inputSystem.keyReleased(e.key));
|
||||
window.addEventListener('keyup', (e) => inputSystem.keyReleased(e.key));
|
||||
|
||||
return inputSystem;
|
||||
}
|
||||
|
@ -19,8 +19,7 @@
|
||||
const game = new Game();
|
||||
const jumpStorm = new JumpStorm(game);
|
||||
|
||||
const url = new URL(document.location);
|
||||
await jumpStorm.init(ctx, "http", "ws", url.host + "/api");
|
||||
await jumpStorm.init(ctx, "http", "ws", document.location.host + "/api");
|
||||
jumpStorm.play();
|
||||
});
|
||||
</script>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
const MAX_ENTRIES = 8;
|
||||
|
||||
export let entries: { name: string, score: number }[] = [];
|
||||
export let entries: { name: string; score: number }[] = [];
|
||||
</script>
|
||||
|
||||
<div class="leaderboard">
|
||||
|
@ -1,7 +1,7 @@
|
||||
import App from "./App.svelte";
|
||||
import App from './App.svelte';
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById("app"),
|
||||
target: document.getElementById('app')
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
let width: number = Miscellaneous.WIDTH;
|
||||
let height: number = Miscellaneous.HEIGHT;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="centered-game">
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
export default {
|
||||
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
}
|
||||
preprocess: vitePreprocess()
|
||||
};
|
||||
|
@ -1,23 +1,23 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import { defineConfig } from 'vite';
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
server: {
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://localhost:8080",
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
ws: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ""),
|
||||
},
|
||||
},
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
}
|
||||
},
|
||||
cors: true,
|
||||
plugins: [svelte()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@engine": fileURLToPath(new URL("../engine", import.meta.url)),
|
||||
},
|
||||
},
|
||||
'@engine': fileURLToPath(new URL('../engine', import.meta.url))
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Entity } from "./entities";
|
||||
import { System } from "./systems";
|
||||
import { Entity } from './entities';
|
||||
import { System } from './systems';
|
||||
|
||||
export class Game {
|
||||
private systemOrder: string[];
|
||||
@ -39,7 +39,7 @@ export class Game {
|
||||
|
||||
public forEachEntityWithComponent(
|
||||
componentName: string,
|
||||
callback: (entity: Entity) => void,
|
||||
callback: (entity: Entity) => void
|
||||
) {
|
||||
this.componentEntities.get(componentName)?.forEach((entityId) => {
|
||||
const entity = this.getEntity(entityId);
|
||||
@ -75,12 +75,12 @@ export class Game {
|
||||
if (!this.componentEntities.has(component.name)) {
|
||||
this.componentEntities.set(
|
||||
component.name,
|
||||
new Set<string>([entity.id]),
|
||||
new Set<string>([entity.id])
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.componentEntities.get(component.name)?.add(entity.id);
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
this.systemOrder.forEach((systemName) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import type { Coord2D, Dimension2D } from "../interfaces";
|
||||
import { dotProduct, rotateVector } from "../utils";
|
||||
import { Component, ComponentNames } from '.';
|
||||
import type { Coord2D, Dimension2D } from '../interfaces';
|
||||
import { dotProduct, rotateVector } from '../utils';
|
||||
|
||||
export class BoundingBox extends Component {
|
||||
public center: Coord2D;
|
||||
@ -48,8 +48,8 @@ export class BoundingBox extends Component {
|
||||
const projection = dotProduct(normal, vertex);
|
||||
return [Math.min(min, projection), Math.max(max, projection)];
|
||||
},
|
||||
[Infinity, -Infinity],
|
||||
),
|
||||
[Infinity, -Infinity]
|
||||
)
|
||||
);
|
||||
|
||||
if (maxThis < minBox || maxBox < minThis) return false;
|
||||
@ -64,14 +64,14 @@ export class BoundingBox extends Component {
|
||||
{ x: -this.dimension.width / 2, y: -this.dimension.height / 2 },
|
||||
{ x: -this.dimension.width / 2, y: this.dimension.height / 2 },
|
||||
{ x: this.dimension.width / 2, y: this.dimension.height / 2 },
|
||||
{ x: this.dimension.width / 2, y: -this.dimension.height / 2 },
|
||||
{ x: this.dimension.width / 2, y: -this.dimension.height / 2 }
|
||||
]
|
||||
.map((vertex) => rotateVector(vertex, this.rotation)) // rotate
|
||||
.map((vertex) => {
|
||||
// translate
|
||||
return {
|
||||
x: vertex.x + this.center.x,
|
||||
y: vertex.y + this.center.y,
|
||||
y: vertex.y + this.center.y
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -92,28 +92,28 @@ export class BoundingBox extends Component {
|
||||
if (rads <= Math.PI / 2) {
|
||||
return {
|
||||
width: Math.abs(height * Math.sin(rads) + width * Math.cos(rads)),
|
||||
height: Math.abs(width * Math.sin(rads) + height * Math.cos(rads)),
|
||||
height: Math.abs(width * Math.sin(rads) + height * Math.cos(rads))
|
||||
};
|
||||
}
|
||||
|
||||
rads -= Math.PI / 2;
|
||||
return {
|
||||
width: Math.abs(height * Math.cos(rads) + width * Math.sin(rads)),
|
||||
height: Math.abs(width * Math.cos(rads) + height * Math.sin(rads)),
|
||||
height: Math.abs(width * Math.cos(rads) + height * Math.sin(rads))
|
||||
};
|
||||
}
|
||||
|
||||
public getTopLeft(): Coord2D {
|
||||
return {
|
||||
x: this.center.x - this.dimension.width / 2,
|
||||
y: this.center.y - this.dimension.height / 2,
|
||||
y: this.center.y - this.dimension.height / 2
|
||||
};
|
||||
}
|
||||
|
||||
public getBottomRight(): Coord2D {
|
||||
return {
|
||||
x: this.center.x + this.dimension.width / 2,
|
||||
y: this.center.y + this.dimension.height / 2,
|
||||
y: this.center.y + this.dimension.height / 2
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class Collide extends Component {
|
||||
constructor() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames, Velocity } from ".";
|
||||
import { Component, ComponentNames, Velocity } from '.';
|
||||
|
||||
export class Control extends Component {
|
||||
public controlVelocityComponent: Velocity;
|
||||
@ -6,7 +6,7 @@ export class Control extends Component {
|
||||
|
||||
constructor(
|
||||
controllableBy: string,
|
||||
controlVelocityComponent: Velocity = new Velocity(),
|
||||
controlVelocityComponent: Velocity = new Velocity()
|
||||
) {
|
||||
super(ComponentNames.Control);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames, Sprite } from ".";
|
||||
import { Component, ComponentNames, Sprite } from '.';
|
||||
|
||||
export class FacingDirection extends Component {
|
||||
public readonly facingLeftSprite: Sprite;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { Force2D } from "../interfaces";
|
||||
import { Component } from "./Component";
|
||||
import { ComponentNames } from ".";
|
||||
import type { Force2D } from '../interfaces';
|
||||
import { Component } from './Component';
|
||||
import { ComponentNames } from '.';
|
||||
|
||||
/**
|
||||
* A list of forces and torque, (in newtons, and newton-meters respectively)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ComponentNames, Component } from ".";
|
||||
import { ComponentNames, Component } from '.';
|
||||
|
||||
export class Gravity extends Component {
|
||||
private static DEFAULT_TERMINAL_VELOCITY = 5;
|
||||
private static DEFAULT_TERMINAL_VELOCITY = 4.5;
|
||||
|
||||
public terminalVelocity: number;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class Jump extends Component {
|
||||
public canJump: boolean;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class Mass extends Component {
|
||||
public mass: number;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class Moment extends Component {
|
||||
public inertia: number;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class NetworkUpdateable extends Component {
|
||||
public isPublish: boolean;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import type { Dimension2D, DrawArgs, Coord2D } from "../interfaces";
|
||||
import { Component, ComponentNames } from '.';
|
||||
import type { Dimension2D, DrawArgs, Coord2D } from '../interfaces';
|
||||
|
||||
export class Sprite extends Component {
|
||||
private sheet: HTMLImageElement;
|
||||
@ -17,7 +17,7 @@ export class Sprite extends Component {
|
||||
spriteImgPos: Coord2D,
|
||||
spriteImgDimensions: Dimension2D,
|
||||
msPerFrame: number,
|
||||
numFrames: number,
|
||||
numFrames: number
|
||||
) {
|
||||
super(ComponentNames.Sprite);
|
||||
|
||||
@ -56,12 +56,12 @@ export class Sprite extends Component {
|
||||
ctx.drawImage(
|
||||
this.sheet,
|
||||
...this.getSpriteArgs(),
|
||||
...this.getDrawArgs(drawArgs),
|
||||
...this.getDrawArgs(drawArgs)
|
||||
);
|
||||
|
||||
if (tint) {
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.globalCompositeOperation = "source-atop";
|
||||
ctx.globalCompositeOperation = 'source-atop';
|
||||
ctx.fillStyle = tint;
|
||||
ctx.fillRect(...this.getDrawArgs(drawArgs));
|
||||
}
|
||||
@ -74,19 +74,23 @@ export class Sprite extends Component {
|
||||
this.spriteImgPos.x + this.currentFrame * this.spriteImgDimensions.width,
|
||||
this.spriteImgPos.y,
|
||||
this.spriteImgDimensions.width,
|
||||
this.spriteImgDimensions.height,
|
||||
this.spriteImgDimensions.height
|
||||
];
|
||||
}
|
||||
|
||||
private getDrawArgs({
|
||||
center,
|
||||
dimension,
|
||||
dimension
|
||||
}: DrawArgs): [dx: number, dy: number, dw: number, dh: number] {
|
||||
return [
|
||||
center.x - dimension.width / 2,
|
||||
center.y - dimension.height / 2,
|
||||
dimension.width,
|
||||
dimension.height,
|
||||
dimension.height
|
||||
];
|
||||
}
|
||||
|
||||
public getSpriteDimensions() {
|
||||
return this.spriteImgDimensions;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class TopCollidable extends Component {
|
||||
constructor() {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import type { Velocity2D } from "../interfaces";
|
||||
import { Component } from "./Component";
|
||||
import { ComponentNames } from ".";
|
||||
import type { Velocity2D } from '../interfaces';
|
||||
import { Component } from './Component';
|
||||
import { ComponentNames } from '.';
|
||||
|
||||
export class Velocity extends Component {
|
||||
public velocity: Velocity2D;
|
||||
|
||||
constructor(
|
||||
velocity: Velocity2D = { dCartesian: { dx: 0, dy: 0 }, dTheta: 0 },
|
||||
velocity: Velocity2D = { dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }
|
||||
) {
|
||||
super(ComponentNames.Velocity);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, ComponentNames } from ".";
|
||||
import { Component, ComponentNames } from '.';
|
||||
|
||||
export class WallBounded extends Component {
|
||||
constructor() {
|
||||
|
@ -1,16 +1,16 @@
|
||||
export * from "./Component";
|
||||
export * from "./BoundingBox";
|
||||
export * from "./Velocity";
|
||||
export * from "./Forces";
|
||||
export * from "./Sprite";
|
||||
export * from "./FacingDirection";
|
||||
export * from "./Jump";
|
||||
export * from "./TopCollidable";
|
||||
export * from "./Collide";
|
||||
export * from "./Control";
|
||||
export * from "./WallBounded";
|
||||
export * from "./Gravity";
|
||||
export * from "./Mass";
|
||||
export * from "./Moment";
|
||||
export * from "./NetworkUpdateable";
|
||||
export * from "./names";
|
||||
export * from './Component';
|
||||
export * from './BoundingBox';
|
||||
export * from './Velocity';
|
||||
export * from './Forces';
|
||||
export * from './Sprite';
|
||||
export * from './FacingDirection';
|
||||
export * from './Jump';
|
||||
export * from './TopCollidable';
|
||||
export * from './Collide';
|
||||
export * from './Control';
|
||||
export * from './WallBounded';
|
||||
export * from './Gravity';
|
||||
export * from './Mass';
|
||||
export * from './Moment';
|
||||
export * from './NetworkUpdateable';
|
||||
export * from './names';
|
||||
|
@ -1,16 +1,16 @@
|
||||
export namespace ComponentNames {
|
||||
export const Sprite = "Sprite";
|
||||
export const BoundingBox = "BoundingBox";
|
||||
export const Velocity = "Velocity";
|
||||
export const FacingDirection = "FacingDirection";
|
||||
export const Control = "Control";
|
||||
export const Jump = "Jump";
|
||||
export const TopCollidable = "TopCollidable";
|
||||
export const Collide = "Collide";
|
||||
export const WallBounded = "WallBounded";
|
||||
export const Gravity = "Gravity";
|
||||
export const Forces = "Forces";
|
||||
export const Mass = "Mass";
|
||||
export const Moment = "Moment";
|
||||
export const NetworkUpdateable = "NetworkUpdateable";
|
||||
export const Sprite = 'Sprite';
|
||||
export const BoundingBox = 'BoundingBox';
|
||||
export const Velocity = 'Velocity';
|
||||
export const FacingDirection = 'FacingDirection';
|
||||
export const Control = 'Control';
|
||||
export const Jump = 'Jump';
|
||||
export const TopCollidable = 'TopCollidable';
|
||||
export const Collide = 'Collide';
|
||||
export const WallBounded = 'WallBounded';
|
||||
export const Gravity = 'Gravity';
|
||||
export const Forces = 'Forces';
|
||||
export const Mass = 'Mass';
|
||||
export const Moment = 'Moment';
|
||||
export const NetworkUpdateable = 'NetworkUpdateable';
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import type { SpriteSpec } from "./sprites";
|
||||
import { SPRITE_SPECS } from "./sprites";
|
||||
import type { SpriteSpec } from './sprites';
|
||||
import { SPRITE_SPECS } from './sprites';
|
||||
|
||||
export const IMAGES = new Map<string, HTMLImageElement>();
|
||||
|
||||
export const loadSpritesIntoImageElements = (
|
||||
spriteSpecs: Partial<SpriteSpec>[],
|
||||
spriteSpecs: Partial<SpriteSpec>[]
|
||||
): Promise<void>[] => {
|
||||
const spritePromises: Promise<void>[] = [];
|
||||
|
||||
@ -17,13 +17,13 @@ export const loadSpritesIntoImageElements = (
|
||||
spritePromises.push(
|
||||
new Promise((resolve) => {
|
||||
img.onload = () => resolve();
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (spriteSpec.states) {
|
||||
spritePromises.push(
|
||||
...loadSpritesIntoImageElements(Array.from(spriteSpec.states.values())),
|
||||
...loadSpritesIntoImageElements(Array.from(spriteSpec.states.values()))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -35,8 +35,8 @@ export const loadAssets = () =>
|
||||
Promise.all([
|
||||
...loadSpritesIntoImageElements(
|
||||
Array.from(SPRITE_SPECS.keys()).map(
|
||||
(key) => SPRITE_SPECS.get(key) as SpriteSpec,
|
||||
),
|
||||
),
|
||||
(key) => SPRITE_SPECS.get(key) as SpriteSpec
|
||||
)
|
||||
)
|
||||
// TODO: Sound
|
||||
]);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Action } from "../interfaces";
|
||||
import { Action } from '../interfaces';
|
||||
|
||||
export namespace KeyConstants {
|
||||
export const KeyActions: Record<string, Action> = {
|
||||
@ -10,11 +10,13 @@ export namespace KeyConstants {
|
||||
|
||||
w: Action.JUMP,
|
||||
ArrowUp: Action.JUMP,
|
||||
|
||||
' ': Action.JUMP
|
||||
};
|
||||
|
||||
// value -> [key] from KeyActions
|
||||
export const ActionKeys: Map<Action, string[]> = Object.keys(
|
||||
KeyActions,
|
||||
KeyActions
|
||||
).reduce((acc: Map<Action, string[]>, key) => {
|
||||
const action = KeyActions[key];
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
export * from "./constants";
|
||||
export * from "./assets.ts";
|
||||
export * from "./sprites.ts";
|
||||
export * from './constants';
|
||||
export * from './assets.ts';
|
||||
export * from './sprites.ts';
|
||||
|
@ -1,7 +1,7 @@
|
||||
export enum Sprites {
|
||||
FLOOR,
|
||||
TRAMPOLINE,
|
||||
COFFEE,
|
||||
COFFEE
|
||||
}
|
||||
|
||||
export interface SpriteSpec {
|
||||
@ -22,12 +22,12 @@ const floorSpriteSpec = {
|
||||
height: 40,
|
||||
frames: 3,
|
||||
msPerFrame: 125,
|
||||
states: new Map<number, Partial<SpriteSpec>>(),
|
||||
states: new Map<number, Partial<SpriteSpec>>()
|
||||
};
|
||||
[40, 80, 120, 160].forEach((width) => {
|
||||
floorSpriteSpec.states.set(width, {
|
||||
width,
|
||||
sheet: `/assets/floor_tile_${width}.png`,
|
||||
sheet: `/assets/floor_tile_${width}.png`
|
||||
});
|
||||
});
|
||||
SPRITE_SPECS.set(Sprites.FLOOR, floorSpriteSpec);
|
||||
@ -37,12 +37,12 @@ const coffeeSpriteSpec = {
|
||||
width: 60,
|
||||
height: 45,
|
||||
frames: 3,
|
||||
states: new Map<string, Partial<SpriteSpec>>(),
|
||||
states: new Map<string, Partial<SpriteSpec>>()
|
||||
};
|
||||
coffeeSpriteSpec.states.set("LEFT", {
|
||||
sheet: "/assets/coffee_left.png",
|
||||
coffeeSpriteSpec.states.set('LEFT', {
|
||||
sheet: '/assets/coffee_left.png'
|
||||
});
|
||||
coffeeSpriteSpec.states.set("RIGHT", {
|
||||
sheet: "/assets/coffee_right.png",
|
||||
coffeeSpriteSpec.states.set('RIGHT', {
|
||||
sheet: '/assets/coffee_right.png'
|
||||
});
|
||||
SPRITE_SPECS.set(Sprites.COFFEE, coffeeSpriteSpec);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EntityNames, Player } from ".";
|
||||
import type { Component } from "../components";
|
||||
import { EntityNames, Player } from '.';
|
||||
import type { Component } from '../components';
|
||||
|
||||
export abstract class Entity {
|
||||
public id: string;
|
||||
@ -18,7 +18,7 @@ export abstract class Entity {
|
||||
|
||||
public getComponent<T extends Component>(name: string): T {
|
||||
if (!this.hasComponent(name)) {
|
||||
throw new Error("Entity does not have component " + name);
|
||||
throw new Error('Entity does not have component ' + name);
|
||||
}
|
||||
return this.components.get(name) as T;
|
||||
}
|
||||
@ -34,9 +34,11 @@ export abstract class Entity {
|
||||
static from(entityName: string, args: any): Entity {
|
||||
switch (entityName) {
|
||||
case EntityNames.Player:
|
||||
return new Player(args.playerId);
|
||||
const player = new Player(args.playerId);
|
||||
player.id = args.id;
|
||||
return player;
|
||||
default:
|
||||
throw new Error(".from() Entity type not implemented: " + entityName);
|
||||
throw new Error('.from() Entity type not implemented: ' + entityName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config";
|
||||
import { BoundingBox, Sprite } from "../components";
|
||||
import { TopCollidable } from "../components/TopCollidable";
|
||||
import { Entity, EntityNames } from "../entities";
|
||||
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from '../config';
|
||||
import { BoundingBox, Sprite } from '../components';
|
||||
import { TopCollidable } from '../components/TopCollidable';
|
||||
import { Entity, EntityNames } from '../entities';
|
||||
|
||||
export class Floor extends Entity {
|
||||
private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
|
||||
Sprites.FLOOR,
|
||||
Sprites.FLOOR
|
||||
) as SpriteSpec;
|
||||
|
||||
constructor(width: number) {
|
||||
@ -17,18 +17,8 @@ export class Floor extends Entity {
|
||||
{ x: 0, y: 0 },
|
||||
{ width, height: Floor.spriteSpec.height },
|
||||
Floor.spriteSpec.msPerFrame,
|
||||
Floor.spriteSpec.frames,
|
||||
),
|
||||
);
|
||||
|
||||
this.addComponent(
|
||||
new BoundingBox(
|
||||
{
|
||||
x: 300,
|
||||
y: 300,
|
||||
},
|
||||
{ width, height: Floor.spriteSpec.height },
|
||||
),
|
||||
Floor.spriteSpec.frames
|
||||
)
|
||||
);
|
||||
|
||||
this.addComponent(new TopCollidable());
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Entity, EntityNames } from ".";
|
||||
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config";
|
||||
import { Entity, EntityNames } from '.';
|
||||
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from '../config';
|
||||
import {
|
||||
Jump,
|
||||
FacingDirection,
|
||||
@ -12,16 +12,16 @@ import {
|
||||
Collide,
|
||||
Control,
|
||||
Mass,
|
||||
Moment,
|
||||
} from "../components";
|
||||
import { Direction } from "../interfaces";
|
||||
Moment
|
||||
} from '../components';
|
||||
import { Direction } from '../interfaces';
|
||||
|
||||
export class Player extends Entity {
|
||||
private static MASS: number = 10;
|
||||
private static MOI: number = 100;
|
||||
|
||||
private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
|
||||
Sprites.COFFEE,
|
||||
Sprites.COFFEE
|
||||
) as SpriteSpec;
|
||||
|
||||
constructor(playerId: string) {
|
||||
@ -31,15 +31,15 @@ export class Player extends Entity {
|
||||
new BoundingBox(
|
||||
{
|
||||
x: 300,
|
||||
y: 100,
|
||||
y: 100
|
||||
},
|
||||
{ width: Player.spriteSpec.width, height: Player.spriteSpec.height },
|
||||
0,
|
||||
),
|
||||
0
|
||||
)
|
||||
);
|
||||
|
||||
this.addComponent(
|
||||
new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }),
|
||||
new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 })
|
||||
);
|
||||
|
||||
this.addComponent(new Mass(Player.MASS));
|
||||
@ -64,8 +64,8 @@ export class Player extends Entity {
|
||||
{ x: 0, y: 0 },
|
||||
{ width: Player.spriteSpec.width, height: Player.spriteSpec.height },
|
||||
Player.spriteSpec.msPerFrame,
|
||||
Player.spriteSpec.frames,
|
||||
),
|
||||
Player.spriteSpec.frames
|
||||
)
|
||||
);
|
||||
|
||||
this.addComponent(new FacingDirection(leftSprite, rightSprite));
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from "./Entity";
|
||||
export * from "./Floor";
|
||||
export * from "./Player";
|
||||
export * from "./names";
|
||||
export * from './Entity';
|
||||
export * from './Floor';
|
||||
export * from './Player';
|
||||
export * from './names';
|
||||
|
@ -1,4 +1,4 @@
|
||||
export namespace EntityNames {
|
||||
export const Player = "Player";
|
||||
export const Floor = "Floor";
|
||||
export const Player = 'Player';
|
||||
export const Floor = 'Floor';
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export enum Action {
|
||||
MOVE_LEFT,
|
||||
MOVE_RIGHT,
|
||||
JUMP,
|
||||
JUMP
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
export enum Direction {
|
||||
UP = "UP",
|
||||
DOWN = "DOWN",
|
||||
LEFT = "LEFT",
|
||||
RIGHT = "RIGHT",
|
||||
UP = 'UP',
|
||||
DOWN = 'DOWN',
|
||||
LEFT = 'LEFT',
|
||||
RIGHT = 'RIGHT'
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Coord2D, Dimension2D } from "./";
|
||||
import type { Coord2D, Dimension2D } from './';
|
||||
|
||||
export interface DrawArgs {
|
||||
center: Coord2D;
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from "./Vec2";
|
||||
export * from "./Draw";
|
||||
export * from "./Direction";
|
||||
export * from "./Action";
|
||||
export * from './Vec2';
|
||||
export * from './Draw';
|
||||
export * from './Direction';
|
||||
export * from './Action';
|
||||
|
@ -1,7 +1,7 @@
|
||||
export enum MessageType {
|
||||
NEW_ENTITY = "NEW_ENTITY",
|
||||
REMOVE_ENTITY = "REMOVE_ENTITY",
|
||||
UPDATE_ENTITY = "UPDATE_ENTITY",
|
||||
NEW_ENTITIES = 'NEW_ENTITIES',
|
||||
REMOVE_ENTITIES = 'REMOVE_ENTITIES',
|
||||
UPDATE_ENTITY = 'UPDATE_ENTITY'
|
||||
}
|
||||
|
||||
export type EntityAddBody = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { Coord2D, Dimension2D } from "../interfaces";
|
||||
import type { BoxedEntry, RefreshingCollisionFinderBehavior } from ".";
|
||||
import { Miscellaneous } from "../config/constants";
|
||||
import type { Coord2D, Dimension2D } from '../interfaces';
|
||||
import type { BoxedEntry, RefreshingCollisionFinderBehavior } from '.';
|
||||
import { Miscellaneous } from '../config/constants';
|
||||
|
||||
export class Grid implements RefreshingCollisionFinderBehavior {
|
||||
private cellEntities: Map<number, string[]>;
|
||||
@ -12,11 +12,11 @@ export class Grid implements RefreshingCollisionFinderBehavior {
|
||||
constructor(
|
||||
gridDimension: Dimension2D = {
|
||||
width: Miscellaneous.WIDTH,
|
||||
height: Miscellaneous.HEIGHT,
|
||||
height: Miscellaneous.HEIGHT
|
||||
},
|
||||
cellDimension: Dimension2D = {
|
||||
width: Miscellaneous.DEFAULT_GRID_WIDTH,
|
||||
height: Miscellaneous.DEFAULT_GRID_HEIGHT,
|
||||
height: Miscellaneous.DEFAULT_GRID_HEIGHT
|
||||
},
|
||||
topLeft = { x: 0, y: 0 }
|
||||
) {
|
||||
@ -73,7 +73,7 @@ export class Grid implements RefreshingCollisionFinderBehavior {
|
||||
|
||||
const translated: Coord2D = {
|
||||
y: center.y - this.topLeft.y,
|
||||
x: center.x - this.topLeft.x,
|
||||
x: center.x - this.topLeft.x
|
||||
};
|
||||
|
||||
const topLeftBox = {
|
||||
@ -82,7 +82,7 @@ export class Grid implements RefreshingCollisionFinderBehavior {
|
||||
),
|
||||
y: Math.floor(
|
||||
(translated.y - dimension.height / 2) / this.cellDimension.height
|
||||
),
|
||||
)
|
||||
};
|
||||
const bottomRightBox = {
|
||||
x: Math.floor(
|
||||
@ -90,7 +90,7 @@ export class Grid implements RefreshingCollisionFinderBehavior {
|
||||
),
|
||||
y: Math.floor(
|
||||
(translated.y + dimension.height / 2) / this.cellDimension.height
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
const cells: number[] = [];
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type { Coord2D, Dimension2D } from "../interfaces";
|
||||
import type { BoxedEntry, RefreshingCollisionFinderBehavior } from ".";
|
||||
import type { Coord2D, Dimension2D } from '../interfaces';
|
||||
import type { BoxedEntry, RefreshingCollisionFinderBehavior } from '.';
|
||||
|
||||
enum Quadrant {
|
||||
I,
|
||||
II,
|
||||
III,
|
||||
IV,
|
||||
IV
|
||||
}
|
||||
|
||||
/*
|
||||
@ -102,8 +102,8 @@ export class QuadTree implements RefreshingCollisionFinderBehavior {
|
||||
[Quadrant.III, { x: this.topLeft.x, y: this.topLeft.y + halfHeight }],
|
||||
[
|
||||
Quadrant.IV,
|
||||
{ x: this.topLeft.x + halfWidth, y: this.topLeft.y + halfHeight },
|
||||
],
|
||||
{ x: this.topLeft.x + halfWidth, y: this.topLeft.y + halfHeight }
|
||||
]
|
||||
] as [Quadrant, Coord2D][]
|
||||
).forEach(([quadrant, pos]) => {
|
||||
this.children.set(
|
||||
@ -122,27 +122,27 @@ export class QuadTree implements RefreshingCollisionFinderBehavior {
|
||||
private getQuadrants(boxedEntry: BoxedEntry): Quadrant[] {
|
||||
const treeCenter: Coord2D = {
|
||||
x: this.topLeft.x + this.dimension.width / 2,
|
||||
y: this.topLeft.y + this.dimension.height / 2,
|
||||
y: this.topLeft.y + this.dimension.height / 2
|
||||
};
|
||||
|
||||
return (
|
||||
[
|
||||
[
|
||||
Quadrant.I,
|
||||
(x: number, y: number) => x >= treeCenter.x && y < treeCenter.y,
|
||||
(x: number, y: number) => x >= treeCenter.x && y < treeCenter.y
|
||||
],
|
||||
[
|
||||
Quadrant.II,
|
||||
(x: number, y: number) => x < treeCenter.x && y < treeCenter.y,
|
||||
(x: number, y: number) => x < treeCenter.x && y < treeCenter.y
|
||||
],
|
||||
[
|
||||
Quadrant.III,
|
||||
(x: number, y: number) => x < treeCenter.x && y >= treeCenter.y,
|
||||
(x: number, y: number) => x < treeCenter.x && y >= treeCenter.y
|
||||
],
|
||||
[
|
||||
Quadrant.IV,
|
||||
(x: number, y: number) => x >= treeCenter.x && y >= treeCenter.y,
|
||||
],
|
||||
(x: number, y: number) => x >= treeCenter.x && y >= treeCenter.y
|
||||
]
|
||||
] as [Quadrant, (x: number, y: number) => boolean][]
|
||||
)
|
||||
.filter(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Coord2D, Dimension2D } from "../interfaces";
|
||||
import type { Coord2D, Dimension2D } from '../interfaces';
|
||||
|
||||
export interface BoxedEntry {
|
||||
id: string;
|
||||
@ -7,8 +7,8 @@ export interface BoxedEntry {
|
||||
}
|
||||
|
||||
export interface RefreshingCollisionFinderBehavior {
|
||||
public clear(): void;
|
||||
public insert(boxedEntry: BoxedEntry): void;
|
||||
public getNeighborIds(boxedEntry: BoxedEntry): Set<string>;
|
||||
public setTopLeft(topLeft: Coord2d): void;
|
||||
clear(): void;
|
||||
insert(boxedEntry: BoxedEntry): void;
|
||||
getNeighborIds(boxedEntry: BoxedEntry): Set<string>;
|
||||
setTopLeft(topLeft: Coord2D): void;
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
export * from "./RefreshingCollisionFinderBehavior";
|
||||
export * from "./QuadTree";
|
||||
export * from "./Grid";
|
||||
export * from './RefreshingCollisionFinderBehavior';
|
||||
export * from './QuadTree';
|
||||
export * from './Grid';
|
||||
|
@ -1,22 +1,22 @@
|
||||
import { SystemNames, System } from ".";
|
||||
import { SystemNames, System } from '.';
|
||||
import {
|
||||
Mass,
|
||||
BoundingBox,
|
||||
ComponentNames,
|
||||
Jump,
|
||||
Velocity,
|
||||
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";
|
||||
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 collisionFinder: RefreshingCollisionFinderBehavior;
|
||||
@ -38,7 +38,7 @@ export class Collision extends System {
|
||||
return;
|
||||
}
|
||||
entitiesToAddToCollisionFinder.push(entity);
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
this.insertEntitiesAndUpdateBounds(entitiesToAddToCollisionFinder);
|
||||
@ -53,7 +53,7 @@ export class Collision extends System {
|
||||
|
||||
entities.forEach((entity) => {
|
||||
const boundingBox = entity.getComponent<BoundingBox>(
|
||||
ComponentNames.BoundingBox,
|
||||
ComponentNames.BoundingBox
|
||||
);
|
||||
|
||||
let dimension = { ...boundingBox.dimension };
|
||||
@ -73,7 +73,7 @@ export class Collision extends System {
|
||||
collisionFinderInsertions.push({
|
||||
id: entity.id,
|
||||
dimension,
|
||||
center,
|
||||
center
|
||||
});
|
||||
});
|
||||
|
||||
@ -82,13 +82,13 @@ export class Collision extends System {
|
||||
this.collisionFinder.setTopLeft(topLeft);
|
||||
this.collisionFinder.setDimension({
|
||||
width: bottomRight.x - topLeft.x,
|
||||
height: bottomRight.y - topLeft.y,
|
||||
height: bottomRight.y - topLeft.y
|
||||
});
|
||||
}
|
||||
|
||||
// then, begin insertions
|
||||
collisionFinderInsertions.forEach((boxedEntry: BoxedEntry) =>
|
||||
this.collisionFinder.insert(boxedEntry),
|
||||
this.collisionFinder.insert(boxedEntry)
|
||||
);
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ export class Collision extends System {
|
||||
|
||||
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);
|
||||
@ -107,13 +107,13 @@ 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: Velocity2D = { dCartesian: { dx: 0, dy: 0 }, dTheta: 0 };
|
||||
if (entityA.hasComponent(ComponentNames.Velocity)) {
|
||||
velocity = entityA.getComponent<Velocity>(
|
||||
ComponentNames.Velocity,
|
||||
ComponentNames.Velocity
|
||||
).velocity;
|
||||
}
|
||||
|
||||
@ -125,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.`
|
||||
);
|
||||
}
|
||||
|
||||
@ -139,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
|
||||
});
|
||||
}
|
||||
|
||||
@ -157,19 +157,19 @@ export class Collision extends System {
|
||||
|
||||
private getCollidingEntities(
|
||||
collidableEntities: Entity[],
|
||||
game: Game,
|
||||
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.collisionFinder.getNeighborIds({
|
||||
id: entity.id,
|
||||
dimension: boundingBox.dimension,
|
||||
center: boundingBox.center,
|
||||
center: boundingBox.center
|
||||
});
|
||||
|
||||
for (const neighborId of neighborIds) {
|
||||
@ -177,7 +177,7 @@ export class Collision extends System {
|
||||
if (!neighbor) return;
|
||||
|
||||
const neighborBoundingBox = neighbor.getComponent<BoundingBox>(
|
||||
ComponentNames.BoundingBox,
|
||||
ComponentNames.BoundingBox
|
||||
);
|
||||
|
||||
if (boundingBox.isCollidingWith(neighborBoundingBox)) {
|
||||
@ -192,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();
|
||||
@ -215,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 -
|
||||
@ -225,7 +225,7 @@ export class Collision extends System {
|
||||
|
||||
boundedCollisionX = Math.max(
|
||||
floorBoundingBox.center.x - floorBoundingBox.dimension.width / 2,
|
||||
clippedX,
|
||||
clippedX
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -2,10 +2,10 @@ import {
|
||||
ComponentNames,
|
||||
Velocity,
|
||||
FacingDirection as FacingDirectionComponent,
|
||||
Control,
|
||||
} from "../components";
|
||||
import { Game } from "../Game";
|
||||
import { System, SystemNames } from "./";
|
||||
Control
|
||||
} from '../components';
|
||||
import { Game } from '../Game';
|
||||
import { System, SystemNames } from './';
|
||||
|
||||
export class FacingDirection extends System {
|
||||
constructor() {
|
||||
@ -23,7 +23,7 @@ export class FacingDirection extends System {
|
||||
const totalVelocityComponent = new Velocity();
|
||||
const control = entity.getComponent<Control>(ComponentNames.Control);
|
||||
const velocity = entity.getComponent<Velocity>(
|
||||
ComponentNames.Velocity,
|
||||
ComponentNames.Velocity
|
||||
).velocity;
|
||||
|
||||
totalVelocityComponent.add(velocity);
|
||||
@ -32,7 +32,7 @@ export class FacingDirection extends System {
|
||||
}
|
||||
|
||||
const facingDirection = entity.getComponent<FacingDirectionComponent>(
|
||||
ComponentNames.FacingDirection,
|
||||
ComponentNames.FacingDirection
|
||||
);
|
||||
|
||||
if (totalVelocityComponent.velocity.dCartesian.dx > 0) {
|
||||
@ -40,7 +40,7 @@ export class FacingDirection extends System {
|
||||
} else if (totalVelocityComponent.velocity.dCartesian.dx < 0) {
|
||||
entity.addComponent(facingDirection.facingLeftSprite);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,12 @@ import {
|
||||
ComponentNames,
|
||||
Velocity,
|
||||
Mass,
|
||||
Control,
|
||||
} from "../components";
|
||||
import { Game } from "../Game";
|
||||
import { KeyConstants, PhysicsConstants } from "../config";
|
||||
import { Action } from "../interfaces";
|
||||
import { System, SystemNames } from ".";
|
||||
Control
|
||||
} from '../components';
|
||||
import { Game } from '../Game';
|
||||
import { KeyConstants, PhysicsConstants } from '../config';
|
||||
import { Action } from '../interfaces';
|
||||
import { System, SystemNames } from '.';
|
||||
|
||||
export class Input extends System {
|
||||
public clientId: string;
|
||||
@ -42,7 +42,7 @@ export class Input extends System {
|
||||
public update(_dt: number, game: Game) {
|
||||
game.forEachEntityWithComponent(ComponentNames.Control, (entity) => {
|
||||
const controlComponent = entity.getComponent<Control>(
|
||||
ComponentNames.Control,
|
||||
ComponentNames.Control
|
||||
);
|
||||
if (controlComponent.controllableBy != this.clientId) return;
|
||||
|
||||
@ -58,7 +58,7 @@ export class Input extends System {
|
||||
|
||||
if (entity.hasComponent(ComponentNames.Jump)) {
|
||||
const velocity = entity.getComponent<Velocity>(
|
||||
ComponentNames.Velocity,
|
||||
ComponentNames.Velocity
|
||||
).velocity;
|
||||
const jump = entity.getComponent<Jump>(ComponentNames.Jump);
|
||||
|
||||
@ -78,9 +78,9 @@ export class Input extends System {
|
||||
entity.getComponent<Forces>(ComponentNames.Forces)?.forces.push({
|
||||
fCartesian: {
|
||||
fy: mass * PhysicsConstants.PLAYER_JUMP_ACC,
|
||||
fx: 0,
|
||||
fx: 0
|
||||
},
|
||||
torque: 0,
|
||||
torque: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { System, SystemNames } from ".";
|
||||
import { Game } from "../Game";
|
||||
import { ComponentNames, NetworkUpdateable } from "../components";
|
||||
import { System, SystemNames } from '.';
|
||||
import { Game } from '../Game';
|
||||
import { ComponentNames, NetworkUpdateable } from '../components';
|
||||
import {
|
||||
type MessageQueueProvider,
|
||||
type MessagePublisher,
|
||||
type MessageProcessor,
|
||||
} from "../network";
|
||||
type MessageProcessor
|
||||
} from '../network';
|
||||
|
||||
export class NetworkUpdate extends System {
|
||||
private queueProvider: MessageQueueProvider;
|
||||
@ -15,7 +15,7 @@ export class NetworkUpdate extends System {
|
||||
constructor(
|
||||
queueProvider: MessageQueueProvider,
|
||||
publisher: MessagePublisher,
|
||||
messageProcessor: MessageProcessor,
|
||||
messageProcessor: MessageProcessor
|
||||
) {
|
||||
super(SystemNames.NetworkUpdate);
|
||||
|
||||
@ -34,9 +34,9 @@ export class NetworkUpdate extends System {
|
||||
ComponentNames.NetworkUpdateable,
|
||||
(entity) => {
|
||||
const networkUpdateComponent = entity.getComponent<NetworkUpdateable>(
|
||||
ComponentNames.NetworkUpdateable,
|
||||
ComponentNames.NetworkUpdateable
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
this.publisher.publish();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { System, SystemNames } from ".";
|
||||
import { System, SystemNames } from '.';
|
||||
import {
|
||||
BoundingBox,
|
||||
ComponentNames,
|
||||
@ -8,11 +8,11 @@ import {
|
||||
Mass,
|
||||
Jump,
|
||||
Moment,
|
||||
Control,
|
||||
} from "../components";
|
||||
import { PhysicsConstants } from "../config";
|
||||
import type { Force2D, Velocity2D } from "../interfaces";
|
||||
import { Game } from "../Game";
|
||||
Control
|
||||
} from '../components';
|
||||
import { PhysicsConstants } from '../config';
|
||||
import type { Force2D, Velocity2D } from '../interfaces';
|
||||
import { Game } from '../Game';
|
||||
|
||||
export class Physics extends System {
|
||||
constructor() {
|
||||
@ -24,10 +24,10 @@ export class Physics extends System {
|
||||
const mass = entity.getComponent<Mass>(ComponentNames.Mass).mass;
|
||||
const forces = entity.getComponent<Forces>(ComponentNames.Forces).forces;
|
||||
const velocity = entity.getComponent<Velocity>(
|
||||
ComponentNames.Velocity,
|
||||
ComponentNames.Velocity
|
||||
).velocity;
|
||||
const inertia = entity.getComponent<Moment>(
|
||||
ComponentNames.Moment,
|
||||
ComponentNames.Moment
|
||||
).inertia;
|
||||
|
||||
// F_g = mg, applied only until terminal velocity is reached
|
||||
@ -37,9 +37,9 @@ export class Physics extends System {
|
||||
forces.push({
|
||||
fCartesian: {
|
||||
fy: mass * PhysicsConstants.GRAVITY,
|
||||
fx: 0,
|
||||
fx: 0
|
||||
},
|
||||
torque: 0,
|
||||
torque: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -49,17 +49,17 @@ export class Physics extends System {
|
||||
(accum: Force2D, { fCartesian, torque }: Force2D) => ({
|
||||
fCartesian: {
|
||||
fx: accum.fCartesian.fx + (fCartesian?.fx ?? 0),
|
||||
fy: accum.fCartesian.fy + (fCartesian?.fy ?? 0),
|
||||
fy: accum.fCartesian.fy + (fCartesian?.fy ?? 0)
|
||||
},
|
||||
torque: accum.torque + (torque ?? 0),
|
||||
torque: accum.torque + (torque ?? 0)
|
||||
}),
|
||||
{ fCartesian: { fx: 0, fy: 0 }, torque: 0 },
|
||||
{ fCartesian: { fx: 0, fy: 0 }, torque: 0 }
|
||||
);
|
||||
|
||||
// integrate accelerations
|
||||
const [ddy, ddx] = [
|
||||
sumOfForces.fCartesian.fy,
|
||||
sumOfForces.fCartesian.fx,
|
||||
sumOfForces.fCartesian.fx
|
||||
].map((x) => x / mass);
|
||||
velocity.dCartesian.dx += ddx * dt;
|
||||
velocity.dCartesian.dy += ddy * dt;
|
||||
@ -79,14 +79,14 @@ export class Physics extends System {
|
||||
const control = entity.getComponent<Control>(ComponentNames.Control);
|
||||
|
||||
velocityComponent.add(
|
||||
entity.getComponent<Velocity>(ComponentNames.Velocity).velocity,
|
||||
entity.getComponent<Velocity>(ComponentNames.Velocity).velocity
|
||||
);
|
||||
if (control) {
|
||||
velocityComponent.add(control.controlVelocityComponent.velocity);
|
||||
}
|
||||
|
||||
const boundingBox = entity.getComponent<BoundingBox>(
|
||||
ComponentNames.BoundingBox,
|
||||
ComponentNames.BoundingBox
|
||||
);
|
||||
|
||||
// integrate velocity
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { System, SystemNames } from ".";
|
||||
import { BoundingBox, ComponentNames, Sprite } from "../components";
|
||||
import { Game } from "../Game";
|
||||
import { clamp } from "../utils";
|
||||
import { System, SystemNames } from '.';
|
||||
import { BoundingBox, ComponentNames, Sprite } from '../components';
|
||||
import { Game } from '../Game';
|
||||
import { clamp } from '../utils';
|
||||
|
||||
export class Render extends System {
|
||||
private ctx: CanvasRenderingContext2D;
|
||||
@ -19,7 +19,7 @@ export class Render extends System {
|
||||
sprite.update(dt);
|
||||
|
||||
const boundingBox = entity.getComponent<BoundingBox>(
|
||||
ComponentNames.BoundingBox,
|
||||
ComponentNames.BoundingBox
|
||||
);
|
||||
|
||||
// don't render if we're outside the screen
|
||||
@ -27,12 +27,12 @@ export class Render extends System {
|
||||
clamp(
|
||||
boundingBox.center.y,
|
||||
-boundingBox.dimension.height / 2,
|
||||
this.ctx.canvas.height + boundingBox.dimension.height / 2,
|
||||
this.ctx.canvas.height + boundingBox.dimension.height / 2
|
||||
) != boundingBox.center.y ||
|
||||
clamp(
|
||||
boundingBox.center.x,
|
||||
-boundingBox.dimension.width / 2,
|
||||
this.ctx.canvas.width + boundingBox.dimension.width / 2,
|
||||
this.ctx.canvas.width + boundingBox.dimension.width / 2
|
||||
) != boundingBox.center.x
|
||||
) {
|
||||
return;
|
||||
@ -41,7 +41,7 @@ export class Render extends System {
|
||||
const drawArgs = {
|
||||
center: boundingBox.center,
|
||||
dimension: boundingBox.dimension,
|
||||
rotation: boundingBox.rotation,
|
||||
rotation: boundingBox.rotation
|
||||
};
|
||||
|
||||
sprite.draw(this.ctx, drawArgs);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Game } from "../Game";
|
||||
import { Game } from '../Game';
|
||||
|
||||
export abstract class System {
|
||||
public readonly name: string;
|
||||
|
@ -1,28 +1,24 @@
|
||||
import { System, SystemNames } from ".";
|
||||
import { BoundingBox, ComponentNames } from "../components";
|
||||
import { Game } from "../Game";
|
||||
import type { Entity } from "../entities";
|
||||
import { clamp } from "../utils";
|
||||
import { System, SystemNames } from '.';
|
||||
import { BoundingBox, ComponentNames } from '../components';
|
||||
import { Game } from '../Game';
|
||||
import { clamp } from '../utils';
|
||||
import { Miscellaneous } from '../config';
|
||||
|
||||
export class WallBounds extends System {
|
||||
private screenWidth: number;
|
||||
|
||||
constructor(screenWidth: number) {
|
||||
constructor() {
|
||||
super(SystemNames.WallBounds);
|
||||
|
||||
this.screenWidth = screenWidth;
|
||||
}
|
||||
|
||||
public update(_dt: number, game: Game) {
|
||||
game.forEachEntityWithComponent(ComponentNames.WallBounded, (entity) => {
|
||||
const boundingBox = entity.getComponent<BoundingBox>(
|
||||
ComponentNames.BoundingBox,
|
||||
ComponentNames.BoundingBox
|
||||
);
|
||||
|
||||
boundingBox.center.x = clamp(
|
||||
boundingBox.center.x,
|
||||
boundingBox.dimension.width / 2,
|
||||
this.screenWidth - boundingBox.dimension.width / 2,
|
||||
Miscellaneous.WIDTH - boundingBox.dimension.width / 2
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
export * from "./names";
|
||||
export * from "./System";
|
||||
export * from "./Render";
|
||||
export * from "./Physics";
|
||||
export * from "./Input";
|
||||
export * from "./FacingDirection";
|
||||
export * from "./Collision";
|
||||
export * from "./WallBounds";
|
||||
export * from "./NetworkUpdate";
|
||||
export * from './names';
|
||||
export * from './System';
|
||||
export * from './Render';
|
||||
export * from './Physics';
|
||||
export * from './Input';
|
||||
export * from './FacingDirection';
|
||||
export * from './Collision';
|
||||
export * from './WallBounds';
|
||||
export * from './NetworkUpdate';
|
||||
|
@ -1,9 +1,9 @@
|
||||
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";
|
||||
export const NetworkUpdate = "NetworkUpdate";
|
||||
export const Render = 'Render';
|
||||
export const Physics = 'Physics';
|
||||
export const FacingDirection = 'FacingDirection';
|
||||
export const Input = 'Input';
|
||||
export const Collision = 'Collision';
|
||||
export const WallBounds = 'WallBounds';
|
||||
export const NetworkUpdate = 'NetworkUpdate';
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
const replacer = (_key: any, value: any) => {
|
||||
if (value instanceof Map) {
|
||||
return {
|
||||
dataType: "Map",
|
||||
value: Array.from(value.entries()),
|
||||
dataType: 'Map',
|
||||
value: Array.from(value.entries())
|
||||
};
|
||||
} else {
|
||||
return value;
|
||||
@ -10,8 +10,8 @@ const replacer = (_key: any, value: any) => {
|
||||
};
|
||||
|
||||
const reviver = (_key: any, value: any) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (value.dataType === "Map") {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (value.dataType === 'Map') {
|
||||
return new Map(value.value);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Coord2D } from "../interfaces";
|
||||
import type { Coord2D } from '../interfaces';
|
||||
|
||||
export const dotProduct = (vector1: Coord2D, vector2: Coord2D): number =>
|
||||
vector1.x * vector2.x + vector1.y * vector2.y;
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from "./rotateVector";
|
||||
export * from "./dotProduct";
|
||||
export * from "./clamp";
|
||||
export * from "./coding";
|
||||
export * from './rotateVector';
|
||||
export * from './dotProduct';
|
||||
export * from './clamp';
|
||||
export * from './coding';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Coord2D } from "../interfaces";
|
||||
import type { Coord2D } from '../interfaces';
|
||||
|
||||
/**
|
||||
* ([[cos(θ), -sin(θ),]) ([x,)
|
||||
@ -10,6 +10,6 @@ export const rotateVector = (vector: Coord2D, theta: number): Coord2D => {
|
||||
|
||||
return {
|
||||
x: vector.x * cos - vector.y * sin,
|
||||
y: vector.x * sin + vector.y * cos,
|
||||
y: vector.x * sin + vector.y * cos
|
||||
};
|
||||
};
|
||||
|
@ -8,6 +8,5 @@
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
}
|
||||
"dependencies": {}
|
||||
}
|
||||
|
@ -1,21 +1,22 @@
|
||||
import { Game } from "@engine/Game";
|
||||
import { EntityNames, Player } from "@engine/entities";
|
||||
import { WallBounds, Physics, Collision, NetworkUpdate } from "@engine/systems";
|
||||
import { Game } from '@engine/Game';
|
||||
import { EntityNames, Player } from '@engine/entities';
|
||||
import { WallBounds, Physics, Collision, NetworkUpdate } from '@engine/systems';
|
||||
import {
|
||||
type MessageQueueProvider,
|
||||
type MessagePublisher,
|
||||
MessageType,
|
||||
type MessageProcessor,
|
||||
type Message,
|
||||
} from "@engine/network";
|
||||
import { stringify, parse } from "@engine/utils";
|
||||
import { Grid } from "@engine/structures";
|
||||
import { Miscellaneous } from "@engine/config";
|
||||
import { Server } from "bun";
|
||||
type Message
|
||||
} from '@engine/network';
|
||||
import { stringify, parse } from '@engine/utils';
|
||||
import { Grid } from '@engine/structures';
|
||||
import { Miscellaneous } from '@engine/config';
|
||||
import { Server } from 'bun';
|
||||
|
||||
const SERVER_PORT = 8080;
|
||||
const SERVER_TICK_RATE = (1 / 100) * 1000;
|
||||
const GAME_TOPIC = "game";
|
||||
const SERVER_TICK_RATE = (1 / 60) * 1000;
|
||||
const GAME_TOPIC = 'game';
|
||||
const MAX_PLAYERS = 8;
|
||||
|
||||
type SessionData = { sessionId: string };
|
||||
|
||||
@ -70,12 +71,12 @@ class ServerSocketMessagePublisher implements MessagePublisher {
|
||||
}
|
||||
|
||||
public publish() {
|
||||
this.messages.forEach(
|
||||
(message) => this.server?.publish(GAME_TOPIC, stringify(message)),
|
||||
);
|
||||
if (this.messages.length) {
|
||||
this.server?.publish(GAME_TOPIC, stringify(this.messages));
|
||||
|
||||
this.messages = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const game = new Game();
|
||||
@ -85,81 +86,102 @@ const messagePublisher = new ServerSocketMessagePublisher();
|
||||
const messageProcessor = new ServerMessageProcessor();
|
||||
const sessionControllableEntities: Map<string, Set<string>> = new Map();
|
||||
|
||||
const sessions = new Set<string>();
|
||||
|
||||
const server = Bun.serve<SessionData>({
|
||||
port: SERVER_PORT,
|
||||
fetch: async (req, server): Promise<Response> => {
|
||||
const url = new URL(req.url);
|
||||
|
||||
const headers = new Headers();
|
||||
headers.set("Access-Control-Allow-Origin", "*");
|
||||
headers.set('Access-Control-Allow-Origin', '*');
|
||||
|
||||
if (url.pathname == '/assign') {
|
||||
if (sessions.size > MAX_PLAYERS)
|
||||
return new Response('too many players', { headers, status: 400 });
|
||||
|
||||
if (url.pathname == "/assign") {
|
||||
const sessionId = crypto.randomUUID();
|
||||
headers.set("Set-Cookie", `SessionId=${sessionId};`);
|
||||
headers.set('Set-Cookie', `SessionId=${sessionId};`);
|
||||
|
||||
sessions.add(sessionId);
|
||||
|
||||
return new Response(sessionId, { headers });
|
||||
}
|
||||
|
||||
const cookie = req.headers.get("cookie");
|
||||
const cookie = req.headers.get('cookie');
|
||||
if (!cookie) {
|
||||
return new Response("No session", { headers, status: 401 });
|
||||
return new Response('No session', { headers, status: 401 });
|
||||
}
|
||||
|
||||
const sessionId = cookie.split(";").at(0)!.split("SessionId=").at(1);
|
||||
const sessionId = cookie.split(';').at(0)!.split('SessionId=').at(1);
|
||||
|
||||
if (url.pathname == "/game") {
|
||||
if (url.pathname == '/game') {
|
||||
headers.set(
|
||||
"Set-Cookie",
|
||||
`SessionId=${sessionId}; HttpOnly; SameSite=Strict;`,
|
||||
'Set-Cookie',
|
||||
`SessionId=${sessionId}; HttpOnly; SameSite=Strict;`
|
||||
);
|
||||
server.upgrade(req, {
|
||||
headers,
|
||||
data: {
|
||||
sessionId,
|
||||
},
|
||||
sessionId
|
||||
}
|
||||
});
|
||||
|
||||
return new Response("upgraded", { headers });
|
||||
return new Response('upgraded', { headers });
|
||||
}
|
||||
if (url.pathname == "/me") {
|
||||
|
||||
if (url.pathname == '/me') {
|
||||
return new Response(sessionId, { headers });
|
||||
}
|
||||
|
||||
return new Response("Not found", { headers, status: 404 });
|
||||
return new Response('Not found', { headers, status: 404 });
|
||||
},
|
||||
websocket: {
|
||||
open(ws) {
|
||||
const { sessionId } = ws.data;
|
||||
|
||||
if (sessionControllableEntities.has(sessionId)) {
|
||||
// no need to add player
|
||||
return;
|
||||
}
|
||||
|
||||
const player = new Player(sessionId);
|
||||
game.addEntity(player);
|
||||
sessionControllableEntities.set(sessionId, new Set(player.id));
|
||||
sessionControllableEntities.set(sessionId, new Set([player.id]));
|
||||
|
||||
messagePublisher.addMessage({
|
||||
type: MessageType.NEW_ENTITY,
|
||||
body: {
|
||||
type: MessageType.NEW_ENTITIES,
|
||||
body: [
|
||||
{
|
||||
entityName: EntityNames.Player,
|
||||
args: { playerId: sessionId },
|
||||
},
|
||||
args: { playerId: sessionId, id: player.id }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ws.subscribe(GAME_TOPIC);
|
||||
},
|
||||
message(ws, message) {
|
||||
if (typeof message == "string") {
|
||||
if (typeof message == 'string') {
|
||||
const receivedMessage = parse<ServerMessage>(message);
|
||||
receivedMessage.sessionData = ws.data;
|
||||
|
||||
messageReceiver.addMessage(receivedMessage);
|
||||
}
|
||||
},
|
||||
close(_ws) {},
|
||||
},
|
||||
close(ws) {
|
||||
const { sessionId } = ws.data;
|
||||
|
||||
sessions.delete(sessionId);
|
||||
|
||||
const sessionEntities = sessionControllableEntities.get(sessionId);
|
||||
if (!sessionEntities) return;
|
||||
|
||||
messagePublisher.addMessage({
|
||||
type: MessageType.REMOVE_ENTITIES,
|
||||
body: Array.from(sessionEntities)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
messagePublisher.setServer(server);
|
||||
@ -167,8 +189,8 @@ messagePublisher.setServer(server);
|
||||
[
|
||||
new Physics(),
|
||||
new Collision(new Grid()),
|
||||
new WallBounds(Miscellaneous.WIDTH),
|
||||
new NetworkUpdate(messageReceiver, messagePublisher, messageProcessor),
|
||||
new WallBounds(),
|
||||
new NetworkUpdate(messageReceiver, messagePublisher, messageProcessor)
|
||||
].forEach((system) => game.addSystem(system));
|
||||
|
||||
game.start();
|
||||
|
Loading…
Reference in New Issue
Block a user