Improve movement

This commit is contained in:
schmelczerandras 2020-10-27 10:32:37 +01:00
parent 7e188c2b9a
commit c9eae3adeb
16 changed files with 227 additions and 279 deletions

View file

@ -10,6 +10,7 @@ import {
ReactsToCollision,
reactsToCollision,
} from '../physics/physicals/reacts-to-collision';
import { Physical } from '../physics/physicals/physical';
@serializesTo(Circle)
export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollision {
@ -18,6 +19,7 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio
public velocity = vec2.create();
private _boundingBox: BoundingBox;
public lastNormal = vec2.fromValues(1, 0);
constructor(
private _center: vec2,
@ -95,38 +97,27 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio
public step(_: number) {}
public step2(deltaTimeInSeconds: number): GameObject | undefined {
vec2.scale(
this.velocity,
this.velocity,
Math.pow(settings.velocityAttenuation, deltaTimeInSeconds),
);
const delta = vec2.scale(vec2.create(), this.velocity, deltaTimeInSeconds);
public step2(
deltaTimeInSeconds: number,
additionalCollider?: Physical,
): { hitObject: GameObject | undefined; velocity: vec2 } {
let delta = vec2.scale(vec2.create(), this.velocity, deltaTimeInSeconds);
this.radius += vec2.length(delta);
const intersecting = this.container.findIntersecting(this.boundingBox);
const intersecting = this.container
.findIntersecting(this.boundingBox)
.filter((b) => b.gameObject !== this.gameObject && b.canCollide);
this.radius -= vec2.length(delta);
const stepCount = Math.ceil(vec2.length(delta) / settings.physicsMaxStep);
vec2.scale(delta, delta, 1 / stepCount);
if (additionalCollider) {
intersecting.push(additionalCollider);
}
let lastHit: GameObject | undefined;
for (let i = 0; i < stepCount; i++) {
const distance = vec2.scale(
vec2.create(),
this.velocity,
deltaTimeInSeconds / stepCount,
);
const { normal, hitSurface, hitObject } = moveCircle(
this,
vec2.clone(distance),
intersecting,
);
let { normal, hitSurface, hitObject } = moveCircle(this, delta, intersecting);
if (hitSurface) {
vec2.copy(this.lastNormal, normal!);
vec2.subtract(
this.velocity,
this.velocity,
@ -137,37 +128,16 @@ export class CirclePhysical implements Circle, DynamicPhysical, ReactsToCollisio
),
);
lastHit = hitObject;
if (vec2.length(this.velocity) > 50) {
delta = vec2.scale(vec2.create(), this.velocity, deltaTimeInSeconds);
moveCircle(this, delta, intersecting);
}
}
return lastHit;
}
const lastVelocity = vec2.clone(this.velocity);
vec2.zero(this.velocity);
public tryMove(delta: vec2): GameObject | undefined {
this.radius += vec2.length(delta);
const intersecting = this.container.findIntersecting(this.boundingBox);
this.radius -= vec2.length(delta);
const stepCount = Math.ceil(vec2.length(delta) / settings.physicsMaxStep);
vec2.scale(delta, delta, 1 / stepCount);
let lastHit: GameObject | undefined;
for (let i = 0; i < stepCount; i++) {
const { tangent, hitSurface, hitObject } = moveCircle(
this,
vec2.clone(delta),
intersecting,
);
if (hitSurface) {
delta = vec2.scale(delta, tangent!, vec2.length(delta));
lastHit = hitObject;
}
}
return lastHit;
return { hitObject, velocity: lastVelocity };
}
public toArray(): Array<any> {

View file

@ -154,43 +154,15 @@ export class PlanetPhysical
}
public getForce(position: vec2): vec2 {
const height = this.distance(position);
let closestIndex = 0;
this.vertices.forEach((v, i) => {
if (
vec2.distance(position, v) < vec2.distance(position, this.vertices[closestIndex])
) {
closestIndex = i;
}
});
const afterClosest = this.vertices[(closestIndex + 1) % this.vertices.length];
const closest = this.vertices[closestIndex];
const beforeClosest = this.vertices[
(closestIndex - 1 + this.vertices.length) % this.vertices.length
];
const diff = vec2.subtract(vec2.create(), position, closest);
const edge1 = vec2.subtract(vec2.create(), afterClosest, closest);
const edge2 = vec2.subtract(vec2.create(), closest, beforeClosest);
const normalizedDiff = vec2.normalize(vec2.create(), diff);
const currentEdge =
vec2.dot(vec2.normalize(vec2.create(), rotate90Deg(edge1)), normalizedDiff) >
vec2.dot(vec2.normalize(vec2.create(), rotate90Deg(edge2)), normalizedDiff)
? edge1
: edge2;
vec2.normalize(currentEdge, currentEdge);
const normal = rotateMinus90Deg(currentEdge);
const diff = vec2.subtract(vec2.create(), this.center, position);
const dist = Math.max(0, vec2.length(diff) - 600);
vec2.normalize(diff, diff);
const scale = clamp(
settings.maxGravityQ * ((settings.maxGravityDistance / height) ** 3 - 1),
settings.maxGravityQ * ((settings.maxGravityDistance / dist) ** 1.5 - 1),
0,
settings.maxGravityStrength,
);
return vec2.scale(normal, normal, scale);
return vec2.scale(diff, diff, scale);
}
public get gameObject(): this {

View file

@ -70,10 +70,13 @@ export class PlayerCharacterPhysical
public static readonly boundRadius =
(PlayerCharacterPhysical.headRadius + PlayerCharacterPhysical.feetRadius * 2) * 2;
private timeSinceDying = 0;
private isDestroyed = false;
private timeSinceBorn = 0;
private hasJustBorn = true;
private direction = 0;
private currentPlanet?: PlanetPhysical;
private lastMovementWasRelative = false;
private secondsSinceOnSurface = 1000;
public head: CirclePhysical;
@ -81,15 +84,8 @@ export class PlayerCharacterPhysical
public rightFoot: CirclePhysical;
public bound: CirclePhysical;
public get isAlive(): boolean {
return !this.isDestroyed;
}
private movementActions: Array<MoveActionCommand> = [];
private lastMovementAction: MoveActionCommand = new MoveActionCommand(
vec2.create(),
false,
);
private lastMovementAction: MoveActionCommand = new MoveActionCommand(vec2.create());
constructor(
name: string,
@ -131,6 +127,10 @@ export class PlayerCharacterPhysical
);
}
public get isAlive(): boolean {
return !this.isDestroyed;
}
public handleMovementAction(c: MoveActionCommand) {
this.movementActions.push(c);
}
@ -150,7 +150,7 @@ export class PlayerCharacterPhysical
this.health -= other.strength;
this.remoteCall('setHealth', this.health);
if (this.health <= 0) {
this.destroy();
this.kill();
other.originator.addKill();
}
}
@ -217,9 +217,6 @@ export class PlayerCharacterPhysical
vec2.scale(direction, direction, 1 / this.movementActions.length);
this.lastMovementWasRelative =
this.movementActions.find((a) => a.isCharacterRelative) !== undefined;
this.lastMovementAction = last(this.movementActions)!;
this.movementActions = [];
}
@ -227,8 +224,35 @@ export class PlayerCharacterPhysical
return vec2.normalize(direction, direction);
}
private animateScaling(q: number) {
this.remoteCall(
'updateCircles',
new Circle(this.head.center, PlayerCharacterPhysical.headRadius * q),
new Circle(this.leftFoot.center, PlayerCharacterPhysical.feetRadius * q),
new Circle(this.rightFoot.center, PlayerCharacterPhysical.feetRadius * q),
);
}
public step(deltaTime: number) {
if ((this.secondsSinceOnSurface += deltaTime) > 1) {
if (this.isDestroyed) {
if ((this.timeSinceDying += deltaTime) > settings.spawnDespawnTime) {
this.destroy();
} else {
this.animateScaling(1 - this.timeSinceDying / settings.spawnDespawnTime);
}
return;
}
if (this.hasJustBorn) {
if ((this.timeSinceBorn += deltaTime) > settings.spawnDespawnTime) {
this.hasJustBorn = false;
} else {
this.animateScaling(this.timeSinceBorn / settings.spawnDespawnTime);
}
return;
}
if ((this.secondsSinceOnSurface += deltaTime) > 0.5) {
this.currentPlanet = undefined;
}
@ -247,12 +271,11 @@ export class PlayerCharacterPhysical
),
),
);
const feetCenter = vec2.add(
vec2.create(),
this.leftFoot.center,
this.rightFoot.center,
);
vec2.scale(feetCenter, feetCenter, 0.5);
const direction = this.averageAndResetMovementActions();
const movementForce = vec2.scale(direction, direction, settings.maxAcceleration);
if (!this.currentPlanet) {
const leftFootGravity = forceAtPosition(
this.leftFoot.center,
intersectingWithForcefield,
@ -262,19 +285,10 @@ export class PlayerCharacterPhysical
intersectingWithForcefield,
);
const direction = this.averageAndResetMovementActions();
const movementForce = vec2.scale(direction, direction, settings.maxAcceleration);
if (!this.currentPlanet) {
this.applyForce(this.leftFoot, leftFootGravity, deltaTime);
this.applyForce(this.rightFoot, rightFootGravity, deltaTime);
const sumForce = vec2.subtract(
vec2.create(),
// the next line is intentional
vec2.add(vec2.create(), leftFootGravity, rightFootGravity),
movementForce,
);
const sumForce = vec2.subtract(vec2.create(), leftFootGravity, movementForce);
this.setDirection(
vec2.length(sumForce) === 0 ? vec2.fromValues(0, -1) : sumForce,
@ -284,32 +298,41 @@ export class PlayerCharacterPhysical
const leftFootGravity = this.currentPlanet!.getForce(this.leftFoot.center);
const rightFootGravity = this.currentPlanet!.getForce(this.rightFoot.center);
if (this.lastMovementWasRelative) {
vec2.rotate(movementForce, movementForce, vec2.create(), this.direction);
vec2.add(leftFootGravity, leftFootGravity, rightFootGravity);
const gravity = vec2.scale(leftFootGravity, leftFootGravity, 0.5);
if (vec2.dot(movementForce, gravity) < -vec2.length(movementForce) * 0.8) {
vec2.scale(gravity, gravity, 0.35);
}
if (vec2.dot(movementForce, leftFootGravity) < -vec2.length(movementForce) * 0.8) {
vec2.scale(leftFootGravity, leftFootGravity, 0.35);
vec2.scale(rightFootGravity, rightFootGravity, 0.35);
}
this.applyForce(this.leftFoot, leftFootGravity, deltaTime);
this.applyForce(this.rightFoot, rightFootGravity, deltaTime);
const scaledLeftFootGravity = vec2.scale(
vec2.create(),
this.leftFoot.lastNormal,
vec2.dot(this.leftFoot.lastNormal, gravity),
);
this.applyForce(this.leftFoot, scaledLeftFootGravity, deltaTime);
const headGravity = this.currentPlanet!.getForce(this.head.center);
const scaledRightFootGravity = vec2.scale(
vec2.create(),
this.rightFoot.lastNormal,
vec2.dot(this.rightFoot.lastNormal, gravity),
);
if (vec2.length(headGravity) < vec2.length(leftFootGravity) / 2) {
this.applyForce(this.rightFoot, scaledRightFootGravity, deltaTime);
if (vec2.length(gravity) <= 100) {
this.currentPlanet = undefined;
}
this.setDirection(headGravity, deltaTime);
this.setDirection(gravity, deltaTime);
}
this.applyForce(this.leftFoot, movementForce, deltaTime);
this.applyForce(this.rightFoot, movementForce, deltaTime);
this.keepPosture(deltaTime);
this.stepBodyPart(this.leftFoot, deltaTime);
this.stepBodyPart(this.rightFoot, deltaTime);
this.keepPosture(deltaTime);
this.stepBodyPart(this.head, deltaTime);
this.remoteCall('updateCircles', this.head, this.leftFoot, this.rightFoot);
}
@ -323,45 +346,29 @@ export class PlayerCharacterPhysical
}
private keepPosture(deltaTime: number) {
const center = this.center;
let center = this.center;
this.springMove(
this.leftFoot,
center,
PlayerCharacterPhysical.leftFootOffset,
deltaTime,
15000,
);
this.springMove(
this.rightFoot,
center,
PlayerCharacterPhysical.rightFootOffset,
deltaTime,
15000,
);
/*
const feetDelta = vec2.subtract(
vec2.create(),
this.leftFoot.center,
this.rightFoot.center,
);
const desiredDistance = vec2.dist(
PlayerCharacterPhysical.desiredLeftFootOffset,
PlayerCharacterPhysical.desiredRightFootOffset,
);
const actualDistance = vec2.length(feetDelta);
const delta = vec2.normalize(feetDelta, feetDelta);
vec2.scale(delta, delta, Math.min(actualDistance / 2, deltaTime * 200));
let hitObject = this.rightFoot.tryMove(delta);
if (hitObject instanceof PlanetPhysical) {
this.secondsSinceOnSurface = 0;
this.currentPlanet = hitObject;
}
vec2.scale(delta, delta, -1);
hitObject = this.leftFoot.tryMove(delta);
if (hitObject instanceof PlanetPhysical) {
this.secondsSinceOnSurface = 0;
this.currentPlanet = hitObject;
}*/
this.springMove(this.head, center, PlayerCharacterPhysical.headOffset, deltaTime);
this.springMove(
this.head,
center,
PlayerCharacterPhysical.headOffset,
deltaTime,
25000,
);
}
private springMove(
@ -369,28 +376,25 @@ export class PlayerCharacterPhysical
center: vec2,
offset: vec2,
deltaTime: number,
strength: number,
) {
const desiredPosition = vec2.add(vec2.create(), center, offset);
vec2.rotate(desiredPosition, desiredPosition, center, this.direction);
const positionDelta = vec2.subtract(desiredPosition, desiredPosition, object.center);
const positionDelta = vec2.subtract(vec2.create(), desiredPosition, object.center);
const positionDeltaDirection = vec2.normalize(vec2.create(), positionDelta);
const positionDeltaLength = vec2.length(positionDelta);
vec2.scale(
positionDelta,
positionDeltaDirection,
Math.min(positionDeltaLength, (positionDeltaLength / 50) * deltaTime * 800),
positionDeltaLength * deltaTime * strength,
);
const hitObject = object.tryMove(positionDelta);
if (hitObject instanceof PlanetPhysical) {
this.secondsSinceOnSurface = 0;
this.currentPlanet = hitObject;
}
object.applyForce(positionDelta, deltaTime);
}
private stepBodyPart(part: CirclePhysical, deltaTime: number) {
const hitObject = part.step2(deltaTime);
const { hitObject } = part.step2(deltaTime);
if (hitObject instanceof PlanetPhysical) {
this.secondsSinceOnSurface = 0;
this.currentPlanet = hitObject;
@ -411,13 +415,14 @@ export class PlayerCharacterPhysical
);
}
public destroy() {
if (!this.isDestroyed) {
public kill() {
this.isDestroyed = true;
}
private destroy() {
this.container.removeObject(this);
this.container.removeObject(this.head);
this.container.removeObject(this.leftFoot);
this.container.removeObject(this.rightFoot);
}
}
}

View file

@ -114,10 +114,19 @@ export class ProjectilePhysical
}
});
vec2.add(this.velocity, this.velocity, vec2.scale(vec2.create(), gravity, deltaTime));
vec2.add(
this.velocity,
this.velocity,
vec2.scale(
vec2.create(),
gravity,
deltaTime * settings.gravityScalingForProjectiles,
),
);
this.object.velocity = this.velocity;
this.object.step2(deltaTime);
vec2.copy(this.object.velocity, this.velocity);
const { velocity } = this.object.step2(deltaTime);
vec2.copy(this.velocity, velocity);
this.remoteCall('setCenter', this.center);
}

View file

@ -17,26 +17,24 @@ export const moveCircle = (
tangent?: vec2;
hitObject?: GameObject;
} => {
const nextCircle = new Circle(vec2.clone(circle.center), circle.radius);
vec2.add(nextCircle.center, nextCircle.center, delta);
possibleIntersectors = possibleIntersectors.filter(
(b) => b.gameObject !== circle.gameObject && b.canCollide,
const direction = vec2.normalize(vec2.create(), delta);
const deltaLength = vec2.length(delta);
let travelled = 0;
let rayEnd = vec2.create();
let prevMinDistance = 0;
while (travelled < deltaLength) {
travelled += prevMinDistance;
vec2.add(
rayEnd,
circle.center,
vec2.scale(vec2.create(), direction, Math.min(travelled, deltaLength)),
);
const sdfAtCenter = evaluateSdf(nextCircle.center, possibleIntersectors);
if (sdfAtCenter > nextCircle.radius) {
circle.center = vec2.add(circle.center, circle.center, delta);
return {
realDelta: delta,
hitSurface: false,
};
}
const minDistance = evaluateSdf(rayEnd, possibleIntersectors);
if (minDistance < circle.radius) {
const intersecting = possibleIntersectors.find(
(i) => i.distance(nextCircle.center) <= circle.radius,
(i) => i.distance(rayEnd) <= circle.radius,
)!;
if (ignoreCollision) {
@ -51,14 +49,28 @@ export const moveCircle = (
}
}
vec2.add(
rayEnd,
circle.center,
vec2.scale(vec2.create(), direction, travelled - prevMinDistance),
);
vec2.copy(circle.center, rayEnd);
const dx =
evaluateSdf(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0.01, 0)), [
evaluateSdf(vec2.add(vec2.create(), rayEnd, vec2.fromValues(0.01, 0)), [
intersecting,
]) - sdfAtCenter;
]) -
evaluateSdf(vec2.add(vec2.create(), rayEnd, vec2.fromValues(-0.01, 0)), [
intersecting,
]);
const dy =
evaluateSdf(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0, 0.01)), [
evaluateSdf(vec2.add(vec2.create(), rayEnd, vec2.fromValues(0, 0.01)), [
intersecting,
]) - sdfAtCenter;
]) -
evaluateSdf(vec2.add(vec2.create(), rayEnd, vec2.fromValues(0, -0.01)), [
intersecting,
]);
const normal = vec2.fromValues(dx, dy);
vec2.normalize(normal, normal);
const rotatedNormal = rotate90Deg(normal);
@ -72,4 +84,15 @@ export const moveCircle = (
? vec2.scale(rotatedNormal, rotatedNormal, -1)
: rotatedNormal,
};
}
prevMinDistance = minDistance;
}
vec2.add(circle.center, circle.center, delta);
return {
realDelta: delta,
hitSurface: false,
};
};

View file

@ -196,7 +196,7 @@ export class NPC extends PlayerBase {
this.timeSinceLastFindShootTarget = 0;
}
this.character?.handleMovementAction(new MoveActionCommand(this.direction, false));
this.character?.handleMovementAction(new MoveActionCommand(this.direction));
}
protected createCharacter() {

View file

@ -69,6 +69,6 @@ export abstract class PlayerBase extends CommandReceiver {
}
public destroy() {
this.character?.destroy();
this.character?.kill();
}
}

View file

@ -9,7 +9,6 @@
"downlevelIteration": true,
"moduleResolution": "node",
"module": "commonjs",
"composite": true,
"lib": ["dom", "es2017"],
"typeRoots": ["./types", "./node_modules/@types"]
},

View file

@ -63,15 +63,6 @@
<div id="settings-container">
<section id="settings">
<label for="enable-relative-movement">
<input id="enable-relative-movement" type="checkbox" />
<img
title="Make movement be relative to the gravitational field"
alt="a dashed circle"
src="../static/circle.svg"
/>
</label>
<label for="enable-vibration">
<input id="enable-vibration" type="checkbox" />
<img

View file

@ -48,9 +48,6 @@ const toggleSettingsButton = document.querySelector(
const minimize = document.querySelector('#minimize') as HTMLElement;
const maximize = document.querySelector('#maximize') as HTMLElement;
const logoutButton = document.querySelector('#logout') as HTMLElement;
const enableRelativeMovement = document.querySelector(
'#enable-relative-movement',
) as HTMLInputElement;
const enableSounds = document.querySelector('#enable-sounds') as HTMLInputElement;
const enableMusic = document.querySelector('#enable-music') as HTMLInputElement;
const enableVibration = document.querySelector('#enable-vibration') as HTMLInputElement;
@ -123,7 +120,6 @@ const main = async () => {
serverContainer.addEventListener('scroll', applyServerContainerShadows);
OptionsHandler.initialize({
relativeMovementEnabled: enableRelativeMovement,
soundsEnabled: enableSounds,
vibrationEnabled: enableVibration,
musicEnabled: enableMusic,

View file

@ -35,9 +35,7 @@ export class KeyboardListener extends CommandGenerator {
if (vec2.squaredLength(movement) > 0) {
vec2.normalize(movement, movement);
}
this.sendCommandToSubcribers(
new MoveActionCommand(movement, OptionsHandler.options.relativeMovementEnabled),
);
this.sendCommandToSubcribers(new MoveActionCommand(movement));
}
private normalize(key: string): string {

View file

@ -75,18 +75,10 @@ export class TouchJoystickListener extends CommandGenerator {
vec2.set(movement, movement.x, -movement.y);
if (length > 10) {
this.sendCommandToSubcribers(
new MoveActionCommand(
vec2.normalize(movement, movement),
OptionsHandler.options.relativeMovementEnabled,
),
new MoveActionCommand(vec2.normalize(movement, movement)),
);
} else {
this.sendCommandToSubcribers(
new MoveActionCommand(
vec2.create(),
OptionsHandler.options.relativeMovementEnabled,
),
);
this.sendCommandToSubcribers(new MoveActionCommand(vec2.create()));
}
});
@ -104,12 +96,7 @@ export class TouchJoystickListener extends CommandGenerator {
} else if (event.touches.length === 0) {
this.isJoystickActive = false;
this.joystick.parentElement?.removeChild(this.joystick);
this.sendCommandToSubcribers(
new MoveActionCommand(
vec2.create(),
OptionsHandler.options.relativeMovementEnabled,
),
);
this.sendCommandToSubcribers(new MoveActionCommand(vec2.create()));
}
});
}

View file

@ -2,6 +2,7 @@ import { ServerInformation, serverInformationEndpoint, TransportEvents } from 's
import io from 'socket.io-client';
import { Configuration } from './config/configuration';
import parser from 'socket.io-msgpack-parser';
import { SoundHandler, Sounds } from './sound-handler';
export type PlayerDecision = {
playerName: string;
@ -26,6 +27,7 @@ export class JoinFormHandler {
});
form.onsubmit = (e) => {
SoundHandler.play(Sounds.click);
const result: PlayerDecision = (Array.from(
(new FormData(form) as any).entries(),
) as Array<[string, any]>).reduce((result, [name, value]) => {
@ -113,6 +115,7 @@ class ServerChooserOption {
this.inputElement.name = 'server';
this.inputElement.checked = isFirst;
this.labelElement.htmlFor = url;
this.labelElement.onclick = () => SoundHandler.play(Sounds.click);
this.divElement.appendChild(this.inputElement);
this.divElement.appendChild(this.labelElement);
this.labelElement.appendChild(this.serverNameElement);

View file

@ -3,7 +3,6 @@ import { SoundHandler, Sounds } from './sound-handler';
interface Options {
vibrationEnabled: boolean;
soundsEnabled: boolean;
relativeMovementEnabled: boolean;
musicEnabled: boolean;
}
@ -12,7 +11,6 @@ export abstract class OptionsHandler {
private static _options: Options = {
vibrationEnabled: true,
soundsEnabled: true,
relativeMovementEnabled: false,
musicEnabled: true,
};

View file

@ -4,14 +4,11 @@ import { Command } from '../command';
@serializable
export class MoveActionCommand extends Command {
public constructor(
public readonly direction: vec2,
public readonly isCharacterRelative: boolean,
) {
public constructor(public readonly direction: vec2) {
super();
}
public toArray(): Array<any> {
return [this.direction, this.isCharacterRelative];
return [this.direction];
}
}

View file

@ -12,10 +12,11 @@ const redPlanetColor = redColorDim;
export const settings = {
lightCutoffDistance: 600,
physicsMaxStep: 8,
maxVelocityX: 1000,
maxVelocityY: 1000,
radiusSteps: 500,
gravityScalingForProjectiles: 5,
spawnDespawnTime: 0.7,
worldRadius: 10000,
objectsOnCircleLength: 0.002,
planetEdgeCount: 7,
@ -23,19 +24,19 @@ export const settings = {
loseControlTimeInSeconds: 24,
planetPointGenerationInterval: 1.5,
planetPointGenerationValue: 1,
maxGravityDistance: 700,
maxGravityQ: 180,
maxGravityDistance: 800,
maxGravityQ: 10000,
planetControlThreshold: 0.2,
playerMaxHealth: 100,
maxGravityStrength: 10000,
maxAcceleration: 10000,
maxGravityStrength: 20000,
maxAcceleration: 60000,
playerMaxStrength: 80,
endGameDeltaScaling: 4,
playerDiedTimeout: 5,
playerStrengthRegenerationPerSeconds: 60,
playerStrengthRegenerationPerSeconds: 80,
projectileMaxStrength: 40,
projectileSpeed: 4000,
projectileMaxBounceCount: 1,
projectileMaxBounceCount: 2,
projectileTimeout: 3,
projectileFadeSpeed: 20,
projectileCreationInterval: 0.1,
@ -45,6 +46,7 @@ export const settings = {
declaPlanetColor,
npcNames: [
'Adam',
'Andrew',
'Clarence',
'Elliot',
'Elmer',
@ -66,7 +68,6 @@ export const settings = {
'Niles',
'Oliver',
'Blaise',
'Andrew',
'Opie',
'Ryan',
'Toby',
@ -112,6 +113,5 @@ export const settings = {
paletteDim: [declaColorDim, neutralColor, redColorDim],
targetPhysicsDeltaTimeInMilliseconds: 20,
minPhysicsSleepTime: 4,
velocityAttenuation: 0.25,
inViewAreaSize: 1920 * 1080 * 3,
};