diff --git a/backend/src/commands/generate-points.ts b/backend/src/commands/generate-points.ts new file mode 100644 index 0000000..289361e --- /dev/null +++ b/backend/src/commands/generate-points.ts @@ -0,0 +1,7 @@ +import { Command, GameObject } from 'shared'; + +export class GeneratePointsCommand extends Command { + public constructor(public readonly decla: number, public readonly red: number) { + super(); + } +} diff --git a/backend/src/commands/react-to-collision.ts b/backend/src/commands/react-to-collision.ts new file mode 100644 index 0000000..fdcd492 --- /dev/null +++ b/backend/src/commands/react-to-collision.ts @@ -0,0 +1,7 @@ +import { Command, GameObject } from 'shared'; + +export class ReactToCollisionCommand extends Command { + public constructor(public readonly other: GameObject) { + super(); + } +} diff --git a/backend/src/commands/step.ts b/backend/src/commands/step.ts new file mode 100644 index 0000000..ee0f6f7 --- /dev/null +++ b/backend/src/commands/step.ts @@ -0,0 +1,10 @@ +import { Command, CommandReceiver } from 'shared'; + +export class StepCommand extends Command { + public constructor( + public readonly deltaTimeInSeconds: number, + public readonly game: CommandReceiver, + ) { + super(); + } +} diff --git a/backend/src/game-server.ts b/backend/src/game-server.ts index a0b1dc1..5eecdbb 100644 --- a/backend/src/game-server.ts +++ b/backend/src/game-server.ts @@ -11,15 +11,19 @@ import { GameEndCommand, GameStartCommand, Command, + CommandReceiver, + CommandExecutors, } from 'shared'; import { createWorld } from './create-world'; import { DeltaTimeCalculator } from './helper/delta-time-calculator'; import { Options } from './options'; import { PlayerContainer } from './players/player-container'; +import { StepCommand } from './commands/step'; +import { GeneratePointsCommand } from './commands/generate-points'; const gameStateSubscribedRoom = 'gameStateSubscribedRoom'; -export class GameServer { +export class GameServer extends CommandReceiver { private objects!: PhysicalContainer; private players!: PlayerContainer; private deltaTimes!: Array; @@ -54,7 +58,13 @@ export class GameServer { previousPlayers?.sendQueuedCommands(); } + protected commandExecutors: CommandExecutors = { + [GeneratePointsCommand.type]: this.addPoints.bind(this), + }; + constructor(private readonly io: ioserver.Server, private options: Options) { + super(); + this.serverName = options.name; this.playerLimit = options.playerLimit; @@ -102,8 +112,11 @@ export class GameServer { this.handlePhysics(); } - private updatePoints() { - const { decla, red } = this.objects.getPointsGenerated(); + private addPoints({ decla, red }: GeneratePointsCommand) { + if (this.isInEndGame) { + return; + } + this.declaPoints += decla; this.redPoints += red; if (this.declaPoints >= this.options.scoreLimit) { @@ -152,11 +165,9 @@ export class GameServer { if (this.isInEndGame) { this.timeScaling *= Math.pow(settings.endGameDeltaScaling, delta); scaledDelta /= this.timeScaling; - } else { - this.updatePoints(); } - this.objects.stepObjects(scaledDelta); + this.objects.handleCommand(new StepCommand(scaledDelta, this)); this.players.step(scaledDelta); this.players.stepCommunication(delta); this.objects.resetRemoteCalls(); diff --git a/backend/src/objects/capabilities/exerts-force.ts b/backend/src/objects/capabilities/exerts-force.ts deleted file mode 100644 index 6e5c4ee..0000000 --- a/backend/src/objects/capabilities/exerts-force.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { vec2 } from 'gl-matrix'; - -export interface ExertsForce { - getForce(target: vec2): vec2; -} - -export const exertsForce = (a: any): a is ExertsForce => a && 'getForce' in a; diff --git a/backend/src/objects/capabilities/generates-points.ts b/backend/src/objects/capabilities/generates-points.ts deleted file mode 100644 index 053f89a..0000000 --- a/backend/src/objects/capabilities/generates-points.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface GeneratesPoints { - getPoints(): { - decla: number; - red: number; - }; -} - -export const generatesPoints = (a: any): a is GeneratesPoints => a && 'getPoints' in a; diff --git a/backend/src/objects/capabilities/reacts-to-collision.ts b/backend/src/objects/capabilities/reacts-to-collision.ts deleted file mode 100644 index 90e880a..0000000 --- a/backend/src/objects/capabilities/reacts-to-collision.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { GameObject } from 'shared'; - -export interface ReactsToCollision { - onCollision(other: GameObject): void; -} - -export const reactsToCollision = (a: any): a is ReactsToCollision => - a && 'onCollision' in a; diff --git a/backend/src/objects/capabilities/time-dependent.ts b/backend/src/objects/capabilities/time-dependent.ts deleted file mode 100644 index 6904d87..0000000 --- a/backend/src/objects/capabilities/time-dependent.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface TimeDependent { - step(deltaTimeInSeconds: number): void; -} - -export const timeDependent = (a: any): a is TimeDependent => a && 'step' in a; diff --git a/backend/src/objects/character-physical.ts b/backend/src/objects/character-physical.ts index 4f9bda8..6485f8b 100644 --- a/backend/src/objects/character-physical.ts +++ b/backend/src/objects/character-physical.ts @@ -11,6 +11,8 @@ import { CharacterTeam, PropertyUpdatesForObject, UpdatePropertyCommand, + CommandExecutors, + CommandReceiver, } from 'shared'; import { DynamicPhysical } from '../physics/physicals/dynamic-physical'; import { CirclePhysical } from './circle-physical'; @@ -21,14 +23,12 @@ import { interpolateAngles } from '../helper/interpolate-angles'; import { forceAtPosition } from '../physics/functions/force-at-position'; import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; import { PlanetPhysical } from './planet-physical'; -import { ReactsToCollision } from './capabilities/reacts-to-collision'; -import { TimeDependent } from './capabilities/time-dependent'; -import { GeneratesPoints } from './capabilities/generates-points'; +import { StepCommand } from '../commands/step'; +import { ReactToCollisionCommand } from '../commands/react-to-collision'; +import { GeneratePointsCommand } from '../commands/generate-points'; @serializesTo(CharacterBase) -export class CharacterPhysical - extends CharacterBase - implements DynamicPhysical, ReactsToCollision, TimeDependent, GeneratesPoints { +export class CharacterPhysical extends CharacterBase implements DynamicPhysical { public readonly canCollide = true; public readonly canMove = true; @@ -94,6 +94,11 @@ export class CharacterPhysical private leftFootVelocity = new Circle(vec2.create(), 0); private rightFootVelocity = new Circle(vec2.create(), 0); + protected commandExecutors: CommandExecutors = { + [StepCommand.type]: this.step.bind(this), + [ReactToCollisionCommand.type]: this.onCollision.bind(this), + }; + constructor( name: string, killCount: number, @@ -134,20 +139,14 @@ export class CharacterPhysical } private hasGeneratedPoints = false; - public getPoints(): { decla: number; red: number } { + private getPoints(game: CommandReceiver) { if (!this.isAlive && !this.hasGeneratedPoints) { this.hasGeneratedPoints = true; const decla = this.team === CharacterTeam.decla ? 0 : settings.playerKillPoint; const red = this.team === CharacterTeam.red ? 0 : settings.playerKillPoint; - return { - decla, - red, - }; + + game.handleCommand(new GeneratePointsCommand(decla, red)); } - return { - decla: 0, - red: 0, - }; } public get isAlive(): boolean { @@ -163,7 +162,7 @@ export class CharacterPhysical this.remoteCall('setKillCount', this.killCount); } - public onCollision(other: GameObject) { + public onCollision({ other }: ReactToCollisionCommand) { if ( other instanceof ProjectilePhysical && other.team !== this.team && @@ -298,7 +297,8 @@ export class CharacterPhysical this.animateScaling(1); } - public step(deltaTime: number) { + private step({ deltaTimeInSeconds, game }: StepCommand) { + this.getPoints(game); const oldHead = new Circle(vec2.clone(this.head.center), this.head.radius); const oldLeftFoot = new Circle( vec2.clone(this.leftFoot.center), @@ -310,35 +310,36 @@ export class CharacterPhysical ); if (this.isDestroyed) { - if ((this.timeSinceDying += deltaTime) > settings.spawnDespawnTime) { + if ((this.timeSinceDying += deltaTimeInSeconds) > settings.spawnDespawnTime) { this.destroy(); } else { this.animateScaling(1 - this.timeSinceDying / settings.spawnDespawnTime); } - this.setPropertyUpdates(oldHead, oldLeftFoot, oldRightFoot, deltaTime); + this.setPropertyUpdates(oldHead, oldLeftFoot, oldRightFoot, deltaTimeInSeconds); return; } if (this.hasJustBorn) { - if ((this.timeSinceBorn += deltaTime) > settings.spawnDespawnTime) { + if ((this.timeSinceBorn += deltaTimeInSeconds) > settings.spawnDespawnTime) { this.hasJustBorn = false; } else { this.animateScaling(this.timeSinceBorn / settings.spawnDespawnTime); } - this.setPropertyUpdates(oldHead, oldLeftFoot, oldRightFoot, deltaTime); + this.setPropertyUpdates(oldHead, oldLeftFoot, oldRightFoot, deltaTimeInSeconds); return; } - if ((this.secondsSinceOnSurface += deltaTime) > 0.5) { + if ((this.secondsSinceOnSurface += deltaTimeInSeconds) > 0.5) { this.currentPlanet = undefined; } this.projectileStrength = Math.min( settings.playerMaxStrength, - this.projectileStrength + settings.playerStrengthRegenerationPerSeconds * deltaTime, + this.projectileStrength + + settings.playerStrengthRegenerationPerSeconds * deltaTimeInSeconds, ); - this.currentPlanet?.takeControl(this.team, deltaTime); + this.currentPlanet?.takeControl(this.team, deltaTimeInSeconds); const intersectingWithForceField = this.container.findIntersecting( getBoundingBoxOfCircle( @@ -351,8 +352,8 @@ export class CharacterPhysical const direction = this.averageAndResetMovementActions(); const movementForce = vec2.scale(direction, direction, settings.maxAcceleration); - this.applyForce(this.leftFoot, movementForce, deltaTime); - this.applyForce(this.rightFoot, movementForce, deltaTime); + this.applyForce(this.leftFoot, movementForce, deltaTimeInSeconds); + this.applyForce(this.rightFoot, movementForce, deltaTimeInSeconds); if (!this.currentPlanet) { const leftFootGravity = forceAtPosition( @@ -364,14 +365,14 @@ export class CharacterPhysical intersectingWithForceField, ); - this.applyForce(this.leftFoot, leftFootGravity, deltaTime); - this.applyForce(this.rightFoot, rightFootGravity, deltaTime); + this.applyForce(this.leftFoot, leftFootGravity, deltaTimeInSeconds); + this.applyForce(this.rightFoot, rightFootGravity, deltaTimeInSeconds); const sumForce = vec2.subtract(vec2.create(), leftFootGravity, movementForce); this.setDirection( vec2.length(sumForce) === 0 ? vec2.fromValues(0, -1) : sumForce, - deltaTime, + deltaTimeInSeconds, ); } else { const leftFootGravity = this.currentPlanet!.getForce(this.leftFoot.center); @@ -389,7 +390,7 @@ export class CharacterPhysical this.leftFoot.lastNormal, vec2.dot(this.leftFoot.lastNormal, gravity), ); - this.applyForce(this.leftFoot, scaledLeftFootGravity, deltaTime); + this.applyForce(this.leftFoot, scaledLeftFootGravity, deltaTimeInSeconds); const scaledRightFootGravity = vec2.scale( vec2.create(), @@ -397,20 +398,20 @@ export class CharacterPhysical vec2.dot(this.rightFoot.lastNormal, gravity), ); - this.applyForce(this.rightFoot, scaledRightFootGravity, deltaTime); + this.applyForce(this.rightFoot, scaledRightFootGravity, deltaTimeInSeconds); if (vec2.length(gravity) <= 100) { this.currentPlanet = undefined; } - this.setDirection(gravity, deltaTime); + this.setDirection(gravity, deltaTimeInSeconds); } - this.keepPosture(deltaTime); - this.stepBodyPart(this.leftFoot, deltaTime); - this.stepBodyPart(this.rightFoot, deltaTime); - this.stepBodyPart(this.head, deltaTime); + this.keepPosture(deltaTimeInSeconds); + this.stepBodyPart(this.leftFoot, deltaTimeInSeconds); + this.stepBodyPart(this.rightFoot, deltaTimeInSeconds); + this.stepBodyPart(this.head, deltaTimeInSeconds); - this.setPropertyUpdates(oldHead, oldLeftFoot, oldRightFoot, deltaTime); + this.setPropertyUpdates(oldHead, oldLeftFoot, oldRightFoot, deltaTimeInSeconds); } private setDirection(direction: vec2, deltaTime: number) { diff --git a/backend/src/objects/circle-physical.ts b/backend/src/objects/circle-physical.ts index 2418b63..9601012 100644 --- a/backend/src/objects/circle-physical.ts +++ b/backend/src/objects/circle-physical.ts @@ -1,14 +1,14 @@ import { vec2 } from 'gl-matrix'; -import { Circle, GameObject, serializesTo } from 'shared'; +import { Circle, CommandReceiver, GameObject, serializesTo } from 'shared'; import { BoundingBox } from '../physics/bounding-boxes/bounding-box'; import { BoundingBoxBase } from '../physics/bounding-boxes/bounding-box-base'; import { moveCircle } from '../physics/functions/move-circle'; import { PhysicalContainer } from '../physics/containers/physical-container'; import { DynamicPhysical } from '../physics/physicals/dynamic-physical'; -import { ReactsToCollision, reactsToCollision } from './capabilities/reacts-to-collision'; +import { ReactToCollisionCommand } from '../commands/react-to-collision'; @serializesTo(Circle) -export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollision { +export class CirclePhysical extends CommandReceiver implements Circle, DynamicPhysical { readonly canCollide = true; readonly canMove = true; @@ -24,6 +24,7 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio private readonly container: PhysicalContainer, private restitution = 0, ) { + super(); this._boundingBox = new BoundingBox(); this.recalculateBoundingBox(); } @@ -41,10 +42,8 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio this.recalculateBoundingBox(); } - public onCollision(other: GameObject) { - if (reactsToCollision(this.owner)) { - this.owner.onCollision(other); - } + public onCollision(c: ReactToCollisionCommand) { + this.owner.handleCommand(c); } public get gameObject(): GameObject { diff --git a/backend/src/objects/planet-physical.ts b/backend/src/objects/planet-physical.ts index 1e966c3..094b48d 100644 --- a/backend/src/objects/planet-physical.ts +++ b/backend/src/objects/planet-physical.ts @@ -10,30 +10,28 @@ import { CharacterTeam, PropertyUpdatesForObject, UpdatePropertyCommand, + CommandExecutors, + CommandReceiver, } from 'shared'; +import { GeneratePointsCommand } from '../commands/generate-points'; +import { StepCommand } from '../commands/step'; import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box'; import { StaticPhysical } from '../physics/physicals/static-physical'; -import { ExertsForce } from './capabilities/exerts-force'; -import { GeneratesPoints } from './capabilities/generates-points'; -import { TimeDependent } from './capabilities/time-dependent'; @serializesTo(PlanetBase) -export class PlanetPhysical - extends PlanetBase - implements StaticPhysical, GeneratesPoints, ExertsForce, TimeDependent { +export class PlanetPhysical extends PlanetBase implements StaticPhysical { public readonly canCollide = true; public readonly canMove = false; - public static neutralPlanetCount = 0; - public static declaPlanetCount = 0; - public static redPlanetCount = 0; - private _boundingBox?: ImmutableBoundingBox; + protected commandExecutors: CommandExecutors = { + [StepCommand.type]: this.step.bind(this), + }; + constructor(vertices: Array) { super(id(), vertices); - PlanetPhysical.neutralPlanetCount++; } public distance(target: vec2): number { @@ -79,33 +77,27 @@ export class PlanetPhysical } private timeSinceLastPointGeneration = 0; - public getPoints(): { - decla: number; - red: number; - } { + private getPoints(game: CommandReceiver) { if (this.timeSinceLastPointGeneration > settings.planetPointGenerationInterval) { this.timeSinceLastPointGeneration = 0; if (this.team !== CharacterTeam.neutral) { this.remoteCall('generatedPoints', settings.planetPointGenerationValue); } - return { - decla: + game.handleCommand( + new GeneratePointsCommand( this.team === CharacterTeam.decla ? settings.planetPointGenerationValue : 0, - red: this.team === CharacterTeam.red ? settings.planetPointGenerationValue : 0, - }; + this.team === CharacterTeam.red ? settings.planetPointGenerationValue : 0, + ), + ); } - - return { - decla: 0, - red: 0, - }; } - public step(deltaTime: number): void { - this.timeSinceLastPointGeneration += deltaTime; + private step({ deltaTimeInSeconds, game }: StepCommand) { + this.timeSinceLastPointGeneration += deltaTimeInSeconds; // In reverse order, so that teams can achieve a 100% control. - this.takeControl(CharacterTeam.neutral, deltaTime); + this.getPoints(game); + this.takeControl(CharacterTeam.neutral, deltaTimeInSeconds); } public getPropertyUpdates(): PropertyUpdatesForObject { diff --git a/backend/src/objects/projectile-physical.ts b/backend/src/objects/projectile-physical.ts index 0a3c5f5..683a8ec 100644 --- a/backend/src/objects/projectile-physical.ts +++ b/backend/src/objects/projectile-physical.ts @@ -8,20 +8,19 @@ import { CharacterTeam, PropertyUpdatesForObject, UpdatePropertyCommand, + CommandExecutors, } from 'shared'; import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box'; import { CirclePhysical } from './circle-physical'; import { DynamicPhysical } from '../physics/physicals/dynamic-physical'; import { PhysicalContainer } from '../physics/containers/physical-container'; -import { ReactsToCollision } from './capabilities/reacts-to-collision'; import { CharacterPhysical } from './character-physical'; import { moveCircle } from '../physics/functions/move-circle'; -import { TimeDependent } from './capabilities/time-dependent'; +import { StepCommand } from '../commands/step'; +import { ReactToCollisionCommand } from '../commands/react-to-collision'; @serializesTo(ProjectileBase) -export class ProjectilePhysical - extends ProjectileBase - implements DynamicPhysical, ReactsToCollision, TimeDependent { +export class ProjectilePhysical extends ProjectileBase implements DynamicPhysical { public readonly canCollide = true; public readonly canMove = true; @@ -31,6 +30,11 @@ export class ProjectilePhysical public object: CirclePhysical; + protected commandExecutors: CommandExecutors = { + [StepCommand.type]: this.handleStep.bind(this), + [ReactToCollisionCommand.type]: this.onCollision.bind(this), + }; + constructor( center: vec2, radius: number, @@ -91,7 +95,7 @@ export class ProjectilePhysical } } - public onCollision(other: GameObject) { + public onCollision({ other }: ReactToCollisionCommand) { if ( !(other instanceof CharacterPhysical && other.team === this.team) && this.bounceCount++ === settings.projectileMaxBounceCount @@ -106,8 +110,8 @@ export class ProjectilePhysical ]); } - public step(deltaTime: number) { - super.step(deltaTime); + private handleStep({ deltaTimeInSeconds }: StepCommand) { + super.step(deltaTimeInSeconds); if (this.strength <= 0) { this.destroy(); @@ -115,7 +119,7 @@ export class ProjectilePhysical } vec2.copy(this.object.velocity, this.velocity); - const { velocity } = this.object.stepManually(deltaTime); + const { velocity } = this.object.stepManually(deltaTimeInSeconds); vec2.copy(this.velocity, velocity); } } diff --git a/backend/src/physics/containers/physical-container.ts b/backend/src/physics/containers/physical-container.ts index 47f826a..604672e 100644 --- a/backend/src/physics/containers/physical-container.ts +++ b/backend/src/physics/containers/physical-container.ts @@ -4,19 +4,19 @@ import { BoundingBoxTree } from './bounding-box-tree'; import { Physical } from '../physicals/physical'; import { StaticPhysical } from '../physicals/static-physical'; import { DynamicPhysical } from '../physicals/dynamic-physical'; -import { - GeneratesPoints, - generatesPoints, -} from '../../objects/capabilities/generates-points'; -import { timeDependent } from '../../objects/capabilities/time-dependent'; +import { Command, CommandReceiver } from 'shared'; -export class PhysicalContainer { +export class PhysicalContainer extends CommandReceiver { private isTreeInitialized = false; private staticBoundingBoxesWaitList: Array = []; private staticBoundingBoxes = new BoundingBoxTree(); private dynamicBoundingBoxes = new BoundingBoxList(); private objects: Array = []; + protected defaultCommandExecutor(c: Command) { + this.objects.forEach((o) => o.handleCommand(c)); + } + public initialize() { this.staticBoundingBoxes.build(this.staticBoundingBoxesWaitList); this.isTreeInitialized = true; @@ -41,29 +41,10 @@ export class PhysicalContainer { this.dynamicBoundingBoxes.remove(object); } - public stepObjects(deltaTime: number) { - this.objects.forEach((o) => timeDependent(o) && o.step(deltaTime)); - } - public resetRemoteCalls() { this.objects.forEach((o) => o.gameObject.resetRemoteCalls()); } - public getPointsGenerated(): { decla: number; red: number } { - return this.objects - .filter((o) => generatesPoints(o)) - .reduce( - (sum, o) => { - const { decla, red } = ((o as unknown) as GeneratesPoints).getPoints(); - return { - decla: sum.decla + decla, - red: sum.red + red, - }; - }, - { decla: 0, red: 0 }, - ); - } - public findIntersecting(box: BoundingBoxBase): Array { return [ ...this.staticBoundingBoxes.findIntersecting(box), diff --git a/backend/src/physics/functions/force-at-position.ts b/backend/src/physics/functions/force-at-position.ts index 4c6f311..85bf2e3 100644 --- a/backend/src/physics/functions/force-at-position.ts +++ b/backend/src/physics/functions/force-at-position.ts @@ -1,10 +1,12 @@ import { vec2 } from 'gl-matrix'; -import { exertsForce } from '../../objects/capabilities/exerts-force'; +import { PlanetPhysical } from '../../objects/planet-physical'; import { Physical } from '../physicals/physical'; export const forceAtPosition = (position: vec2, objects: Array) => - objects.reduce( - (sum: vec2, o: Physical) => - exertsForce(o) ? vec2.add(sum, sum, o.getForce(position)) : sum, - vec2.create(), - ); + objects + .filter((o) => o instanceof PlanetPhysical) + .reduce( + (sum: vec2, o: Physical) => + vec2.add(sum, sum, (o as PlanetPhysical).getForce(position)), + vec2.create(), + ); diff --git a/backend/src/physics/functions/move-circle.ts b/backend/src/physics/functions/move-circle.ts index f9d32ca..d59dd86 100644 --- a/backend/src/physics/functions/move-circle.ts +++ b/backend/src/physics/functions/move-circle.ts @@ -1,9 +1,9 @@ import { vec2 } from 'gl-matrix'; import { Circle, GameObject, rotate90Deg } from 'shared'; import { CirclePhysical } from '../../objects/circle-physical'; -import { reactsToCollision } from '../../objects/capabilities/reacts-to-collision'; import { evaluateSdf } from './evaluate-sdf'; import { Physical } from '../physicals/physical'; +import { ReactToCollisionCommand } from '../../commands/react-to-collision'; export const moveCircle = ( circle: CirclePhysical, @@ -43,13 +43,8 @@ export const moveCircle = ( if (ignoreCollision) { circle.center = vec2.add(circle.center, circle.center, delta); } else { - if (reactsToCollision(intersecting)) { - intersecting.onCollision(circle.gameObject); - } - - if (reactsToCollision(circle)) { - circle.onCollision(intersecting.gameObject); - } + intersecting.handleCommand(new ReactToCollisionCommand(circle.gameObject)); + circle.handleCommand(new ReactToCollisionCommand(intersecting.gameObject)); } vec2.add( diff --git a/backend/src/physics/physicals/physical-base.ts b/backend/src/physics/physicals/physical-base.ts index 3f923b6..ab41eac 100644 --- a/backend/src/physics/physicals/physical-base.ts +++ b/backend/src/physics/physicals/physical-base.ts @@ -1,8 +1,8 @@ import { vec2 } from 'gl-matrix'; -import { GameObject } from 'shared'; +import { CommandReceiver, GameObject } from 'shared'; import { BoundingBoxBase } from '../bounding-boxes/bounding-box-base'; -export interface PhysicalBase { +export interface PhysicalBase extends CommandReceiver { readonly canCollide: boolean; readonly canMove: boolean; readonly boundingBox: BoundingBoxBase; diff --git a/backend/src/react-to-collision.ts b/backend/src/react-to-collision.ts new file mode 100644 index 0000000..fdcd492 --- /dev/null +++ b/backend/src/react-to-collision.ts @@ -0,0 +1,7 @@ +import { Command, GameObject } from 'shared'; + +export class ReactToCollisionCommand extends Command { + public constructor(public readonly other: GameObject) { + super(); + } +} diff --git a/frontend/src/scripts/objects/types/planet-view.ts b/frontend/src/scripts/objects/types/planet-view.ts index 4aec3ea..fbae00f 100644 --- a/frontend/src/scripts/objects/types/planet-view.ts +++ b/frontend/src/scripts/objects/types/planet-view.ts @@ -33,7 +33,7 @@ export class PlanetView extends PlanetBase { this.ownershipProgress.className = 'ownership'; } - private step(deltaTimeInSeconds: number): void { + private step({ deltaTimeInSeconds }: StepCommand): void { this.shape.randomOffset += deltaTimeInSeconds / 4; this.shape.colorMixQ = this.ownership;