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 @@ -
+