diff --git a/src/constants.ts b/src/constants.ts
new file mode 100644
index 0000000..f4b651e
--- /dev/null
+++ b/src/constants.ts
@@ -0,0 +1,4 @@
+// @ts-ignore: injected by webpack
+export const isProduction: boolean = __IS_PRODUCTION__;
+// @ts-ignore: injected by webpack
+export const lastEdit = new Date(__CURRENT_DATE__);
diff --git a/src/game-loop/game-loop-settings.ts b/src/game-loop/game-loop-settings.ts
index 085c9d8..e71ebc8 100644
--- a/src/game-loop/game-loop-settings.ts
+++ b/src/game-loop/game-loop-settings.ts
@@ -4,8 +4,5 @@ export interface GameLoopSettings {
renderSpeed: number;
simulatedDelayMs: number;
- spawnRadius: number;
- spawnInterval: number;
-
startColorHue: number;
}
diff --git a/src/game-loop/game-loop.ts b/src/game-loop/game-loop.ts
index 4aab844..7a1d362 100644
--- a/src/game-loop/game-loop.ts
+++ b/src/game-loop/game-loop.ts
@@ -189,6 +189,9 @@ export default class GameLoop {
pipeline.setParameters({
time,
isNextGenerationOdd: this.gameRules.nextGenerationId % 2,
+ nextGenerationSensorOffsetDistance: this.gameRules.getSensorOffset(),
+ nextGenerationSpeed: this.gameRules.getNextGenerationMoveSpeed(),
+ infectionProbability: this.gameRules.getInfectionProbability(),
deltaTime,
canvasSize: this.canvasSize,
brushColor: GamePresentation.getGenerationColor(
diff --git a/src/game-loop/game-rules.ts b/src/game-loop/game-rules.ts
index d743313..6097c32 100644
--- a/src/game-loop/game-rules.ts
+++ b/src/game-loop/game-rules.ts
@@ -1,5 +1,7 @@
import { GenerationCounts } from '../pipelines/agents/agent-generation/generation-counts';
import { settings } from '../settings';
+import { clamp, clamp01 } from '../utils/clamp';
+import { mix } from '../utils/mix';
import { Random } from '../utils/random';
import { vec2 } from 'gl-matrix';
@@ -11,7 +13,15 @@ export interface SpawnAction {
}
export class GameRules {
+ private static readonly DEAFULT_SPAWN_INTERVAL = 8;
+ private static readonly DEAFULT_SPAWN_TIME_LENGTH = 2;
+ private static readonly DEFAULT_SPAWN_RADIUS = 20;
+
private lastSpawnTimeInSeconds = 0;
+ private currentSpawnInterval = 0;
+ private currentSpawnRadius = 0;
+ private lastGenerationChangeTimeInSeconds = 0;
+
public nextGenerationId = 1;
public generationCounts: {
currentGenerationCount: number;
@@ -23,10 +33,37 @@ export class GameRules {
public constructor(startingTimeInSeconds: number) {
this.lastSpawnTimeInSeconds = startingTimeInSeconds;
+ this.lastGenerationChangeTimeInSeconds = startingTimeInSeconds;
}
+ private lastSpawnAction: SpawnAction | undefined;
+
public getSpawnAction(timeInSeconds: number, canvasSize: vec2): SpawnAction {
- if (timeInSeconds - this.lastSpawnTimeInSeconds < settings.spawnInterval) {
+ if (
+ this.lastSpawnAction &&
+ timeInSeconds - this.lastSpawnTimeInSeconds < GameRules.DEAFULT_SPAWN_TIME_LENGTH
+ ) {
+ return this.lastSpawnAction;
+ }
+
+ this.currentSpawnInterval = mix(
+ GameRules.DEAFULT_SPAWN_INTERVAL,
+ GameRules.DEAFULT_SPAWN_INTERVAL / 5,
+ clamp01((timeInSeconds - this.lastGenerationChangeTimeInSeconds) / 120)
+ );
+
+ this.currentSpawnRadius = mix(
+ GameRules.DEFAULT_SPAWN_RADIUS,
+ GameRules.DEFAULT_SPAWN_RADIUS * 3,
+ clamp01((timeInSeconds - this.lastGenerationChangeTimeInSeconds) / 120)
+ );
+
+ const q = this.generationCounts.nextGenerationCount / settings.agentCount;
+
+ if (
+ timeInSeconds - this.lastSpawnTimeInSeconds < this.currentSpawnInterval ||
+ q > 0.05
+ ) {
return {
generation: this.nextGenerationId,
position: vec2.create(),
@@ -36,14 +73,16 @@ export class GameRules {
this.lastSpawnTimeInSeconds = timeInSeconds;
- return {
+ this.lastSpawnAction = {
generation: this.nextGenerationId,
position: vec2.fromValues(
Random.randomBetween(0, canvasSize.x),
Random.randomBetween(0, canvasSize.y)
),
- radius: settings.spawnRadius,
+ radius: this.currentSpawnRadius,
};
+
+ return this.lastSpawnAction;
}
public updateGenerationCounts({
@@ -55,8 +94,9 @@ export class GameRules {
const currentGenerationCount =
this.nextGenerationId % 2 === 1 ? evenGenerationCount : oddGenerationCount;
- if (currentGenerationCount === 0) {
+ if (currentGenerationCount <= 100) {
this.nextGenerationId++;
+ this.lastGenerationChangeTimeInSeconds = performance.now() / 1000;
}
this.generationCounts = {
@@ -64,4 +104,19 @@ export class GameRules {
nextGenerationCount,
};
}
+
+ public getNextGenerationMoveSpeed(): number {
+ const q = this.generationCounts.nextGenerationCount / settings.agentCount;
+ return mix(settings.moveSpeed / 8, settings.moveSpeed, q ** 2);
+ }
+
+ public getInfectionProbability(): number {
+ const q = this.generationCounts.nextGenerationCount / settings.agentCount;
+ return clamp(mix(0.3, 1, q * 5), 0, 0.9);
+ }
+
+ public getSensorOffset(): number {
+ const q = this.generationCounts.nextGenerationCount / settings.agentCount;
+ return mix(20, settings.sensorOffsetDistance, q);
+ }
}
diff --git a/src/index.html b/src/index.html
index 4337837..ecbeabc 100644
--- a/src/index.html
+++ b/src/index.html
@@ -37,7 +37,7 @@
-
+