prettier formatting

This commit is contained in:
Elizabeth Hunt 2023-08-25 16:48:17 -06:00
parent dec7b614d8
commit 773ce84f4b
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
65 changed files with 429 additions and 391 deletions

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "none"
}

View File

@ -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'
},
}
};

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />

View File

@ -10,7 +10,7 @@
--orange: #af3a03;
}
[data-theme="dark"] {
[data-theme='dark'] {
--bg: #282828;
--text: #f9f5d7;
--red: #fb4934;

View File

@ -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;
}

View File

@ -17,7 +17,7 @@
rgba(162, 254, 254, 1) 100%
);
content: "";
content: '';
width: 100%;
height: 100%;
top: 0;

View File

@ -1,4 +1,4 @@
@import url("./colors.css");
@import url('./colors.css');
.primary {
color: var(--aqua);

View File

@ -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;
}

View File

@ -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>

View File

@ -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">

View File

@ -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;

View File

@ -6,7 +6,6 @@
let width: number = Miscellaneous.WIDTH;
let height: number = Miscellaneous.HEIGHT;
</script>
<div class="centered-game">

View File

@ -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()
};

View File

@ -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))
}
}
});

View File

@ -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) => {

View File

@ -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
};
}
}

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class Collide extends Component {
constructor() {

View File

@ -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);

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames, Sprite } from ".";
import { Component, ComponentNames, Sprite } from '.';
export class FacingDirection extends Component {
public readonly facingLeftSprite: Sprite;

View File

@ -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)

View File

@ -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;

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class Jump extends Component {
public canJump: boolean;

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class Mass extends Component {
public mass: number;

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class Moment extends Component {
public inertia: number;

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class NetworkUpdateable extends Component {
public isPublish: boolean;

View File

@ -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;
}
}

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class TopCollidable extends Component {
constructor() {

View File

@ -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);

View File

@ -1,4 +1,4 @@
import { Component, ComponentNames } from ".";
import { Component, ComponentNames } from '.';
export class WallBounded extends Component {
constructor() {

View File

@ -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';

View File

@ -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';
}

View File

@ -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
]);

View File

@ -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];

View File

@ -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';

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -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());

View File

@ -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));

View File

@ -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';

View File

@ -1,4 +1,4 @@
export namespace EntityNames {
export const Player = "Player";
export const Floor = "Floor";
export const Player = 'Player';
export const Floor = 'Floor';
}

View File

@ -1,5 +1,5 @@
export enum Action {
MOVE_LEFT,
MOVE_RIGHT,
JUMP,
JUMP
}

View File

@ -1,6 +1,6 @@
export enum Direction {
UP = "UP",
DOWN = "DOWN",
LEFT = "LEFT",
RIGHT = "RIGHT",
UP = 'UP',
DOWN = 'DOWN',
LEFT = 'LEFT',
RIGHT = 'RIGHT'
}

View File

@ -1,4 +1,4 @@
import type { Coord2D, Dimension2D } from "./";
import type { Coord2D, Dimension2D } from './';
export interface DrawArgs {
center: Coord2D;

View File

@ -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';

View File

@ -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 = {

View File

@ -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[] = [];

View File

@ -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(

View File

@ -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;
}

View File

@ -1,3 +1,3 @@
export * from "./RefreshingCollisionFinderBehavior";
export * from "./QuadTree";
export * from "./Grid";
export * from './RefreshingCollisionFinderBehavior';
export * from './QuadTree';
export * from './Grid';

View File

@ -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 (

View File

@ -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);
}
},
}
);
}
}

View File

@ -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
});
}
}

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -1,4 +1,4 @@
import { Game } from "../Game";
import { Game } from '../Game';
export abstract class System {
public readonly name: string;

View File

@ -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
);
});
}

View File

@ -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';

View File

@ -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';
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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';

View File

@ -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
};
};

View File

@ -8,6 +8,5 @@
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
}
"dependencies": {}
}

View File

@ -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,13 +71,13 @@ 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();