From cd75bdbfde21c57ecea2abcd4712dd8473382436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Schmelczer=20Andr=C3=A1s?= Date: Sun, 11 Oct 2020 20:32:56 +0200 Subject: [PATCH] WIP --- backend/src/main.ts | 12 --- backend/src/map/create-dungeon.ts | 76 ++++++++++------- backend/src/objects/character-physical.ts | 9 +- backend/src/objects/circle-physical.ts | 6 -- backend/src/objects/projectile-physical.ts | 61 ++++++++++++++ backend/src/physics/move-circle.ts | 82 +++++++------------ backend/src/players/player.ts | 15 +++- frontend/src/index.ts | 3 + .../commands/generators/mouse-listener.ts | 7 +- .../commands/generators/touch-listener.ts | 7 +- frontend/src/scripts/game.ts | 48 +++++++---- frontend/src/scripts/objects/lamp-view.ts | 2 +- .../src/scripts/objects/projectile-view.ts | 18 ++++ frontend/src/scripts/objects/tunnel-view.ts | 2 +- shared/src/helper/random.ts | 13 +++ shared/src/main.ts | 2 +- shared/src/objects/types/character-base.ts | 2 +- shared/src/objects/types/lamp-base.ts | 2 +- shared/src/objects/types/projectile-base.ts | 15 ++++ shared/src/objects/types/tunnel-base.ts | 2 +- 20 files changed, 253 insertions(+), 131 deletions(-) create mode 100644 backend/src/objects/projectile-physical.ts create mode 100644 frontend/src/scripts/objects/projectile-view.ts create mode 100644 shared/src/objects/types/projectile-base.ts diff --git a/backend/src/main.ts b/backend/src/main.ts index be08247..a104f8a 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -25,9 +25,6 @@ Random.seed = 42; const objects = new PhysicalContainer(); createDungeon(objects); -createDungeon(objects); -createDungeon(objects); -createDungeon(objects); objects.initialize(); @@ -99,15 +96,6 @@ const handlePhysics = () => { console.log(players.map((p) => p.latency)); } - if (deltas.length > 100) { - deltas.sort((a, b) => a - b); - console.log(`Median physics time: ${deltas[50].toFixed(2)} ms`); - console.log( - `Memory used: ${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`, - ); - deltas = []; - } - objects.sendCommand(step); players.forEach((p) => p.sendCommand(step)); diff --git a/backend/src/map/create-dungeon.ts b/backend/src/map/create-dungeon.ts index f654b71..0edef3d 100644 --- a/backend/src/map/create-dungeon.ts +++ b/backend/src/map/create-dungeon.ts @@ -1,45 +1,61 @@ import { vec2, vec3 } from 'gl-matrix'; import { Random } from 'shared'; import { LampPhysical } from '../objects/lamp-physical'; + import { TunnelPhysical } from '../objects/tunnel-physical'; import { PhysicalContainer } from '../physics/containers/physical-container'; export const createDungeon = (objects: PhysicalContainer) => { - let previousRadius = 350; - let previousEnd = vec2.create(); + const lightPositions: Array = []; - let tunnelsCountSinceLastLight = 0; - - for (let i = 0; i < 50000; i += 500) { - const deltaHeight = (Random.getRandom() - 0.5) * 500; - const height = previousEnd.y + deltaHeight; - const currentEnd = vec2.fromValues(i, height); - const currentToRadius = Random.getRandom() * 300 + 150; - - const tunnel = new TunnelPhysical( - previousEnd, - currentEnd, - previousRadius, - currentToRadius, + for (let j = 0; j < 6; j++) { + let previousRadius = 500; + let previousEnd = vec2.fromValues( + j === 0 ? 0 : Random.getRandomInRange(-1000, 1000), + j === 0 ? 0 : Random.getRandomInRange(-1000, 1000), ); + for (let i = 0; i < 500; i++) { + const delta = vec2.fromValues(j % 2 ? 1 : -1, Random.getRandomInRange(-1, 1)); - objects.addObject(tunnel); + vec2.normalize(delta, delta); + vec2.scale(delta, delta, 500); - if (++tunnelsCountSinceLastLight > 3 && Random.getRandom() > 0.7) { - objects.addObject( - new LampPhysical( - currentEnd, - vec3.normalize( - vec3.create(), - vec3.fromValues(Random.getRandom(), 0, Random.getRandom()), - ), - 0.5, - ), + const currentEnd = vec2.add(delta, delta, previousEnd); + + const currentToRadius = Random.getRandom() * 250 + 150; + + const tunnel = new TunnelPhysical( + previousEnd, + currentEnd, + previousRadius, + currentToRadius, ); - tunnelsCountSinceLastLight = 0; - } - previousEnd = currentEnd; - previousRadius = currentToRadius; + objects.addObject(tunnel); + + if (Random.getRandom() > 0.7) { + const position = currentEnd; + if (!lightPositions.find((p) => vec2.dist(p, position) < 2000)) { + lightPositions.push(position); + objects.addObject( + new LampPhysical( + currentEnd, + vec3.normalize( + vec3.create(), + vec3.fromValues( + Random.getRandomInRange(0.5, 1), + 0, + Random.getRandomInRange(0.5, 1), + ), + ), + Random.getRandomInRange(0.5, 1), + ), + ); + } + } + + previousEnd = currentEnd; + previousRadius = currentToRadius; + } } }; diff --git a/backend/src/objects/character-physical.ts b/backend/src/objects/character-physical.ts index 93eecd0..c0ed88a 100644 --- a/backend/src/objects/character-physical.ts +++ b/backend/src/objects/character-physical.ts @@ -44,19 +44,22 @@ export class CharacterPhysical extends CharacterBase implements Physical { constructor(private readonly container: PhysicalContainer) { super(id()); this.head = new CirclePhysical( - vec2.clone(CharacterPhysical.headOffset), + //vec2.clone(CharacterPhysical.headOffset), + [-2952.911, 215.241], 50, this, container, ); this.leftFoot = new CirclePhysical( - vec2.clone(CharacterPhysical.leftFootOffset), + // vec2.clone(CharacterPhysical.leftFootOffset), + [-2930.603, 162.542], 20, this, container, ); this.rightFoot = new CirclePhysical( - vec2.clone(CharacterPhysical.rightFootOffset), + //vec2.clone(CharacterPhysical.rightFootOffset), + [-2973.152, 167.921], 20, this, container, diff --git a/backend/src/objects/circle-physical.ts b/backend/src/objects/circle-physical.ts index a4872ad..b72d9c6 100644 --- a/backend/src/objects/circle-physical.ts +++ b/backend/src/objects/circle-physical.ts @@ -136,12 +136,6 @@ export class CirclePhysical implements Circle, Physical { if (hitSurface) { vec2.scale(this.velocity, tangent!, vec2.dot(tangent!, this.velocity)); - if ( - vec2.length(this.velocity) < - settings.frictionMinVelocity * deltaTimeInSeconds - ) { - this.velocity = vec2.create(); - } wasHit = true; } } diff --git a/backend/src/objects/projectile-physical.ts b/backend/src/objects/projectile-physical.ts new file mode 100644 index 0000000..bca9efb --- /dev/null +++ b/backend/src/objects/projectile-physical.ts @@ -0,0 +1,61 @@ +import { vec2 } from 'gl-matrix'; +import { + id, + StepCommand, + settings, + CommandExecutors, + serializesTo, + ProjectileBase, +} from 'shared'; +import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box'; +import { CirclePhysical } from './circle-physical'; +import { Physical } from '../physics/physical'; +import { PhysicalContainer } from '../physics/containers/physical-container'; + +@serializesTo(ProjectileBase) +export class ProjectilePhysical extends ProjectileBase implements Physical { + public readonly canCollide = true; + public readonly isInverted = false; + public readonly canMove = true; + + public object: CirclePhysical; + + protected commandExecutors: CommandExecutors = { + [StepCommand.type]: this.step.bind(this), + }; + + constructor( + center: vec2, + radius: number, + startingForce: vec2, + readonly container: PhysicalContainer, + ) { + super(id(), center, radius); + this.object = new CirclePhysical(center, radius, this, container); + this.object.applyForce(startingForce, 1000); + } + + private _boundingBox?: ImmutableBoundingBox; + + public get boundingBox(): ImmutableBoundingBox { + if (!this._boundingBox) { + this._boundingBox = (this.object as CirclePhysical).boundingBox; + } + + return this._boundingBox; + } + + public get gameObject(): this { + return this; + } + + public distance(target: vec2): number { + return this.object.distance(target); + } + + public step(c: StepCommand) { + const deltaTime = c.deltaTimeInMiliseconds / 1000; + this.object.applyForce(settings.gravitationalForce, deltaTime); + this.object.step(deltaTime); + } +} diff --git a/backend/src/physics/move-circle.ts b/backend/src/physics/move-circle.ts index 1c30524..234a814 100644 --- a/backend/src/physics/move-circle.ts +++ b/backend/src/physics/move-circle.ts @@ -1,5 +1,5 @@ import { vec2 } from 'gl-matrix'; -import { rotate90Deg, settings } from 'shared'; +import { Circle, rotate90Deg } from 'shared'; import { CirclePhysical } from '../objects/circle-physical'; import { Physical } from './physical'; @@ -13,71 +13,47 @@ export const moveCircle = ( normal?: vec2; tangent?: vec2; } => { - circle.center = vec2.add(circle.center, circle.center, delta); + const nextCircle = new Circle(vec2.clone(circle.center), circle.radius); + vec2.add(nextCircle.center, nextCircle.center, delta); - const intersecting = possibleIntersectors.filter( - (b) => - b.gameObject !== circle.gameObject && circle.areIntersecting(b) && b.canCollide, + possibleIntersectors = possibleIntersectors.filter( + (b) => b.gameObject !== circle.gameObject && b.canCollide, ); - if (intersecting.length === 0) { + const getSdfAtPoint = (point: vec2): number => { + const sdf = possibleIntersectors + .filter((i) => i.isInverted) + .reduce((min, i) => (min = Math.max(min, -i.distance(point))), -1000); + + return possibleIntersectors + .filter((i) => !i.isInverted) + .reduce((min, i) => (min = Math.min(min, i.distance(point))), sdf); + }; + + const sdfAtCenter = getSdfAtPoint(nextCircle.center); + + if (sdfAtCenter > nextCircle.radius) { + circle.center = vec2.add(circle.center, circle.center, delta); return { realDelta: delta, hitSurface: false, }; } - const points = circle.getPerimeterPoints(settings.hitDetectionCirclePointCount); + const dx = + getSdfAtPoint(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(1, 0))) - + sdfAtCenter; + const dy = + getSdfAtPoint(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0, 1))) - + sdfAtCenter; + const normal = vec2.fromValues(dx, dy); - const distancesOfPoints = points - .map((point) => ({ - point, - closest: intersecting - .map((i) => ({ - inverted: i.isInverted, - distance: i.distance(point), - })) - .sort((a, b) => a.distance - b.distance)[0], - })) - .filter((i) => i.closest); + vec2.normalize(normal, normal); - const distancesOfIntersectingPoints = distancesOfPoints.filter( - (d) => - (d.closest.distance > 0 && d.closest.inverted) || - (d.closest.distance < 0 && !d.closest.inverted), - ); - - if (distancesOfIntersectingPoints.length === 0) { - return { - realDelta: delta, - hitSurface: false, - }; - } - - const deltas = distancesOfIntersectingPoints.map((pointDistance) => { - vec2.subtract(pointDistance.point, circle.center, pointDistance.point); - vec2.normalize(pointDistance.point, pointDistance.point); - vec2.scale( - pointDistance.point, - pointDistance.point, - (pointDistance.closest.inverted ? 1 : -1) * pointDistance.closest.distance, - ); - return pointDistance.point; - }); - - const approxNormal = deltas.reduce( - (sum, current) => vec2.add(sum, sum, current), - vec2.create(), - ); - vec2.scale(approxNormal, approxNormal, 1 / deltas.length); - - circle.center = vec2.add(circle.center, circle.center, approxNormal); - - vec2.normalize(approxNormal, approxNormal); return { realDelta: delta, hitSurface: true, - normal: approxNormal, - tangent: rotate90Deg(approxNormal), + normal, + tangent: rotate90Deg(normal), }; }; diff --git a/backend/src/players/player.ts b/backend/src/players/player.ts index 757a004..9fc51c8 100644 --- a/backend/src/players/player.ts +++ b/backend/src/players/player.ts @@ -1,3 +1,4 @@ +import { vec2 } from 'gl-matrix'; import { CommandExecutors, CommandReceiver, @@ -11,9 +12,11 @@ import { StepCommand, SetAspectRatioActionCommand, calculateViewArea, + SecondaryActionCommand, } from 'shared'; import { getTimeInMilliseconds } from '../helper/get-time-in-milliseconds'; import { CharacterPhysical } from '../objects/character-physical'; +import { ProjectilePhysical } from '../objects/projectile-physical'; import { BoundingBox } from '../physics/bounding-boxes/bounding-box'; import { PhysicalContainer } from '../physics/containers/physical-container'; @@ -46,6 +49,15 @@ export class Player extends CommandReceiver { [SetAspectRatioActionCommand.type]: (v: SetAspectRatioActionCommand) => (this.aspectRatio = v.aspectRatio), [MoveActionCommand.type]: (c: MoveActionCommand) => this.character.sendCommand(c), + [SecondaryActionCommand.type]: (c: SecondaryActionCommand) => { + const start = vec2.clone(this.character.center); + const direction = vec2.subtract(vec2.create(), c.position, start); + vec2.normalize(direction, direction); + vec2.add(start, start, vec2.scale(vec2.create(), direction, 100)); + const force = vec2.scale(direction, direction, 1000); + const projectile = new ProjectilePhysical(start, 20, force, this.objects); + this.objects.addObject(projectile); + }, }; constructor( @@ -70,7 +82,6 @@ export class Player extends CommandReceiver { ); this.measureLatency(); - this.sendObjects(); } @@ -113,7 +124,7 @@ export class Player extends CommandReceiver { ); } - this.socket.emit( + this.socket.volatile.emit( TransportEvents.ServerToPlayer, serialize( new UpdateObjectsCommand([ diff --git a/frontend/src/index.ts b/frontend/src/index.ts index 27e9fd5..d7b4619 100644 --- a/frontend/src/index.ts +++ b/frontend/src/index.ts @@ -1,8 +1,10 @@ import { glMatrix } from 'gl-matrix'; import { CharacterBase, LampBase, overrideDeserialization, TunnelBase } from 'shared'; +import { ProjectileBase } from 'shared/src/objects/types/projectile-base'; import { Game } from './scripts/game'; import { CharacterView } from './scripts/objects/character-view'; import { LampView } from './scripts/objects/lamp-view'; +import { ProjectileView } from './scripts/objects/projectile-view'; import { TunnelView } from './scripts/objects/tunnel-view'; import './styles/main.scss'; @@ -11,6 +13,7 @@ glMatrix.setMatrixArrayType(Array); overrideDeserialization(CharacterBase, CharacterView); overrideDeserialization(TunnelBase, TunnelView); overrideDeserialization(LampBase, LampView); +overrideDeserialization(ProjectileBase, ProjectileView); const main = async () => { try { diff --git a/frontend/src/scripts/commands/generators/mouse-listener.ts b/frontend/src/scripts/commands/generators/mouse-listener.ts index ca0cdd7..b8cb30a 100644 --- a/frontend/src/scripts/commands/generators/mouse-listener.ts +++ b/frontend/src/scripts/commands/generators/mouse-listener.ts @@ -5,9 +5,10 @@ import { SecondaryActionCommand, TernaryActionCommand, } from 'shared'; +import { Game } from '../../game'; export class MouseListener extends CommandGenerator { - constructor(target: HTMLElement) { + constructor(target: HTMLElement, private readonly game: Game) { super(); target.addEventListener('mousemove', (event: MouseEvent) => { @@ -31,6 +32,8 @@ export class MouseListener extends CommandGenerator { } private positionFromEvent(event: MouseEvent): vec2 { - return vec2.fromValues(event.clientX, event.clientY); + return this.game.displayToWorldCoordinates( + vec2.fromValues(event.clientX, event.clientY), + ); } } diff --git a/frontend/src/scripts/commands/generators/touch-listener.ts b/frontend/src/scripts/commands/generators/touch-listener.ts index ce073bf..681518c 100644 --- a/frontend/src/scripts/commands/generators/touch-listener.ts +++ b/frontend/src/scripts/commands/generators/touch-listener.ts @@ -6,11 +6,12 @@ import { TernaryActionCommand, MoveActionCommand, } from 'shared'; +import { Game } from '../../game'; export class TouchListener extends CommandGenerator { private previousPosition = vec2.create(); - constructor(target: HTMLElement) { + constructor(target: HTMLElement, private readonly game: Game) { super(); target.addEventListener('touchstart', (event: TouchEvent) => { @@ -57,6 +58,8 @@ export class TouchListener extends CommandGenerator { vec2.create(), ); - return vec2.scale(center, center, 1 / event.touches.length); + return this.game.displayToWorldCoordinates( + vec2.scale(center, center, 1 / event.touches.length), + ); } } diff --git a/frontend/src/scripts/game.ts b/frontend/src/scripts/game.ts index acfba8c..46ef3df 100644 --- a/frontend/src/scripts/game.ts +++ b/frontend/src/scripts/game.ts @@ -6,6 +6,7 @@ import { FilteringOptions, Flashlight, InvertedTunnel, + PolygonFactory, Renderer, renderNoise, WrapOptions, @@ -18,21 +19,22 @@ import { settings, StepCommand, TransportEvents, + SetAspectRatioActionCommand, } from 'shared'; -import { SetAspectRatioActionCommand } from 'shared/src/main'; import io from 'socket.io-client'; import { KeyboardListener } from './commands/generators/keyboard-listener'; import { MouseListener } from './commands/generators/mouse-listener'; import { TouchListener } from './commands/generators/touch-listener'; import { CommandReceiverSocket } from './commands/receivers/command-receiver-socket'; import { RenderCommand } from './commands/types/render'; -import { Configuration } from './config/configuration'; + import { DeltaTimeCalculator } from './helper/delta-time-calculator'; import { rgb } from './helper/rgb'; import { GameObjectContainer } from './objects/game-object-container'; import { BlobShape } from './shapes/blob-shape'; +const Polygon = PolygonFactory(20); export class Game { public readonly gameObjects = new GameObjectContainer(this); private readonly canvas: HTMLCanvasElement = document.querySelector( @@ -44,12 +46,15 @@ export class Game { private overlay: HTMLElement = document.querySelector('#overlay') as HTMLDivElement; private async setupCommunication(): Promise { - await Configuration.initialize(); + // await Configuration.initialize(); - this.socket = io(Configuration.servers[0], { - reconnectionDelayMax: 10000, - transports: ['websocket'], - }); + this.socket = io( + 'http://localhost:3000', + /*Configuration.servers[1],*/ { + reconnectionDelayMax: 10000, + transports: ['websocket'], + }, + ); this.socket.on('reconnect_attempt', () => { this.socket.io.opts.transports = ['polling', 'websocket']; @@ -69,22 +74,26 @@ export class Game { broadcastCommands( [ new KeyboardListener(document.body), - new MouseListener(this.canvas), - new TouchListener(this.canvas), + new MouseListener(this.canvas, this), + new TouchListener(this.canvas, this), ], [this.gameObjects, new CommandReceiverSocket(this.socket)], ); } private async setupRenderer(): Promise { - const noiseTexture = await renderNoise([512, 1], 50, 1 / 10); + const noiseTexture = await renderNoise([64, 1], 40, 1 / 10); this.renderer = await compile( this.canvas, [ { ...InvertedTunnel.descriptor, - shaderCombinationSteps: [0, 2, 6, 16], + shaderCombinationSteps: [0, 2, 6, 16, 32], + }, + { + ...Polygon.descriptor, + shaderCombinationSteps: [0, 1], }, { ...BlobShape.descriptor, @@ -92,7 +101,7 @@ export class Game { }, { ...Circle.descriptor, - shaderCombinationSteps: [0, 2, 16], + shaderCombinationSteps: [0, 2, 16, 32], }, { ...CircleLight.descriptor, @@ -107,11 +116,12 @@ export class Game { shadowTraceCount: 16, paletteSize: 10, enableStopwatch: true, + ignoreWebGL2: true, }, ); this.renderer.setRuntimeSettings({ - isWorldInverted: true, + //isWorldInverted: true, ambientLight: rgb(0.35, 0.1, 0.45), colorPalette: [ rgb(0.4, 1, 0.6), @@ -134,11 +144,19 @@ export class Game { }, }, }); + this.renderer.addDrawable( + new Polygon([ + [10.0, 10.0], + [200, 500], + [500, 400], + ]), + ); + this.renderer.renderDrawables(); } public async start(): Promise { - await Promise.all([this.setupCommunication(), this.setupRenderer()]); - requestAnimationFrame(this.gameLoop.bind(this)); + await Promise.all([/*this.setupCommunication(),*/ this.setupRenderer()]); + // requestAnimationFrame(this.gameLoop.bind(this)); } public displayToWorldCoordinates(p: vec2): vec2 { diff --git a/frontend/src/scripts/objects/lamp-view.ts b/frontend/src/scripts/objects/lamp-view.ts index a2b1045..f03ea98 100644 --- a/frontend/src/scripts/objects/lamp-view.ts +++ b/frontend/src/scripts/objects/lamp-view.ts @@ -8,7 +8,7 @@ export class LampView extends LampBase { protected commandExecutors: CommandExecutors = { [RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.light), - } as any; + }; constructor(id: Id, center: vec2, color: vec3, lightness: number) { super(id, center, color, lightness); diff --git a/frontend/src/scripts/objects/projectile-view.ts b/frontend/src/scripts/objects/projectile-view.ts new file mode 100644 index 0000000..bc81f73 --- /dev/null +++ b/frontend/src/scripts/objects/projectile-view.ts @@ -0,0 +1,18 @@ +import { vec2 } from 'gl-matrix'; +import { Circle } from 'sdf-2d'; +import { CommandExecutors, Id } from 'shared'; +import { ProjectileBase } from 'shared/src/objects/types/projectile-base'; +import { RenderCommand } from '../commands/types/render'; + +export class ProjectileView extends ProjectileBase { + private circle: Circle; + + protected commandExecutors: CommandExecutors = { + [RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.circle), + }; + + constructor(id: Id, center: vec2, radius: number) { + super(id, center, radius); + this.circle = new Circle(center, radius); + } +} diff --git a/frontend/src/scripts/objects/tunnel-view.ts b/frontend/src/scripts/objects/tunnel-view.ts index ecd6638..c51dc5f 100644 --- a/frontend/src/scripts/objects/tunnel-view.ts +++ b/frontend/src/scripts/objects/tunnel-view.ts @@ -8,7 +8,7 @@ export class TunnelView extends TunnelBase { protected commandExecutors: CommandExecutors = { [RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.shape), - } as any; + }; constructor(id: Id, from: vec2, to: vec2, fromRadius: number, toRadius: number) { super(id, from, to, fromRadius, toRadius); diff --git a/shared/src/helper/random.ts b/shared/src/helper/random.ts index 10e93bb..4f800bc 100644 --- a/shared/src/helper/random.ts +++ b/shared/src/helper/random.ts @@ -9,6 +9,19 @@ export abstract class Random { Random._seed = value; } + public static choose(values: Array): T | undefined { + const to = values.length; + if (to === 0) { + return undefined; + } + + return values[Math.floor(this.getRandomInRange(0, to))]; + } + + public static getRandomInRange(from: number, to: number): number { + return from + this.getRandom() * (to - from); + } + public static getRandom(): number { let t = (Random._seed += 0x6d2b79f5); t = Math.imul(t ^ (t >>> 15), t | 1); diff --git a/shared/src/main.ts b/shared/src/main.ts index bf9a7bb..3c47bcf 100644 --- a/shared/src/main.ts +++ b/shared/src/main.ts @@ -6,7 +6,6 @@ export * from './commands/types/update-objects'; export * from './commands/types/step'; export * from './commands/types/ternary-action'; export * from './commands/types/move-action'; -export * from './commands/types/set-aspect-ratio-action'; export * from './commands/types/primary-action'; export * from './commands/types/secondary-action'; export * from './commands/command-receiver'; @@ -33,6 +32,7 @@ export * from './transport/serialization/serializable'; export * from './transport/serialization/override-deserialization'; export * from './objects/types/character-base'; export * from './objects/types/lamp-base'; +export * from './objects/types/projectile-base'; export * from './objects/types/tunnel-base'; export * from './settings'; export * from './transport/transport-events'; diff --git a/shared/src/objects/types/character-base.ts b/shared/src/objects/types/character-base.ts index a0e6f84..8475c63 100644 --- a/shared/src/objects/types/character-base.ts +++ b/shared/src/objects/types/character-base.ts @@ -15,7 +15,7 @@ export class CharacterBase extends GameObject { } public toArray(): Array { - const { id, head, leftFoot, rightFoot } = this as any; + const { id, head, leftFoot, rightFoot } = this; return [id, head, leftFoot, rightFoot]; } } diff --git a/shared/src/objects/types/lamp-base.ts b/shared/src/objects/types/lamp-base.ts index cf594a2..3977fce 100644 --- a/shared/src/objects/types/lamp-base.ts +++ b/shared/src/objects/types/lamp-base.ts @@ -9,7 +9,7 @@ export class LampBase extends GameObject { } public toArray(): Array { - const { id, center, color, lightness } = this as any; + const { id, center, color, lightness } = this; return [id, center, color, lightness]; } } diff --git a/shared/src/objects/types/projectile-base.ts b/shared/src/objects/types/projectile-base.ts new file mode 100644 index 0000000..90ef4e2 --- /dev/null +++ b/shared/src/objects/types/projectile-base.ts @@ -0,0 +1,15 @@ +import { vec2 } from 'gl-matrix'; +import { Id } from '../../transport/identity'; +import { serializable } from '../../transport/serialization/serializable'; +import { GameObject } from '../game-object'; + +@serializable +export class ProjectileBase extends GameObject { + constructor(id: Id, public center: vec2, public radius: number) { + super(id); + } + + public toArray(): Array { + return [this.id, this.center, this.radius]; + } +} diff --git a/shared/src/objects/types/tunnel-base.ts b/shared/src/objects/types/tunnel-base.ts index 58dea4d..054a02c 100644 --- a/shared/src/objects/types/tunnel-base.ts +++ b/shared/src/objects/types/tunnel-base.ts @@ -16,7 +16,7 @@ export class TunnelBase extends GameObject { } public toArray(): Array { - const { id, from, to, fromRadius, toRadius } = this as any; + const { id, from, to, fromRadius, toRadius } = this; return [id, from, to, fromRadius, toRadius]; } }