From ec01e1ce566ff6206788f18a30bea64099d6df9f Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Fri, 26 Jun 2026 22:19:13 +0500 Subject: [PATCH] fix: add frame factor calculations --- js/config.js | 8 ++++---- js/enemy.js | 6 +++--- js/game.js | 11 ++++++----- js/intro.js | 17 ++++++++++------- js/particle.js | 6 +++--- js/projectile.js | 6 +++--- js/utils.js | 14 +++++++++++++- 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/js/config.js b/js/config.js index 1b4a3f8..7bec1eb 100644 --- a/js/config.js +++ b/js/config.js @@ -29,11 +29,11 @@ const CONFIG = { gameOverDelay: 10000, }, speed: { - slowEnemyCrossTimeStart: 120, - slowEnemyCrossTimeCap: 20, + slowEnemyCrossTimeStart: 240, + slowEnemyCrossTimeCap: 30, slowEnemyCrossTimeCapWave: 50, - fastEnemyCrossTimeStart: 60, - fastEnemyCrossTimeCap: 10, + fastEnemyCrossTimeStart: 120, + fastEnemyCrossTimeCap: 15, fastEnemyCrossTimeCapWave: 50, bossCrossTime: 60, projectileCrossTime: 0.43, diff --git a/js/enemy.js b/js/enemy.js index 3b65f85..1b24bd3 100644 --- a/js/enemy.js +++ b/js/enemy.js @@ -112,9 +112,9 @@ class Enemy { } update() { - this.y += this.speed; - this.pulse += 0.05; - if (this.flashTimer > 0) this.flashTimer--; + this.y += this.speed * frameFactor; + this.pulse += 0.05 * frameFactor; + if (this.flashTimer > 0) this.flashTimer -= frameFactor; } draw() { diff --git a/js/game.js b/js/game.js index 9896c8a..c5580a2 100644 --- a/js/game.js +++ b/js/game.js @@ -230,7 +230,7 @@ function update() { if (gameState !== "playing") return; if (wavePauseActive) { - wavePauseTimer--; + wavePauseTimer -= frameFactor; if (wavePauseTimer <= 0) { wavePauseActive = false; waveEnemiesLeft = getEnemiesPerWave(); @@ -239,7 +239,7 @@ function update() { } } } else if (waveEnemiesLeft > 0) { - spawnTimer++; + spawnTimer += frameFactor; const spawnInterval = CONFIG.game.waveInterval / getEnemiesPerWave(); if (spawnTimer >= spawnInterval) { spawnEnemy(); @@ -248,7 +248,7 @@ function update() { } } - waveTimer++; + waveTimer += frameFactor; if (waveTimer >= CONFIG.game.waveInterval && !wavePauseActive && waveEnemiesLeft <= 0) { wave++; waveTimer = 0; @@ -283,7 +283,7 @@ function update() { } if (shakeTimer > 0) { - shakeTimer--; + shakeTimer -= frameFactor; shakeAmount *= 0.9; } } @@ -329,7 +329,8 @@ function draw() { ctx.restore(); } -function loop() { +function loop(timestamp) { + calcDt(timestamp); update(); draw(); if (gameLoopStarted) { diff --git a/js/intro.js b/js/intro.js index 2ca8057..a411854 100644 --- a/js/intro.js +++ b/js/intro.js @@ -83,27 +83,30 @@ function runIntro() { ctx.restore(); } - function introLoop() { - frame++; + function introLoop(timestamp) { + calcDt(timestamp); + const prevFrame = Math.floor(frame); + frame += frameFactor; + const curFrame = Math.floor(frame); if (frame <= I.fadeInFrames) { textAlpha = Math.min(1, frame / I.fadeInFrames); } - if (frame === I.shot1Frame) shots.push({ progress: 0, trail: [], done: false }); - if (frame === I.shot2Frame) shots.push({ progress: 0, trail: [], done: false }); - if (frame === I.shot3Frame) shots.push({ progress: 0, trail: [], done: false }); + if (prevFrame < I.shot1Frame && curFrame >= I.shot1Frame) shots.push({ progress: 0, trail: [], done: false }); + if (prevFrame < I.shot2Frame && curFrame >= I.shot2Frame) shots.push({ progress: 0, trail: [], done: false }); + if (prevFrame < I.shot3Frame && curFrame >= I.shot3Frame) shots.push({ progress: 0, trail: [], done: false }); for (let s of shots) { if (s.done) continue; - s.progress = Math.min(1, s.progress + I.shotSpeed); + s.progress = Math.min(1, s.progress + I.shotSpeed * frameFactor); const x = shooterX + (lTargetX - shooterX) * s.progress; const y = shooterY + (lTargetY - shooterY) * s.progress; s.trail.push({ x, y, life: 1 }); if (s.trail.length > I.trailMax) s.trail.shift(); - for (let t of s.trail) t.life -= I.trailDecay; + for (let t of s.trail) t.life -= I.trailDecay * frameFactor; s.trail = s.trail.filter((t) => t.life > 0); if (s.progress >= 1) { diff --git a/js/particle.js b/js/particle.js index b698269..57976e9 100644 --- a/js/particle.js +++ b/js/particle.js @@ -10,9 +10,9 @@ class Particle { this.size = S.particleSizeMin + Math.random() * (S.particleSizeMax - S.particleSizeMin); } update() { - this.x += this.vx; - this.y += this.vy; - this.life -= this.decay; + this.x += this.vx * frameFactor; + this.y += this.vy * frameFactor; + this.life -= this.decay * frameFactor; this.vx *= S.particleDamping; this.vy *= S.particleDamping; } diff --git a/js/projectile.js b/js/projectile.js index 09ca387..fd4c1dc 100644 --- a/js/projectile.js +++ b/js/projectile.js @@ -36,12 +36,12 @@ class Projectile { if (this.trail.length > S.projectileTrailLength) this.trail.shift(); for (let t of this.trail) { - t.life -= S.projectileTrailDecay; + t.life -= S.projectileTrailDecay * frameFactor; } this.trail = this.trail.filter((t) => t.life > 0); - this.x += this.vx; - this.y += this.vy; + this.x += this.vx * frameFactor; + this.y += this.vy * frameFactor; if (this.isHit && this.target && !this.hit) { const dx = this.target.x - this.x; diff --git a/js/utils.js b/js/utils.js index 6d347b5..051da6a 100644 --- a/js/utils.js +++ b/js/utils.js @@ -1,3 +1,15 @@ +let frameFactor = 1; +let _lastTime = 0; + +function calcDt(timestamp) { + if (!_lastTime || !timestamp) { + frameFactor = 1; + } else { + frameFactor = Math.min((timestamp - _lastTime) / (1000 / 60), 6); + } + _lastTime = timestamp || performance.now(); +} + function crossTimeToSpeed(crossTimeSec) { const playH = H - S.removeZone; return playH / (crossTimeSec * 60); @@ -191,7 +203,7 @@ function drawGrid() { ctx.strokeStyle = CONFIG.colors.primaryGrid; ctx.lineWidth = 1; const gridSize = S.gridSize; - bgOffset = (bgOffset + S.gridSpeed) % gridSize; + bgOffset = (bgOffset + S.gridSpeed * frameFactor) % gridSize; for (let x = 0; x <= W; x += gridSize) { ctx.beginPath(); ctx.moveTo(x, 0);