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