Add player container

This commit is contained in:
schmelczerandras 2020-10-24 10:01:54 +02:00
parent 1cd8f5fbe6
commit b55e927a34
16 changed files with 159 additions and 133 deletions

View file

@ -1,5 +1,4 @@
import { PhysicalContainer } from './physics/containers/physical-container'; import { PhysicalContainer } from './physics/containers/physical-container';
import { Player } from './players/player';
import ioserver from 'socket.io'; import ioserver from 'socket.io';
import { import {
TransportEvents, TransportEvents,
@ -11,18 +10,22 @@ import {
import { createWorld } from './map/create-world'; import { createWorld } from './map/create-world';
import { DeltaTimeCalculator } from './helper/delta-time-calculator'; import { DeltaTimeCalculator } from './helper/delta-time-calculator';
import { Options } from './options'; import { Options } from './options';
import { PlayerContainer } from './players/player-container';
const playerCountSubscribedRoom = 'playerCountUpdates'; const playerCountSubscribedRoom = 'playerCountUpdates';
export class GameServer { export class GameServer {
private objects = new PhysicalContainer(); private objects = new PhysicalContainer();
private players: Array<Player> = []; private players: PlayerContainer;
private deltaTimes: Array<number> = []; private deltaTimes: Array<number> = [];
private deltaTimeCalculator = new DeltaTimeCalculator(); private deltaTimeCalculator = new DeltaTimeCalculator();
private serverName: string; private serverName: string;
private playerLimit: number; private playerLimit: number;
constructor(private readonly io: ioserver.Server, options: Options) { constructor(private readonly io: ioserver.Server, options: Options) {
this.players = new PlayerContainer(this.objects);
this.serverName = options.name; this.serverName = options.name;
this.playerLimit = options.playerLimit; this.playerLimit = options.playerLimit;
@ -31,8 +34,7 @@ export class GameServer {
io.on('connection', (socket: SocketIO.Socket) => { io.on('connection', (socket: SocketIO.Socket) => {
socket.on(TransportEvents.PlayerJoining, (playerInfo: PlayerInformation) => { socket.on(TransportEvents.PlayerJoining, (playerInfo: PlayerInformation) => {
const player = new Player(playerInfo, this.players, this.objects, socket); const player = this.players.createPlayer(playerInfo, socket);
this.players.push(player);
socket.on(TransportEvents.PlayerToServer, (json: string) => { socket.on(TransportEvents.PlayerToServer, (json: string) => {
const command = deserialize(json); const command = deserialize(json);
player.sendCommand(command); player.sendCommand(command);
@ -42,7 +44,7 @@ export class GameServer {
socket.on('disconnect', () => { socket.on('disconnect', () => {
player.destroy(); player.destroy();
this.players = this.players.filter((p) => p !== player); this.players.deletePlayer(player);
this.sendPlayerCountUpdate(); this.sendPlayerCountUpdate();
}); });
}); });
@ -56,7 +58,7 @@ export class GameServer {
public sendPlayerCountUpdate() { public sendPlayerCountUpdate() {
this.io this.io
.to(playerCountSubscribedRoom) .to(playerCountSubscribedRoom)
.emit(TransportEvents.PlayerCountUpdate, this.players.length); .emit(TransportEvents.PlayerCountUpdate, this.players.count);
} }
public start() { public start() {
@ -64,8 +66,7 @@ export class GameServer {
} }
private handlePhysics() { private handlePhysics() {
const delta = this.deltaTimeCalculator.getNextDeltaTimeInMilliseconds(); const delta = this.deltaTimeCalculator.getNextDeltaTimeInSeconds();
this.deltaTimes.push(delta);
const framesBetweenDeltaTimeCalculation = 1000; const framesBetweenDeltaTimeCalculation = 1000;
if (this.deltaTimes.length > framesBetweenDeltaTimeCalculation) { if (this.deltaTimes.length > framesBetweenDeltaTimeCalculation) {
@ -79,15 +80,15 @@ export class GameServer {
`Memory used: ${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`, `Memory used: ${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`,
); );
this.deltaTimes = []; this.deltaTimes = [];
console.log(this.players.map((p) => p.latency));
} }
this.objects.stepObjects(delta / 1000); this.objects.stepObjects(delta);
this.players.forEach((p) => p.step(delta / 1000)); this.players.step(delta);
const physicsDelta = this.deltaTimeCalculator.getDeltaTimeInMilliseconds(); const physicsDelta = this.deltaTimeCalculator.getDeltaTimeInSeconds() * 1000;
this.deltaTimes.push(physicsDelta); this.deltaTimes.push(physicsDelta);
const sleepTime = settings.targetPhysicsDeltaTimeInMilliseconds - physicsDelta; const sleepTime = settings.targetPhysicsDeltaTimeInMilliseconds - physicsDelta;
if (sleepTime >= settings.minPhysicsSleepTime) { if (sleepTime >= settings.minPhysicsSleepTime) {
setTimeout(this.handlePhysics.bind(this), sleepTime); setTimeout(this.handlePhysics.bind(this), sleepTime);
} else { } else {
@ -98,7 +99,7 @@ export class GameServer {
public get serverInfo(): ServerInformation { public get serverInfo(): ServerInformation {
return { return {
serverName: this.serverName, serverName: this.serverName,
playerCount: this.players.length, playerCount: this.players.count,
playerLimit: this.playerLimit, playerLimit: this.playerLimit,
}; };
} }

View file

@ -1,20 +1,20 @@
export class DeltaTimeCalculator { export class DeltaTimeCalculator {
private previousTime: [number, number] = process.hrtime(); private previousTime: [number, number] = process.hrtime();
public getNextDeltaTimeInMilliseconds(): number { public getNextDeltaTimeInSeconds(): number {
const deltaTime = process.hrtime(this.previousTime); const deltaTime = process.hrtime(this.previousTime);
this.previousTime = process.hrtime(); this.previousTime = process.hrtime();
const [seconds, nanoSeconds] = deltaTime; const [seconds, nanoSeconds] = deltaTime;
return seconds * 1000 + nanoSeconds / 1000 / 1000; return seconds * 1000 + nanoSeconds / 1000 / 1000 / 1000;
} }
public getDeltaTimeInMilliseconds(): number { public getDeltaTimeInSeconds(): number {
const deltaTime = process.hrtime(this.previousTime); const deltaTime = process.hrtime(this.previousTime);
const [seconds, nanoSeconds] = deltaTime; const [seconds, nanoSeconds] = deltaTime;
return seconds * 1000 + nanoSeconds / 1000 / 1000; return seconds * 1000 + nanoSeconds / 1000 / 1000 / 1000;
} }
} }

View file

@ -97,12 +97,11 @@ export class PlayerCharacterPhysical
name: string, name: string,
killCount: number, killCount: number,
deathCount: number, deathCount: number,
public readonly colorIndex: number,
team: CharacterTeam, team: CharacterTeam,
private readonly container: PhysicalContainer, private readonly container: PhysicalContainer,
startPosition: vec2, startPosition: vec2,
) { ) {
super(id(), name, killCount, deathCount, colorIndex, 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, PlayerCharacterPhysical.headOffset),
@ -176,7 +175,6 @@ export class PlayerCharacterPhysical
const projectile = new ProjectilePhysical( const projectile = new ProjectilePhysical(
vec2.clone(this.center), vec2.clone(this.center),
20, 20,
this.colorIndex,
strength, strength,
this.team, this.team,
velocity, velocity,

View file

@ -34,14 +34,13 @@ export class ProjectilePhysical
constructor( constructor(
center: vec2, center: vec2,
radius: number, radius: number,
colorIndex: number,
public strength: number, public strength: number,
public team: CharacterTeam, team: CharacterTeam,
private velocity: vec2, private velocity: vec2,
public readonly originator: PlayerCharacterPhysical, public readonly originator: PlayerCharacterPhysical,
readonly container: PhysicalContainer, readonly container: PhysicalContainer,
) { ) {
super(id(), center, radius, colorIndex, strength); super(id(), center, radius, team, strength);
this.object = new CirclePhysical(center, radius, this, container, 0.9); this.object = new CirclePhysical(center, radius, this, container, 0.9);
this.moveOutsideOfObject(); this.moveOutsideOfObject();

View file

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

View file

@ -0,0 +1,49 @@
import { CharacterTeam, PlayerInformation, Random } from 'shared';
import { PhysicalContainer } from '../physics/containers/physical-container';
import { Player } from './player';
export class PlayerContainer {
private _players: Array<Player> = [];
constructor(private readonly objects: PhysicalContainer) {}
public createPlayer(playerInfo: PlayerInformation, socket: SocketIO.Socket): Player {
const player = new Player(
playerInfo,
this,
this.objects,
socket,
this.getTeamOfNextPlayer(),
);
this._players.push(player);
return player;
}
public get players(): Array<Player> {
return this._players;
}
public get count(): number {
return this.players.length;
}
public step(deltaTimeInSeconds: number) {
this.players.forEach((p) => p.step(deltaTimeInSeconds));
}
private getTeamOfNextPlayer(): CharacterTeam {
const declaCount = this._players.filter((p) => p.team === CharacterTeam.decla).length;
const redCount = this._players.filter((p) => p.team === CharacterTeam.red).length;
if ((declaCount === redCount && Random.getRandom() >= 0.5) || declaCount < redCount) {
return CharacterTeam.decla;
} else {
return CharacterTeam.red;
}
}
public deletePlayer(player: Player) {
this._players = this._players.filter((p) => p !== player);
}
}

View file

@ -1,22 +0,0 @@
import { CharacterTeam, Random } from 'shared';
let declaCount = 0;
let redCount = 0;
export const requestTeam = (): { team: CharacterTeam; colorIndex: number } => {
if ((declaCount === redCount && Random.getRandom() > 0.5) || declaCount < redCount) {
declaCount++;
return { team: CharacterTeam.decla, colorIndex: 0 };
} else {
redCount++;
return { team: CharacterTeam.red, colorIndex: 1 };
}
};
export const freeTeam = (team: CharacterTeam) => {
if (team === CharacterTeam.decla) {
declaCount--;
} else {
redCount--;
}
};

View file

@ -29,8 +29,8 @@ 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 { PlayerCharacterPhysical } from '../objects/player-character-physical';
import { freeTeam, requestTeam } from './player-team-service';
import { PlanetPhysical } from '../objects/planet-physical'; import { PlanetPhysical } from '../objects/planet-physical';
import { PlayerContainer } from './player-container';
export class Player extends CommandReceiver { export class Player extends CommandReceiver {
private character?: PlayerCharacterPhysical | null; private character?: PlayerCharacterPhysical | null;
@ -66,52 +66,15 @@ export class Player extends CommandReceiver {
}, },
}; };
private findEmptyPositionForPlayer(): vec2 {
let possibleCenter = this.players.find(
(p) => p.character?.isAlive && p.team === this.team,
)?.center;
if (!possibleCenter) {
possibleCenter = vec2.create();
}
let rotation = 0;
let radius = 0;
for (;;) {
const playerPosition = vec2.fromValues(
radius * Math.cos(rotation) + possibleCenter.x,
radius * Math.sin(rotation) + possibleCenter.y,
);
const playerBoundingCircle = new Circle(
playerPosition,
PlayerCharacterPhysical.boundRadius,
);
const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle);
const possibleIntersectors = this.objects.findIntersecting(playerBoundingBox);
if (!isCircleIntersecting(playerBoundingCircle, possibleIntersectors)) {
return playerPosition;
}
rotation += Math.PI / 8;
radius += 30;
}
}
public readonly team: CharacterTeam;
private colorIndex: number;
constructor( constructor(
private readonly playerInfo: PlayerInformation, private readonly playerInfo: PlayerInformation,
private readonly players: Array<Player>, private readonly playerContainer: PlayerContainer,
private readonly objects: PhysicalContainer, private readonly objectContainer: PhysicalContainer,
private readonly socket: SocketIO.Socket, private readonly socket: SocketIO.Socket,
public readonly team: CharacterTeam,
) { ) {
super(); super();
const { team, colorIndex } = requestTeam();
this.team = team; this.team = team;
this.colorIndex = colorIndex;
this.createCharacter(); this.createCharacter();
@ -129,13 +92,12 @@ export class Player extends CommandReceiver {
this.playerInfo.name.slice(0, 20), this.playerInfo.name.slice(0, 20),
this.sumKills, this.sumKills,
this.sumDeaths, this.sumDeaths,
this.colorIndex,
this.team, this.team,
this.objects, this.objectContainer,
this.findEmptyPositionForPlayer(), this.findEmptyPositionForPlayer(),
); );
this.objects.addObject(this.character); this.objectContainer.addObject(this.character);
this.objectsPreviouslyInViewArea.push(this.character); this.objectsPreviouslyInViewArea.push(this.character);
this.socket.emit( this.socket.emit(
@ -146,7 +108,7 @@ export class Player extends CommandReceiver {
private center: vec2 = vec2.create(); private center: vec2 = vec2.create();
private timeUntilRespawn = 0; private timeUntilRespawn = 0;
public step(deltaTime: number) { public step(deltaTimeInSeconds: number) {
if (this.character) { if (this.character) {
this.center = this.character?.center; this.center = this.character?.center;
@ -161,7 +123,7 @@ export class Player extends CommandReceiver {
this.character = null; this.character = null;
this.timeUntilRespawn = settings.playerDiedTimeout; this.timeUntilRespawn = settings.playerDiedTimeout;
} }
} else if ((this.timeUntilRespawn -= deltaTime) < 0) { } else if ((this.timeUntilRespawn -= deltaTimeInSeconds) < 0) {
this.createCharacter(); this.createCharacter();
} }
@ -171,7 +133,7 @@ export class Player extends CommandReceiver {
bb.size = viewArea.size; bb.size = viewArea.size;
const objectsInViewArea = Array.from( const objectsInViewArea = Array.from(
new Set(this.objects.findIntersecting(bb).map((o) => o.gameObject)), new Set(this.objectContainer.findIntersecting(bb).map((o) => o.gameObject)),
); );
const newlyIntersecting = objectsInViewArea.filter( const newlyIntersecting = objectsInViewArea.filter(
@ -210,6 +172,41 @@ export class Player extends CommandReceiver {
); );
} }
private findEmptyPositionForPlayer(): vec2 {
let possibleCenter = this.playerContainer.players.find(
(p) => p.character?.isAlive && p.team === this.team,
)?.center;
if (!possibleCenter) {
possibleCenter = vec2.create();
}
let rotation = 0;
let radius = 0;
for (;;) {
const playerPosition = vec2.fromValues(
radius * Math.cos(rotation) + possibleCenter.x,
radius * Math.sin(rotation) + possibleCenter.y,
);
const playerBoundingCircle = new Circle(
playerPosition,
PlayerCharacterPhysical.boundRadius,
);
const playerBoundingBox = getBoundingBoxOfCircle(playerBoundingCircle);
const possibleIntersectors = this.objectContainer.findIntersecting(
playerBoundingBox,
);
if (!isCircleIntersecting(playerBoundingCircle, possibleIntersectors)) {
return playerPosition;
}
rotation += Math.PI / 8;
radius += 30;
}
}
private getOtherPlayers(): Array<OtherPlayerDirection> { private getOtherPlayers(): Array<OtherPlayerDirection> {
if (!this.character) { if (!this.character) {
return []; return [];
@ -220,12 +217,12 @@ export class Player extends CommandReceiver {
bb.topLeft = viewArea.topLeft; bb.topLeft = viewArea.topLeft;
bb.size = viewArea.size; bb.size = viewArea.size;
const playersInViewArea = this.objects 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 PlayerCharacterPhysical);
const otherPlayers = this.players.filter( const otherPlayers = this.playerContainer.players.filter(
(p) => playersInViewArea.indexOf(p.character!) < 0, (p) => playersInViewArea.indexOf(p.character!) < 0,
); );
@ -247,10 +244,7 @@ export class Player extends CommandReceiver {
public destroy() { public destroy() {
this.isActive = false; this.isActive = false;
freeTeam(this.team);
if (this.character) { this.character?.destroy();
this.character.destroy();
}
} }
} }

View file

@ -1,6 +1,13 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { Renderer } from 'sdf-2d'; import { Renderer } from 'sdf-2d';
import { CharacterBase, CharacterTeam, Circle, Id, UpdateMessage } from 'shared'; import {
CharacterBase,
CharacterTeam,
Circle,
Id,
settings,
UpdateMessage,
} from 'shared';
import { BlobShape } from '../shapes/blob-shape'; import { BlobShape } from '../shapes/blob-shape';
import { ViewObject } from './view-object'; import { ViewObject } from './view-object';
@ -10,15 +17,14 @@ export class CharacterView extends CharacterBase implements ViewObject {
constructor( constructor(
id: Id, id: Id,
colorIndex: number,
team: CharacterTeam, team: CharacterTeam,
health: number, health: number,
head?: Circle, head?: Circle,
leftFoot?: Circle, leftFoot?: Circle,
rightFoot?: Circle, rightFoot?: Circle,
) { ) {
super(id, colorIndex, team, health, head, leftFoot, rightFoot); super(id, team, health, head, leftFoot, rightFoot);
this.shape = new BlobShape(colorIndex); this.shape = new BlobShape(settings.colorIndices[team]);
} }
public get position(): vec2 { public get position(): vec2 {

View file

@ -19,26 +19,14 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje
name: string, name: string,
killCount: number, killCount: number,
deathCount: number, deathCount: number,
colorIndex: number,
team: CharacterTeam, team: CharacterTeam,
health: number, health: number,
head?: Circle, head?: Circle,
leftFoot?: Circle, leftFoot?: Circle,
rightFoot?: Circle, rightFoot?: Circle,
) { ) {
super( super(id, name, killCount, deathCount, team, health, head, leftFoot, rightFoot);
id, this.shape = new BlobShape(settings.colorIndices[team]);
name,
killCount,
deathCount,
colorIndex,
team,
health,
head,
leftFoot,
rightFoot,
);
this.shape = new BlobShape(colorIndex);
this.previousHealth = this.health; this.previousHealth = this.health;
this.nameElement.className = 'player-tag ' + this.team; this.nameElement.className = 'player-tag ' + this.team;

View file

@ -1,6 +1,6 @@
import { vec2 } from 'gl-matrix'; import { vec2 } from 'gl-matrix';
import { CircleLight, ColorfulCircle, Renderer } from 'sdf-2d'; import { CircleLight, ColorfulCircle, Renderer } from 'sdf-2d';
import { Id, ProjectileBase, settings, UpdateMessage } from 'shared'; import { CharacterTeam, Id, ProjectileBase, settings, UpdateMessage } from 'shared';
import { ViewObject } from './view-object'; import { ViewObject } from './view-object';
export class ProjectileView extends ProjectileBase implements ViewObject { export class ProjectileView extends ProjectileBase implements ViewObject {
@ -11,12 +11,16 @@ export class ProjectileView extends ProjectileBase implements ViewObject {
id: Id, id: Id,
center: vec2, center: vec2,
radius: number, radius: number,
colorIndex: number, team: CharacterTeam,
strength: number, strength: number,
) { ) {
super(id, center, radius, colorIndex, strength); super(id, center, radius, team, strength);
this.circle = new ColorfulCircle(center, radius / 2, colorIndex); this.circle = new ColorfulCircle(center, radius / 2, settings.colorIndices[team]);
this.light = new CircleLight(center, settings.palette[colorIndex], 0); this.light = new CircleLight(
center,
settings.paletteDim[settings.colorIndices[team]],
0,
);
} }
public step(deltaTimeInMilliseconds: number): void { public step(deltaTimeInMilliseconds: number): void {

View file

@ -8,7 +8,6 @@ import { CharacterTeam } from './character-team';
export class CharacterBase extends GameObject { export class CharacterBase extends GameObject {
constructor( constructor(
id: Id, id: Id,
public colorIndex: number,
public team: CharacterTeam, public team: CharacterTeam,
public health: number, public health: number,
public head?: Circle, public head?: Circle,
@ -19,7 +18,7 @@ export class CharacterBase extends GameObject {
} }
public toArray(): Array<any> { public toArray(): Array<any> {
const { id, colorIndex, team, health, head, leftFoot, rightFoot } = this; const { id, team, health, head, leftFoot, rightFoot } = this;
return [id, colorIndex, team, health, head, leftFoot, rightFoot]; return [id, team, health, head, leftFoot, rightFoot];
} }
} }

View file

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

View file

@ -11,14 +11,13 @@ export class PlayerCharacterBase extends CharacterBase {
public name: string, public name: string,
public killCount: number, public killCount: number,
public deathCount: number, public deathCount: number,
colorIndex: number,
team: CharacterTeam, team: CharacterTeam,
health: number, health: number,
head?: Circle, head?: Circle,
leftFoot?: Circle, leftFoot?: Circle,
rightFoot?: Circle, rightFoot?: Circle,
) { ) {
super(id, colorIndex, team, health, head, leftFoot, rightFoot); super(id, team, health, head, leftFoot, rightFoot);
} }
public toArray(): Array<any> { public toArray(): Array<any> {
@ -27,7 +26,6 @@ export class PlayerCharacterBase extends CharacterBase {
this.name, this.name,
this.killCount, this.killCount,
this.deathCount, this.deathCount,
this.colorIndex,
this.team, this.team,
this.health, this.health,
this.head, this.head,

View file

@ -2,6 +2,7 @@ import { vec2 } from 'gl-matrix';
import { Id } from '../../transport/identity'; import { Id } from '../../transport/identity';
import { serializable } from '../../transport/serialization/serializable'; import { serializable } from '../../transport/serialization/serializable';
import { GameObject } from '../game-object'; import { GameObject } from '../game-object';
import { CharacterTeam } from './character-team';
@serializable @serializable
export class ProjectileBase extends GameObject { export class ProjectileBase extends GameObject {
@ -9,13 +10,13 @@ export class ProjectileBase extends GameObject {
id: Id, id: Id,
public center: vec2, public center: vec2,
public radius: number, public radius: number,
public colorIndex: number, public team: CharacterTeam,
public strength: number, public strength: number,
) { ) {
super(id); super(id);
} }
public toArray(): Array<any> { public toArray(): Array<any> {
return [this.id, this.center, this.radius, this.colorIndex, this.strength]; return [this.id, this.center, this.radius, this.team, this.strength];
} }
} }

View file

@ -1,8 +1,13 @@
import { rgb255 } from './helper/rgb255'; import { rgb255 } from './helper/rgb255';
import { CharacterTeam } from './objects/types/character-team';
const q = 2.5; const q = 2.5;
const qDim = 1.5;
const declaColor = rgb255(64 * q, 105 * q, 165 * q); const declaColor = rgb255(64 * q, 105 * q, 165 * q);
const neutralColor = rgb255(82 * q, 165 * q, 64 * q);
const redColor = rgb255(209 * q, 86 * q, 82 * q); const redColor = rgb255(209 * q, 86 * q, 82 * q);
const declaColorDim = rgb255(64 * qDim, 105 * qDim, 165 * qDim);
const redColorDim = rgb255(209 * qDim, 8 * qDim, 82 * qDim);
const declaPlanetColor = declaColor; const declaPlanetColor = declaColor;
const redPlanetColor = redColor; const redPlanetColor = redColor;
@ -32,14 +37,18 @@ export const settings = {
projectileFadeSpeed: 20, projectileFadeSpeed: 20,
projectileCreationInterval: 0.1, projectileCreationInterval: 0.1,
playerColorIndexOffset: 3, playerColorIndexOffset: 3,
backgroundGradient: [rgb255(90, 38, 43), rgb255(43, 39, 73)], backgroundGradient: [rgb255(90, 38, 43), rgb255(0, 0, 0), rgb255(43, 39, 73)],
declaColor, declaColor,
declaPlanetColor, declaPlanetColor,
redColor, redColor,
redPlanetColor, redPlanetColor,
declaIndex: 0, colorIndices: {
redIndex: 1, [CharacterTeam.decla]: 0,
palette: [declaColor, redColor], [CharacterTeam.neutral]: 1,
[CharacterTeam.red]: 2,
},
palette: [declaColor, neutralColor, redColor],
paletteDim: [declaColorDim, neutralColor, redColorDim],
targetPhysicsDeltaTimeInMilliseconds: 20, targetPhysicsDeltaTimeInMilliseconds: 20,
minPhysicsSleepTime: 4, minPhysicsSleepTime: 4,
velocityAttenuation: 0.25, velocityAttenuation: 0.25,