tarinai/js/simulation_effects_system.js
2026-07-01 22:59:49 +09:00

50 lines
1.9 KiB
JavaScript

"use strict";
// Layer: simulation/system-effects
// Owns frame updates for transient visual/effect entities.
(function (global) {
function updateEffect(effect, dt, frameId = 0) {
if (!effect || effect.dead) return false;
const runDt = Math.min(0.24, Math.max(0, Number(effect._effectUpdateAccum || 0) + dt));
effect._effectUpdateAccum = 0;
effect._effectUpdatedFrame = frameId;
effect.update(runDt);
return true;
}
function updateEffects(worldRef, dt) {
const effects = worldRef.effects || [];
const total = effects.length;
const frameId = (worldRef._effectUpdateFrameId || 0) + 1;
worldRef._effectUpdateFrameId = frameId;
if (total <= 56) {
for (const ef of effects) updateEffect(ef, dt, frameId);
worldRef._effectUpdateStats = { total, updated: total, skipped: 0, batched: false };
return;
}
const budget = Math.max(40, Math.ceil(total * 0.42));
let cursor = Math.max(0, Math.floor(worldRef._effectUpdateCursor || 0)) % total;
let updated = 0;
let scanned = 0;
while (updated < budget && scanned < total) {
const ef = effects[cursor];
cursor = (cursor + 1) % total;
scanned += 1;
if (!ef || ef.dead) continue;
updateEffect(ef, dt, frameId);
updated += 1;
}
for (let i = 0; i < total; i += 1) {
const ef = effects[i];
if (!ef || ef.dead || ef._effectUpdatedFrame === frameId) continue;
if (Number.isFinite(ef._effectUpdateAccum)) ef._effectUpdateAccum = Math.min(0.24, ef._effectUpdateAccum + dt);
else ef._effectUpdateAccum = dt;
}
worldRef._effectUpdateCursor = cursor;
worldRef._effectUpdateStats = { total, updated, skipped: Math.max(0, total - updated), batched: true };
}
global.TarinaiEffectsSimulationSystem = Object.freeze({
phases: Object.freeze({ updateEffects }),
});
})(typeof window !== "undefined" ? window : globalThis);