This commit is contained in:
schmelczerandras 2020-11-04 22:05:21 +01:00
parent b774357807
commit 57d7009342
39 changed files with 203 additions and 250 deletions

View file

@ -67,8 +67,8 @@ export const createWorld = (objectContainer: PhysicalContainer, worldRadius: num
} }
} }
} }
console.log('Generated planet count', objects.length); console.info('Generated planet count', objects.length);
console.log('Generated light count', lights.length); console.info('Generated light count', lights.length);
[...objects, ...lights].forEach((o) => objectContainer.addObject(o)); [...objects, ...lights].forEach((o) => objectContainer.addObject(o));
}; };

View file

@ -69,7 +69,7 @@ export class GameServer {
const commands: Array<Command> = deserialize(json); const commands: Array<Command> = deserialize(json);
commands.forEach((c) => player.sendCommand(c)); commands.forEach((c) => player.sendCommand(c));
} catch (e) { } catch (e) {
console.log('Error while processing command', e); console.error('Error while processing command', e);
} }
}); });
@ -169,16 +169,16 @@ export class GameServer {
if (this.deltaTimes.length > framesBetweenDeltaTimeCalculation) { if (this.deltaTimes.length > framesBetweenDeltaTimeCalculation) {
this.deltaTimes.sort((a, b) => a - b); this.deltaTimes.sort((a, b) => a - b);
console.log( console.info(
`Median physics time: ${this.deltaTimes[ `Median physics time: ${this.deltaTimes[
Math.floor(framesBetweenDeltaTimeCalculation / 2) Math.floor(framesBetweenDeltaTimeCalculation / 2)
].toFixed(2)} ms`, ].toFixed(2)} ms`,
); );
console.log( console.info(
'Tail times: ', 'Tail times: ',
this.deltaTimes.slice(-20).map((v) => `${(v * 1000).toFixed(2)} ms`), this.deltaTimes.slice(-20).map((v) => `${(v * 1000).toFixed(2)} ms`),
); );
console.log( console.info(
`Memory used: ${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`, `Memory used: ${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`,
); );
this.deltaTimes = []; this.deltaTimes = [];

View file

@ -28,19 +28,19 @@ const gameServer = new GameServer(io, options);
app.use( app.use(
cors({ cors({
origin: (origin, callback) => { origin: (_, callback) => {
callback(null, true); callback(null, true);
}, },
credentials: true, credentials: true,
}), }),
); );
app.get(serverInformationEndpoint, (req, res) => { app.get(serverInformationEndpoint, (_, res) => {
res.json(gameServer.serverInfo); res.json(gameServer.serverInfo);
}); });
server.listen(options.port, () => { server.listen(options.port, () => {
console.log(`server started at http://localhost:${options.port}`); console.info(`Server started on port ${options.port}`);
}); });
gameServer.start(); gameServer.start();

View file

@ -0,0 +1,7 @@
import { vec2 } from 'gl-matrix';
export interface ExertsForce {
getForce(target: vec2): vec2;
}
export const exertsForce = (a: any): a is ExertsForce => a && 'getForce' in a;

View file

@ -0,0 +1,5 @@
export interface TimeDependent {
step(deltaTimeInSeconds: number): void;
}
export const timeDependent = (a: any): a is TimeDependent => a && 'step' in a;

View file

@ -7,7 +7,7 @@ import {
last, last,
GameObject, GameObject,
Circle, Circle,
PlayerCharacterBase, CharacterBase,
CharacterTeam, CharacterTeam,
PropertyUpdatesForObject, PropertyUpdatesForObject,
UpdateProperty, UpdateProperty,
@ -21,12 +21,14 @@ import { interpolateAngles } from '../helper/interpolate-angles';
import { forceAtPosition } from '../physics/functions/force-at-position'; import { forceAtPosition } from '../physics/functions/force-at-position';
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
import { PlanetPhysical } from './planet-physical'; import { PlanetPhysical } from './planet-physical';
import { ReactsToCollision } from '../physics/functions/reacts-to-collision'; import { ReactsToCollision } from './capabilities/reacts-to-collision';
import { TimeDependent } from './capabilities/time-dependent';
import { GeneratesPoints } from './capabilities/generates-points';
@serializesTo(PlayerCharacterBase) @serializesTo(CharacterBase)
export class PlayerCharacterPhysical export class CharacterPhysical
extends PlayerCharacterBase extends CharacterBase
implements DynamicPhysical, ReactsToCollision { implements DynamicPhysical, ReactsToCollision, TimeDependent, GeneratesPoints {
public readonly canCollide = true; public readonly canCollide = true;
public readonly canMove = true; public readonly canMove = true;
@ -44,32 +46,32 @@ export class PlayerCharacterPhysical
vec2.create(), vec2.create(),
vec2.add( vec2.add(
vec2.create(), vec2.create(),
PlayerCharacterPhysical.desiredHeadOffset, CharacterPhysical.desiredHeadOffset,
PlayerCharacterPhysical.desiredLeftFootOffset, CharacterPhysical.desiredLeftFootOffset,
), ),
PlayerCharacterPhysical.desiredRightFootOffset, CharacterPhysical.desiredRightFootOffset,
), ),
1 / 3, 1 / 3,
); );
private static readonly headOffset = vec2.subtract( private static readonly headOffset = vec2.subtract(
vec2.create(), vec2.create(),
PlayerCharacterPhysical.desiredHeadOffset, CharacterPhysical.desiredHeadOffset,
PlayerCharacterPhysical.centerOfMass, CharacterPhysical.centerOfMass,
); );
private static readonly leftFootOffset = vec2.subtract( private static readonly leftFootOffset = vec2.subtract(
vec2.create(), vec2.create(),
PlayerCharacterPhysical.desiredLeftFootOffset, CharacterPhysical.desiredLeftFootOffset,
PlayerCharacterPhysical.centerOfMass, CharacterPhysical.centerOfMass,
); );
private static readonly rightFootOffset = vec2.subtract( private static readonly rightFootOffset = vec2.subtract(
vec2.create(), vec2.create(),
PlayerCharacterPhysical.desiredRightFootOffset, CharacterPhysical.desiredRightFootOffset,
PlayerCharacterPhysical.centerOfMass, CharacterPhysical.centerOfMass,
); );
public static readonly boundRadius = public static readonly boundRadius =
(PlayerCharacterPhysical.headRadius + PlayerCharacterPhysical.feetRadius * 2) * 2; (CharacterPhysical.headRadius + CharacterPhysical.feetRadius * 2) * 2;
private timeSinceDying = 0; private timeSinceDying = 0;
private isDestroyed = false; private isDestroyed = false;
@ -102,20 +104,20 @@ export class PlayerCharacterPhysical
) { ) {
super(id(), name, killCount, deathCount, team, settings.playerMaxHealth); super(id(), name, killCount, deathCount, team, settings.playerMaxHealth);
this.head = new CirclePhysical( this.head = new CirclePhysical(
vec2.add(vec2.create(), startPosition, PlayerCharacterPhysical.headOffset), vec2.add(vec2.create(), startPosition, CharacterPhysical.headOffset),
PlayerCharacterPhysical.headRadius, CharacterPhysical.headRadius,
this, this,
container, container,
); );
this.leftFoot = new CirclePhysical( this.leftFoot = new CirclePhysical(
vec2.add(vec2.create(), startPosition, PlayerCharacterPhysical.leftFootOffset), vec2.add(vec2.create(), startPosition, CharacterPhysical.leftFootOffset),
PlayerCharacterPhysical.feetRadius, CharacterPhysical.feetRadius,
this, this,
container, container,
); );
this.rightFoot = new CirclePhysical( this.rightFoot = new CirclePhysical(
vec2.add(vec2.create(), startPosition, PlayerCharacterPhysical.rightFootOffset), vec2.add(vec2.create(), startPosition, CharacterPhysical.rightFootOffset),
PlayerCharacterPhysical.feetRadius, CharacterPhysical.feetRadius,
this, this,
container, container,
); );
@ -125,12 +127,29 @@ export class PlayerCharacterPhysical
this.bound = new CirclePhysical( this.bound = new CirclePhysical(
vec2.create(), vec2.create(),
PlayerCharacterPhysical.boundRadius, CharacterPhysical.boundRadius,
this, this,
container, container,
); );
} }
private hasGeneratedPoints = false;
public getPoints(): { decla: number; red: number } {
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,
};
}
return {
decla: 0,
red: 0,
};
}
public get isAlive(): boolean { public get isAlive(): boolean {
return !this.isDestroyed; return !this.isDestroyed;
} }
@ -154,7 +173,7 @@ export class PlayerCharacterPhysical
this.health -= other.strength; this.health -= other.strength;
this.remoteCall('setHealth', this.health); this.remoteCall('setHealth', this.health);
if (this.health <= 0 && this.isAlive) { if (this.health <= 0 && this.isAlive) {
this.kill(); this.onDie();
other.originator.addKill(); other.originator.addKill();
} }
} }
@ -231,8 +250,8 @@ export class PlayerCharacterPhysical
} }
private animateScaling(q: number) { private animateScaling(q: number) {
this.head.radius = PlayerCharacterPhysical.headRadius * q; this.head.radius = CharacterPhysical.headRadius * q;
this.leftFoot.radius = this.rightFoot.radius = PlayerCharacterPhysical.feetRadius * q; this.leftFoot.radius = this.rightFoot.radius = CharacterPhysical.feetRadius * q;
} }
public getPropertyUpdates(): PropertyUpdatesForObject { public getPropertyUpdates(): PropertyUpdatesForObject {
@ -325,7 +344,7 @@ export class PlayerCharacterPhysical
getBoundingBoxOfCircle( getBoundingBoxOfCircle(
new Circle( new Circle(
this.center, this.center,
PlayerCharacterPhysical.boundRadius + settings.maxGravityDistance, CharacterPhysical.boundRadius + settings.maxGravityDistance,
), ),
), ),
); );
@ -407,25 +426,19 @@ export class PlayerCharacterPhysical
this.springMove( this.springMove(
this.leftFoot, this.leftFoot,
center, center,
PlayerCharacterPhysical.leftFootOffset, CharacterPhysical.leftFootOffset,
deltaTime, deltaTime,
3000, 3000,
); );
this.springMove( this.springMove(
this.rightFoot, this.rightFoot,
center, center,
PlayerCharacterPhysical.rightFootOffset, CharacterPhysical.rightFootOffset,
deltaTime, deltaTime,
3000, 3000,
); );
this.springMove( this.springMove(this.head, center, CharacterPhysical.headOffset, deltaTime, 7000);
this.head,
center,
PlayerCharacterPhysical.headOffset,
deltaTime,
7000,
);
} }
private springMove( private springMove(
@ -462,7 +475,7 @@ export class PlayerCharacterPhysical
} }
private stepBodyPart(part: CirclePhysical, deltaTime: number) { private stepBodyPart(part: CirclePhysical, deltaTime: number) {
const { hitObject } = part.step2(deltaTime); const { hitObject } = part.stepManually(deltaTime);
if (hitObject instanceof PlanetPhysical) { if (hitObject instanceof PlanetPhysical) {
this.secondsSinceOnSurface = 0; this.secondsSinceOnSurface = 0;
this.currentPlanet = hitObject; this.currentPlanet = hitObject;
@ -477,9 +490,9 @@ export class PlayerCharacterPhysical
); );
} }
public kill() { public onDie() {
this.isDestroyed = true; this.isDestroyed = true;
this.remoteCall('kill'); this.remoteCall('onDie');
} }
private destroy() { private destroy() {

View file

@ -1,15 +1,11 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { Circle, GameObject, serializesTo, settings } from 'shared'; import { Circle, GameObject, serializesTo } from 'shared';
import { PhysicalBase } from '../physics/physicals/physical-base';
import { BoundingBox } from '../physics/bounding-boxes/bounding-box'; import { BoundingBox } from '../physics/bounding-boxes/bounding-box';
import { BoundingBoxBase } from '../physics/bounding-boxes/bounding-box-base'; import { BoundingBoxBase } from '../physics/bounding-boxes/bounding-box-base';
import { moveCircle } from '../physics/functions/move-circle'; import { moveCircle } from '../physics/functions/move-circle';
import { PhysicalContainer } from '../physics/containers/physical-container'; import { PhysicalContainer } from '../physics/containers/physical-container';
import { DynamicPhysical } from '../physics/physicals/dynamic-physical'; import { DynamicPhysical } from '../physics/physicals/dynamic-physical';
import { import { ReactsToCollision, reactsToCollision } from './capabilities/reacts-to-collision';
ReactsToCollision,
reactsToCollision,
} from '../physics/functions/reacts-to-collision';
@serializesTo(Circle) @serializesTo(Circle)
export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollision { export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollision {
@ -17,8 +13,9 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio
readonly canMove = true; readonly canMove = true;
public velocity = vec2.create(); public velocity = vec2.create();
public lastNormal = vec2.fromValues(0, 1);
private _boundingBox: BoundingBox; private _boundingBox: BoundingBox;
public lastNormal = vec2.fromValues(1, 0);
constructor( constructor(
private _center: vec2, private _center: vec2,
@ -67,18 +64,6 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio
return vec2.distance(target, this.center) - this.radius; return vec2.distance(target, this.center) - this.radius;
} }
public distanceBetween(target: Circle): number {
return vec2.distance(target.center, this.center) - this.radius - target.radius;
}
public areIntersecting(other: PhysicalBase): boolean {
return other.distance(this.center) < this.radius;
}
public isInside(other: PhysicalBase): boolean {
return other.distance(this.center) < -this.radius;
}
private recalculateBoundingBox() { private recalculateBoundingBox() {
this._boundingBox.xMin = this.center.x - this._radius; this._boundingBox.xMin = this.center.x - this._radius;
this._boundingBox.xMax = this.center.x + this._radius; this._boundingBox.xMax = this.center.x + this._radius;
@ -94,9 +79,7 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio
); );
} }
public step(_: number) {} public stepManually(
public step2(
deltaTimeInSeconds: number, deltaTimeInSeconds: number,
): { hitObject: GameObject | undefined; velocity: vec2 } { ): { hitObject: GameObject | undefined; velocity: vec2 } {
let delta = vec2.scale(vec2.create(), this.velocity, deltaTimeInSeconds); let delta = vec2.scale(vec2.create(), this.velocity, deltaTimeInSeconds);

View file

@ -32,12 +32,6 @@ export class LampPhysical extends LampBase implements StaticPhysical {
return this; return this;
} }
public getForce(_: vec2): vec2 {
return vec2.create();
}
public step(deltaTime: number): void {}
public distance(target: vec2): number { public distance(target: vec2): number {
return vec2.distance(this.center, target); return vec2.distance(this.center, target);
} }

View file

@ -4,8 +4,6 @@ import {
clamp, clamp,
clamp01, clamp01,
id, id,
rotate90Deg,
rotateMinus90Deg,
serializesTo, serializesTo,
settings, settings,
PlanetBase, PlanetBase,
@ -14,12 +12,14 @@ import {
import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box'; import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-bounding-box';
import { StaticPhysical } from '../physics/physicals/static-physical'; import { StaticPhysical } from '../physics/physicals/static-physical';
import { GeneratesPoints } from './generates-points'; import { ExertsForce } from './capabilities/exerts-force';
import { GeneratesPoints } from './capabilities/generates-points';
import { TimeDependent } from './capabilities/time-dependent';
@serializesTo(PlanetBase) @serializesTo(PlanetBase)
export class PlanetPhysical export class PlanetPhysical
extends PlanetBase extends PlanetBase
implements StaticPhysical, GeneratesPoints { implements StaticPhysical, GeneratesPoints, ExertsForce, TimeDependent {
public readonly canCollide = true; public readonly canCollide = true;
public readonly canMove = false; public readonly canMove = false;

View file

@ -13,15 +13,15 @@ import { ImmutableBoundingBox } from '../physics/bounding-boxes/immutable-boundi
import { CirclePhysical } from './circle-physical'; import { CirclePhysical } from './circle-physical';
import { DynamicPhysical } from '../physics/physicals/dynamic-physical'; import { DynamicPhysical } from '../physics/physicals/dynamic-physical';
import { PhysicalContainer } from '../physics/containers/physical-container'; import { PhysicalContainer } from '../physics/containers/physical-container';
import { PlanetPhysical } from './planet-physical'; import { ReactsToCollision } from './capabilities/reacts-to-collision';
import { ReactsToCollision } from '../physics/functions/reacts-to-collision'; import { CharacterPhysical } from './character-physical';
import { PlayerCharacterPhysical } from './player-character-physical';
import { moveCircle } from '../physics/functions/move-circle'; import { moveCircle } from '../physics/functions/move-circle';
import { TimeDependent } from './capabilities/time-dependent';
@serializesTo(ProjectileBase) @serializesTo(ProjectileBase)
export class ProjectilePhysical export class ProjectilePhysical
extends ProjectileBase extends ProjectileBase
implements DynamicPhysical, ReactsToCollision { implements DynamicPhysical, ReactsToCollision, TimeDependent {
public readonly canCollide = true; public readonly canCollide = true;
public readonly canMove = true; public readonly canMove = true;
@ -37,7 +37,7 @@ export class ProjectilePhysical
public strength: number, public strength: number,
team: CharacterTeam, team: CharacterTeam,
private velocity: vec2, private velocity: vec2,
public readonly originator: PlayerCharacterPhysical, public readonly originator: CharacterPhysical,
readonly container: PhysicalContainer, readonly container: PhysicalContainer,
) { ) {
super(id(), center, radius, team, strength); super(id(), center, radius, team, strength);
@ -60,7 +60,7 @@ export class ProjectilePhysical
while (wasCollision) { while (wasCollision) {
const intersecting = this.container const intersecting = this.container
.findIntersecting(this.boundingBox) .findIntersecting(this.boundingBox)
.filter((g) => g instanceof PlayerCharacterPhysical && g.team === this.team); .filter((g) => g instanceof CharacterPhysical && g.team === this.team);
const { hitSurface } = moveCircle(this.object, delta, intersecting, true); const { hitSurface } = moveCircle(this.object, delta, intersecting, true);
wasCollision = hitSurface; wasCollision = hitSurface;
} }
@ -93,7 +93,7 @@ export class ProjectilePhysical
public onCollision(other: GameObject) { public onCollision(other: GameObject) {
if ( if (
!(other instanceof PlayerCharacterPhysical && other.team === this.team) && !(other instanceof CharacterPhysical && other.team === this.team) &&
this.bounceCount++ === settings.projectileMaxBounceCount this.bounceCount++ === settings.projectileMaxBounceCount
) { ) {
this.destroy(); this.destroy();
@ -115,7 +115,7 @@ export class ProjectilePhysical
} }
vec2.copy(this.object.velocity, this.velocity); vec2.copy(this.object.velocity, this.velocity);
const { velocity } = this.object.step2(deltaTime); const { velocity } = this.object.stepManually(deltaTime);
vec2.copy(this.velocity, velocity); vec2.copy(this.velocity, velocity);
} }
} }

View file

@ -1,12 +1,14 @@
import { BoundingBoxBase } from '../bounding-boxes/bounding-box-base'; import { BoundingBoxBase } from '../bounding-boxes/bounding-box-base';
import { BoundingBoxList } from './bounding-box-list'; import { BoundingBoxList } from './bounding-box-list';
import { BoundingBoxTree } from './bounding-box-tree'; import { BoundingBoxTree } from './bounding-box-tree';
import { Physical } from '../physicals/physical'; import { Physical } from '../physicals/physical';
import { StaticPhysical } from '../physicals/static-physical'; import { StaticPhysical } from '../physicals/static-physical';
import { DynamicPhysical } from '../physicals/dynamic-physical'; import { DynamicPhysical } from '../physicals/dynamic-physical';
import { GeneratesPoints, generatesPoints } from '../../objects/generates-points'; import {
GeneratesPoints,
generatesPoints,
} from '../../objects/capabilities/generates-points';
import { timeDependent } from '../../objects/capabilities/time-dependent';
export class PhysicalContainer { export class PhysicalContainer {
private isTreeInitialized = false; private isTreeInitialized = false;
@ -40,7 +42,7 @@ export class PhysicalContainer {
} }
public stepObjects(deltaTime: number) { public stepObjects(deltaTime: number) {
this.objects.forEach((o) => o.step(deltaTime)); this.objects.forEach((o) => timeDependent(o) && o.step(deltaTime));
} }
public resetRemoteCalls() { public resetRemoteCalls() {

View file

@ -1,9 +1,10 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { exertsForce } from '../../objects/capabilities/exerts-force';
import { Physical } from '../physicals/physical'; import { Physical } from '../physicals/physical';
export const forceAtPosition = (position: vec2, objects: Array<Physical>) => export const forceAtPosition = (position: vec2, objects: Array<Physical>) =>
objects.reduce( objects.reduce(
(sum: vec2, o: Physical) => (sum: vec2, o: Physical) =>
!o.canMove ? vec2.add(sum, sum, o.getForce(position)) : sum, exertsForce(o) ? vec2.add(sum, sum, o.getForce(position)) : sum,
vec2.create(), vec2.create(),
); );

View file

@ -1,7 +1,7 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { Circle, GameObject, rotate90Deg } from 'shared'; import { Circle, GameObject, rotate90Deg } from 'shared';
import { CirclePhysical } from '../../objects/circle-physical'; import { CirclePhysical } from '../../objects/circle-physical';
import { reactsToCollision } from './reacts-to-collision'; import { reactsToCollision } from '../../objects/capabilities/reacts-to-collision';
import { evaluateSdf } from './evaluate-sdf'; import { evaluateSdf } from './evaluate-sdf';
import { Physical } from '../physicals/physical'; import { Physical } from '../physicals/physical';
@ -11,10 +11,8 @@ export const moveCircle = (
possibleIntersectors: Array<Physical>, possibleIntersectors: Array<Physical>,
ignoreCollision = false, ignoreCollision = false,
): { ): {
realDelta: vec2;
hitSurface: boolean; hitSurface: boolean;
normal?: vec2; normal?: vec2;
tangent?: vec2;
hitObject?: GameObject; hitObject?: GameObject;
} => { } => {
const direction = vec2.clone(delta); const direction = vec2.clone(delta);
@ -78,16 +76,10 @@ export const moveCircle = (
]); ]);
const normal = vec2.fromValues(dx, dy); const normal = vec2.fromValues(dx, dy);
vec2.normalize(normal, normal); vec2.normalize(normal, normal);
const rotatedNormal = rotate90Deg(normal);
return { return {
realDelta: delta,
hitSurface: true, hitSurface: true,
normal, normal,
hitObject: intersecting?.gameObject, hitObject: intersecting?.gameObject,
tangent:
vec2.dot(rotatedNormal, delta) < 0
? vec2.scale(rotatedNormal, rotatedNormal, -1)
: rotatedNormal,
}; };
} }
@ -97,7 +89,6 @@ export const moveCircle = (
vec2.add(circle.center, circle.center, delta); vec2.add(circle.center, circle.center, delta);
return { return {
realDelta: delta,
hitSurface: false, hitSurface: false,
}; };
}; };

View file

@ -9,5 +9,4 @@ export interface PhysicalBase {
readonly gameObject: GameObject; readonly gameObject: GameObject;
distance(target: vec2): number; distance(target: vec2): number;
step(deltaTime: number): void;
} }

View file

@ -1,10 +1,7 @@
import { PhysicalBase } from './physical-base'; import { PhysicalBase } from './physical-base';
import { ImmutableBoundingBox } from '../bounding-boxes/immutable-bounding-box'; import { ImmutableBoundingBox } from '../bounding-boxes/immutable-bounding-box';
import { vec2 } from 'gl-matrix';
export interface StaticPhysical extends PhysicalBase { export interface StaticPhysical extends PhysicalBase {
readonly canMove: false; readonly canMove: false;
readonly boundingBox: ImmutableBoundingBox; readonly boundingBox: ImmutableBoundingBox;
getForce(target: vec2): vec2;
} }

View file

@ -1,17 +1,17 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { import {
PlayerInformation, PlayerInformation,
CharacterTeam,
settings, settings,
Circle, Circle,
Random, Random,
MoveActionCommand, MoveActionCommand,
CharacterTeam,
} from 'shared'; } from 'shared';
import { PhysicalContainer } from '../physics/containers/physical-container'; import { PhysicalContainer } from '../physics/containers/physical-container';
import { PlayerContainer } from './player-container'; import { PlayerContainer } from './player-container';
import { PlayerBase } from './player-base'; import { PlayerBase } from './player-base';
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
import { PlayerCharacterPhysical } from '../objects/player-character-physical'; import { CharacterPhysical } from '../objects/character-physical';
import { PlanetPhysical } from '../objects/planet-physical'; import { PlanetPhysical } from '../objects/planet-physical';
import { Physical } from '../physics/physicals/physical'; import { Physical } from '../physics/physicals/physical';
@ -98,22 +98,18 @@ export class NPC extends PlayerBase {
private findNearCharactersSorted( private findNearCharactersSorted(
nearObjects: Array<Physical>, nearObjects: Array<Physical>,
): Array<{ character: PlayerCharacterPhysical; distance: number }> { ): Array<{ character: CharacterPhysical; distance: number }> {
const characters = Array.from( const characters = Array.from(
new Set( new Set(
nearObjects.filter( nearObjects.filter(
(o) => (o) =>
o.gameObject instanceof PlayerCharacterPhysical && o.gameObject instanceof CharacterPhysical && o.gameObject !== this.character,
o.gameObject !== this.character,
), ),
), ),
).map((c) => ({ ).map((c) => ({
character: c.gameObject, character: c.gameObject,
distance: vec2.distance( distance: vec2.distance(this.center, (c.gameObject as CharacterPhysical).center),
this.center, })) as Array<{ character: CharacterPhysical; distance: number }>;
(c.gameObject as PlayerCharacterPhysical).center,
),
})) as Array<{ character: PlayerCharacterPhysical; distance: number }>;
characters.sort((a, b) => a.distance - b.distance); characters.sort((a, b) => a.distance - b.distance);
@ -139,12 +135,10 @@ export class NPC extends PlayerBase {
const nearObjects = this.objectContainer.findIntersecting(observableArea); const nearObjects = this.objectContainer.findIntersecting(observableArea);
const enemies = nearObjects.filter( const enemies = nearObjects.filter(
(o) => (o) => o.gameObject instanceof CharacterPhysical && o.gameObject.team !== this.team,
o.gameObject instanceof PlayerCharacterPhysical &&
o.gameObject.team !== this.team,
); );
if (enemies.length > 0) { if (enemies.length > 0) {
return (enemies[0].gameObject as PlayerCharacterPhysical).center; return (enemies[0].gameObject as CharacterPhysical).center;
} }
} }

View file

@ -3,11 +3,11 @@ import { CommandReceiver, Circle, PlayerInformation, CharacterTeam } from 'share
import { PhysicalContainer } from '../physics/containers/physical-container'; import { PhysicalContainer } from '../physics/containers/physical-container';
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting'; import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting';
import { PlayerCharacterPhysical } from '../objects/player-character-physical'; import { CharacterPhysical } from '../objects/character-physical';
import { PlayerContainer } from './player-container'; import { PlayerContainer } from './player-container';
export abstract class PlayerBase extends CommandReceiver { export abstract class PlayerBase extends CommandReceiver {
public character?: PlayerCharacterPhysical | null; public character?: CharacterPhysical | null;
public center: vec2 = vec2.create(); public center: vec2 = vec2.create();
protected sumKills = 0; protected sumKills = 0;
@ -23,7 +23,7 @@ export abstract class PlayerBase extends CommandReceiver {
} }
protected createCharacter(preferredCenter: vec2) { protected createCharacter(preferredCenter: vec2) {
this.character = new PlayerCharacterPhysical( this.character = new CharacterPhysical(
this.playerInfo.name.slice(0, 20), this.playerInfo.name.slice(0, 20),
this.sumKills, this.sumKills,
this.sumDeaths, this.sumDeaths,
@ -52,7 +52,7 @@ export abstract class PlayerBase extends CommandReceiver {
const playerBoundingCircle = new Circle( const playerBoundingCircle = new Circle(
playerPosition, playerPosition,
PlayerCharacterPhysical.boundRadius, CharacterPhysical.boundRadius,
); );
const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle); const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle);
@ -69,6 +69,6 @@ export abstract class PlayerBase extends CommandReceiver {
} }
public destroy() { public destroy() {
this.character?.kill(); this.character?.onDie();
} }
} }

View file

@ -9,7 +9,6 @@ import {
TransportEvents, TransportEvents,
SetAspectRatioActionCommand, SetAspectRatioActionCommand,
calculateViewArea, calculateViewArea,
SecondaryActionCommand,
settings, settings,
PlayerInformation, PlayerInformation,
CharacterTeam, CharacterTeam,
@ -26,18 +25,15 @@ import {
} from 'shared'; } from 'shared';
import { BoundingBox } from '../physics/bounding-boxes/bounding-box'; import { BoundingBox } from '../physics/bounding-boxes/bounding-box';
import { PhysicalContainer } from '../physics/containers/physical-container'; import { PhysicalContainer } from '../physics/containers/physical-container';
import { PlayerCharacterPhysical } from '../objects/player-character-physical'; import { CharacterPhysical } from '../objects/character-physical';
import { PlayerContainer } from './player-container'; import { PlayerContainer } from './player-container';
import { PlayerBase } from './player-base'; import { PlayerBase } from './player-base';
import { DeltaTimeCalculator } from '../helper/delta-time-calculator';
export class Player extends PlayerBase { export class Player extends PlayerBase {
// default, until the clients sends its real value
private aspectRatio: number = 16 / 9; private aspectRatio: number = 16 / 9;
private isActive = true;
private objectsPreviouslyInViewArea: Array<GameObject> = []; private objectsPreviouslyInViewArea: Array<GameObject> = [];
private pingDeltaTime = new DeltaTimeCalculator();
private _latency?: number;
protected commandExecutors: CommandExecutors = { protected commandExecutors: CommandExecutors = {
[SetAspectRatioActionCommand.type]: (v: SetAspectRatioActionCommand) => [SetAspectRatioActionCommand.type]: (v: SetAspectRatioActionCommand) =>
@ -57,31 +53,10 @@ export class Player extends PlayerBase {
private readonly socket: SocketIO.Socket, private readonly socket: SocketIO.Socket,
) { ) {
super(playerInfo, playerContainer, objectContainer, team); super(playerInfo, playerContainer, objectContainer, team);
this.createCharacter(); this.createCharacter();
socket.on(
TransportEvents.Pong,
() => (this._latency = this.pingDeltaTime.getNextDeltaTimeInSeconds()),
);
this.measureLatency();
this.step(0); this.step(0);
} }
public measureLatency() {
this.pingDeltaTime.getNextDeltaTimeInSeconds(true);
this.socket.emit(TransportEvents.Ping);
if (this.isActive) {
setTimeout(this.measureLatency.bind(this), 10000);
}
}
public get latency(): number | undefined {
return this._latency;
}
protected createCharacter() { protected createCharacter() {
const preferredCenter = this.playerContainer.players.find( const preferredCenter = this.playerContainer.players.find(
(p) => p.character?.isAlive && p.team === this.team, (p) => p.character?.isAlive && p.team === this.team,
@ -191,7 +166,7 @@ export class Player extends PlayerBase {
const playersInViewArea = this.objectContainer const playersInViewArea = this.objectContainer
.findIntersecting(bb) .findIntersecting(bb)
.map((o) => o.gameObject) .map((o) => o.gameObject)
.filter((g) => g instanceof PlayerCharacterPhysical); .filter((g) => g instanceof CharacterPhysical);
const otherPlayers = this.playerContainer.players.filter( const otherPlayers = this.playerContainer.players.filter(
(p) => p.character?.isAlive && playersInViewArea.indexOf(p.character!) < 0, (p) => p.character?.isAlive && playersInViewArea.indexOf(p.character!) < 0,
@ -222,6 +197,5 @@ export class Player extends PlayerBase {
public destroy() { public destroy() {
super.destroy(); super.destroy();
this.isActive = false;
} }
} }

View file

@ -48,11 +48,11 @@
minlength="1" minlength="1"
maxlength="20" maxlength="20"
placeholder=" " placeholder=" "
id="playerName" id="name"
name="playerName" name="name"
type="text" type="text"
/> />
<label for="playerName">Choose a name</label> <label for="name">Choose a name</label>
</div> </div>
<div id="server-container"></div> <div id="server-container"></div>

View file

@ -3,7 +3,7 @@ import {
LampBase, LampBase,
overrideDeserialization, overrideDeserialization,
PlanetBase, PlanetBase,
PlayerCharacterBase, CharacterBase,
ProjectileBase, ProjectileBase,
} from 'shared'; } from 'shared';
import { LampView } from './scripts/objects/lamp-view'; import { LampView } from './scripts/objects/lamp-view';
@ -17,9 +17,9 @@ import '../static/favicons/favicon-32x32.png';
import '../static/favicons/favicon.ico'; import '../static/favicons/favicon.ico';
import { LandingPageBackground } from './scripts/landing-page-background'; import { LandingPageBackground } from './scripts/landing-page-background';
import { JoinFormHandler } from './scripts/join-form-handler'; import { JoinFormHandler } from './scripts/join-form-handler';
import { handleFullScreen } from './scripts/handle-full-screen'; import { handleFullScreen } from './scripts/helper/handle-full-screen';
import { Game } from './scripts/game'; import { Game } from './scripts/game';
import { PlayerCharacterView } from './scripts/objects/player-character-view'; import { CharacterView } from './scripts/objects/character-view';
import { handleInsights } from './scripts/handle-insights'; import { handleInsights } from './scripts/handle-insights';
import { getInsightsFromRenderer } from './scripts/get-insights-from-renderer'; import { getInsightsFromRenderer } from './scripts/get-insights-from-renderer';
import { Renderer } from 'sdf-2d'; import { Renderer } from 'sdf-2d';
@ -32,12 +32,13 @@ import { VibrationHandler } from './scripts/vibration-handler';
glMatrix.setMatrixArrayType(Array); glMatrix.setMatrixArrayType(Array);
overrideDeserialization(PlayerCharacterBase, PlayerCharacterView); overrideDeserialization(CharacterBase, CharacterView);
overrideDeserialization(PlanetBase, PlanetView); overrideDeserialization(PlanetBase, PlanetView);
overrideDeserialization(LampBase, LampView); overrideDeserialization(LampBase, LampView);
overrideDeserialization(ProjectileBase, ProjectileView); overrideDeserialization(ProjectileBase, ProjectileView);
const landingUI = document.querySelector('#landing-ui') as HTMLElement; const landingUI = document.querySelector('#landing-ui') as HTMLElement;
const nameInput = document.querySelector('#name') as HTMLInputElement;
const joinGameForm = document.querySelector('#join-game-form') as HTMLFormElement; const joinGameForm = document.querySelector('#join-game-form') as HTMLFormElement;
const serverContainer = document.querySelector('#server-container') as HTMLElement; const serverContainer = document.querySelector('#server-container') as HTMLElement;
const canvas = document.querySelector('canvas') as HTMLCanvasElement; const canvas = document.querySelector('canvas') as HTMLCanvasElement;
@ -114,6 +115,11 @@ const main = async () => {
try { try {
let game: Game; let game: Game;
const storedUserName = localStorage?.getItem('userName');
if (storedUserName) {
nameInput.value = JSON.parse(storedUserName);
}
const firstClickListener = () => { const firstClickListener = () => {
SoundHandler.initialize( SoundHandler.initialize(
() => { () => {
@ -166,6 +172,9 @@ const main = async () => {
hide(spinner); hide(spinner);
const playerDecision = await joinHandler.getPlayerDecision(); const playerDecision = await joinHandler.getPlayerDecision();
localStorage?.setItem('userName', JSON.stringify(playerDecision.name));
if (!history.state) { if (!history.state) {
history.pushState(true, ''); history.pushState(true, '');
} }

View file

@ -3,11 +3,11 @@ import { CommandGenerator, PrimaryActionCommand, SecondaryActionCommand } from '
import { Game } from '../game'; import { Game } from '../game';
export class MouseListener extends CommandGenerator { export class MouseListener extends CommandGenerator {
constructor(private readonly game: Game) { constructor(private target: HTMLElement, private readonly game: Game) {
super(); super();
addEventListener('mousedown', this.mouseDownListener); target.addEventListener('mousedown', this.mouseDownListener);
addEventListener('contextmenu', this.contextMenuListener); target.addEventListener('contextmenu', this.contextMenuListener);
} }
private mouseDownListener = (event: MouseEvent) => { private mouseDownListener = (event: MouseEvent) => {
@ -32,7 +32,7 @@ export class MouseListener extends CommandGenerator {
} }
public destroy() { public destroy() {
removeEventListener('mousedown', this.mouseDownListener); this.target.removeEventListener('mousedown', this.mouseDownListener);
removeEventListener('contextmenu', this.contextMenuListener); this.target.removeEventListener('contextmenu', this.contextMenuListener);
} }
} }

View file

@ -1,5 +1,12 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { Renderer, renderNoise } from 'sdf-2d'; import {
CircleLight,
FilteringOptions,
Renderer,
renderNoise,
runAnimation,
WrapOptions,
} from 'sdf-2d';
import { import {
deserialize, deserialize,
TransportEvents, TransportEvents,
@ -9,22 +16,23 @@ import {
clamp, clamp,
UpdateGameState, UpdateGameState,
GameEndCommand, GameEndCommand,
CharacterTeam,
ServerAnnouncement, ServerAnnouncement,
GameStartCommand, GameStartCommand,
CommandReceiver, CommandReceiver,
CommandExecutors, CommandExecutors,
Command, Command,
settings,
} from 'shared'; } from 'shared';
import io from 'socket.io-client'; import io from 'socket.io-client';
import { KeyboardListener } from './commands/keyboard-listener'; import { KeyboardListener } from './commands/keyboard-listener';
import { MouseListener } from './commands/mouse-listener'; import { MouseListener } from './commands/mouse-listener';
import { TouchListener } from './commands/touch-listener'; import { TouchListener } from './commands/touch-listener';
import { CommandSocket } from './commands/command-socket'; import { CommandSocket } from './commands/command-socket';
import { startAnimation } from './start-animation';
import { PlayerDecision } from './join-form-handler'; import { PlayerDecision } from './join-form-handler';
import { GameObjectContainer } from './objects/game-object-container'; import { GameObjectContainer } from './objects/game-object-container';
import parser from 'socket.io-msgpack-parser'; import parser from 'socket.io-msgpack-parser';
import { BlobShape } from './shapes/blob-shape';
import { PlanetShape } from './shapes/planet-shape';
export class Game extends CommandReceiver { export class Game extends CommandReceiver {
public gameObjects = new GameObjectContainer(this); public gameObjects = new GameObjectContainer(this);
@ -59,8 +67,8 @@ export class Game extends CommandReceiver {
this.progressBar.appendChild(this.redPlanetCountElement); this.progressBar.appendChild(this.redPlanetCountElement);
this.keyboardListener = new KeyboardListener(); this.keyboardListener = new KeyboardListener();
this.mouseListener = new MouseListener(this); this.mouseListener = new MouseListener(this.canvas, this);
this.touchListener = new TouchListener(this.overlay, this.overlay, this); this.touchListener = new TouchListener(this.canvas, this.overlay, this);
} }
private initialize() { private initialize() {
@ -111,9 +119,7 @@ export class Game extends CommandReceiver {
this.isBetweenGames = false; this.isBetweenGames = false;
this.socket.emit(TransportEvents.PlayerJoining, { this.socket.emit(TransportEvents.PlayerJoining, this.playerDecision);
name: this.playerDecision.playerName,
} as PlayerInformation);
} }
protected defaultCommandExecutor(c: Command) { protected defaultCommandExecutor(c: Command) {
@ -200,7 +206,35 @@ export class Game extends CommandReceiver {
this.initialize(); this.initialize();
await startAnimation(this.canvas, this.gameLoop.bind(this), noiseTexture); await runAnimation(
this.canvas,
[
PlanetShape.descriptor,
BlobShape.descriptor,
{
...CircleLight.descriptor,
shaderCombinationSteps: [0, 1, 2, 4, 8, 16],
},
],
this.gameLoop.bind(this),
{
shadowTraceCount: 16,
paletteSize: settings.palette.length,
colorPalette: settings.palette,
enableHighDpiRendering: true,
lightCutoffDistance: settings.lightCutoffDistance,
textures: {
noiseTexture: {
source: noiseTexture,
overrides: {
maxFilter: FilteringOptions.LINEAR,
wrapS: WrapOptions.MIRRORED_REPEAT,
wrapT: WrapOptions.MIRRORED_REPEAT,
},
},
},
},
);
this.socket.close(); this.socket.close();
this.overlay.innerHTML = ''; this.overlay.innerHTML = '';
this.keyboardListener.destroy(); this.keyboardListener.destroy();

View file

@ -1,4 +1,4 @@
import { SoundHandler, Sounds } from './sound-handler'; import { SoundHandler, Sounds } from '../sound-handler';
export const handleFullScreen = ( export const handleFullScreen = (
minimizeButton: HTMLElement, minimizeButton: HTMLElement,

View file

@ -5,7 +5,7 @@ import parser from 'socket.io-msgpack-parser';
import { SoundHandler, Sounds } from './sound-handler'; import { SoundHandler, Sounds } from './sound-handler';
export type PlayerDecision = { export type PlayerDecision = {
playerName: string; name: string;
server: string; server: string;
}; };

View file

@ -1,7 +1,6 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { import {
CircleLight, CircleLight,
compile,
FilteringOptions, FilteringOptions,
hsl, hsl,
NoisyPolygonFactory, NoisyPolygonFactory,

View file

@ -3,7 +3,7 @@ import { Renderer } from 'sdf-2d';
import { import {
Circle, Circle,
Id, Id,
PlayerCharacterBase, CharacterBase,
CharacterTeam, CharacterTeam,
settings, settings,
UpdateProperty, UpdateProperty,
@ -14,7 +14,7 @@ import { SoundHandler, Sounds } from '../sound-handler';
import { VibrationHandler } from '../vibration-handler'; import { VibrationHandler } from '../vibration-handler';
import { ViewObject } from './view-object'; import { ViewObject } from './view-object';
export class PlayerCharacterView extends PlayerCharacterBase implements ViewObject { export class CharacterView extends CharacterBase implements ViewObject {
private shape: BlobShape; private shape: BlobShape;
private nameElement: HTMLElement = document.createElement('div'); private nameElement: HTMLElement = document.createElement('div');
private statsElement: HTMLElement = document.createElement('div'); private statsElement: HTMLElement = document.createElement('div');
@ -81,7 +81,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje
} }
} }
public kill() { public onDie() {
if (this.isMainCharacter) { if (this.isMainCharacter) {
VibrationHandler.vibrate(150); VibrationHandler.vibrate(150);
} }

View file

@ -11,12 +11,12 @@ import {
} from 'shared'; } from 'shared';
import { Game } from '../game'; import { Game } from '../game';
import { Camera } from './camera'; import { Camera } from './camera';
import { PlayerCharacterView } from './player-character-view'; import { CharacterView } from './character-view';
import { ViewObject } from './view-object'; import { ViewObject } from './view-object';
export class GameObjectContainer extends CommandReceiver { export class GameObjectContainer extends CommandReceiver {
protected objects: Map<Id, ViewObject> = new Map(); protected objects: Map<Id, ViewObject> = new Map();
public player!: PlayerCharacterView; public player!: CharacterView;
public camera!: Camera; public camera!: Camera;
protected commandExecutors: CommandExecutors = { protected commandExecutors: CommandExecutors = {
@ -25,7 +25,7 @@ export class GameObjectContainer extends CommandReceiver {
this.deleteObject(this.camera.id); this.deleteObject(this.camera.id);
} }
this.player = c.character as PlayerCharacterView; this.player = c.character as CharacterView;
this.player.isMainCharacter = true; this.player.isMainCharacter = true;
this.camera = new Camera(this.game); this.camera = new Camera(this.game);

View file

@ -1,45 +0,0 @@
import {
CircleLight,
FilteringOptions,
Renderer,
runAnimation,
WrapOptions,
} from 'sdf-2d';
import { settings } from 'shared';
import { BlobShape } from './shapes/blob-shape';
import { PlanetShape } from './shapes/planet-shape';
export const startAnimation = async (
canvas: HTMLCanvasElement,
draw: (r: Renderer, current: number, delta: number) => boolean,
noiseTexture: TexImageSource,
): Promise<void> =>
await runAnimation(
canvas,
[
PlanetShape.descriptor,
BlobShape.descriptor,
{
...CircleLight.descriptor,
shaderCombinationSteps: [0, 1, 2, 4, 8, 16],
},
],
draw,
{
shadowTraceCount: 16,
paletteSize: settings.palette.length,
colorPalette: settings.palette,
enableHighDpiRendering: true,
lightCutoffDistance: settings.lightCutoffDistance,
textures: {
noiseTexture: {
source: noiseTexture,
overrides: {
maxFilter: FilteringOptions.LINEAR,
wrapS: WrapOptions.MIRRORED_REPEAT,
wrapT: WrapOptions.MIRRORED_REPEAT,
},
},
},
},
);

View file

@ -1,10 +1,10 @@
import { PlayerCharacterBase } from '../../objects/types/player-character-base'; import { CharacterBase } from '../../objects/types/character-base';
import { serializable } from '../../serialization/serializable'; import { serializable } from '../../serialization/serializable';
import { Command } from '../command'; import { Command } from '../command';
@serializable @serializable
export class CreatePlayerCommand extends Command { export class CreatePlayerCommand extends Command {
public constructor(public readonly character: PlayerCharacterBase) { public constructor(public readonly character: CharacterBase) {
super(); super();
} }

View file

@ -1,4 +1,4 @@
import { CharacterTeam } from '../../objects/types/character-team'; import { CharacterTeam } from '../../objects/types/character-base';
import { serializable } from '../../serialization/serializable'; import { serializable } from '../../serialization/serializable';
import { Command } from '../command'; import { Command } from '../command';

View file

@ -1,6 +1,6 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { Id } from '../../communication/id'; import { Id } from '../../communication/id';
import { CharacterTeam } from '../../objects/types/character-team'; import { CharacterTeam } from '../../objects/types/character-base';
import { serializable } from '../../serialization/serializable'; import { serializable } from '../../serialization/serializable';
import { Command } from '../command'; import { Command } from '../command';

View file

@ -9,10 +9,6 @@ export class Circle {
return vec2.distance(this.center, target) - this.radius; return vec2.distance(this.center, target) - this.radius;
} }
public distanceBetween(target: Circle): number {
return vec2.distance(target.center, this.center) - this.radius - target.radius;
}
public toArray(): Array<any> { public toArray(): Array<any> {
return [this.center, this.radius]; return [this.center, this.radius];
} }

View file

@ -40,8 +40,7 @@ export * from './serialization/serialize';
export * from './serialization/serializes-to'; export * from './serialization/serializes-to';
export * from './serialization/serializable'; export * from './serialization/serializable';
export * from './serialization/override-deserialization'; export * from './serialization/override-deserialization';
export * from './objects/types/character-team'; export * from './objects/types/character-base';
export * from './objects/types/player-character-base';
export * from './objects/types/lamp-base'; export * from './objects/types/lamp-base';
export * from './objects/types/planet-base'; export * from './objects/types/planet-base';
export * from './objects/types/projectile-base'; export * from './objects/types/projectile-base';

View file

@ -2,10 +2,15 @@ import { Id } from '../../communication/id';
import { Circle } from '../../helper/circle'; import { Circle } from '../../helper/circle';
import { serializable } from '../../serialization/serializable'; import { serializable } from '../../serialization/serializable';
import { GameObject } from '../game-object'; import { GameObject } from '../game-object';
import { CharacterTeam } from './character-team';
export enum CharacterTeam {
decla = 'decla',
neutral = 'neutral',
red = 'red',
}
@serializable @serializable
export class PlayerCharacterBase extends GameObject { export class CharacterBase extends GameObject {
constructor( constructor(
id: Id, id: Id,
public name: string, public name: string,
@ -26,7 +31,7 @@ export class PlayerCharacterBase extends GameObject {
this.health = health; this.health = health;
} }
public kill() {} public onDie() {}
public setKillCount(killCount: number) { public setKillCount(killCount: number) {
this.killCount = killCount; this.killCount = killCount;

View file

@ -1,5 +0,0 @@
export enum CharacterTeam {
decla = 'decla',
neutral = 'neutral',
red = 'red',
}

View file

@ -2,8 +2,8 @@ import { vec2 } from 'gl-matrix';
import { settings } from '../../settings'; import { settings } from '../../settings';
import { serializable } from '../../serialization/serializable'; import { serializable } from '../../serialization/serializable';
import { GameObject } from '../game-object'; import { GameObject } from '../game-object';
import { CharacterTeam } from './character-team';
import { Id } from '../../communication/id'; import { Id } from '../../communication/id';
import { CharacterTeam } from './character-base';
@serializable @serializable
export class ProjectileBase extends GameObject { export class ProjectileBase extends GameObject {

View file

@ -1,5 +1,5 @@
import { rgb255 } from './helper/rgb255'; import { rgb255 } from './helper/rgb255';
import { CharacterTeam } from './objects/types/character-team'; import { CharacterTeam } from './objects/types/character-base';
const declaColor = rgb255(64, 105, 165); const declaColor = rgb255(64, 105, 165);
const neutralColor = rgb255(82, 165, 64); const neutralColor = rgb255(82, 165, 64);
@ -19,6 +19,7 @@ export const settings = {
worldRadius: 10000, worldRadius: 10000,
objectsOnCircleLength: 0.002, objectsOnCircleLength: 0.002,
planetEdgeCount: 7, planetEdgeCount: 7,
playerKillPoint: 10,
takeControlTimeInSeconds: 4, takeControlTimeInSeconds: 4,
loseControlTimeInSeconds: 24, loseControlTimeInSeconds: 24,
planetPointGenerationInterval: 1.5, planetPointGenerationInterval: 1.5,