tarinai/js/simulation_creature_system.js
2026-06-26 12:46:32 +09:00

70 lines
3.3 KiB
JavaScript

"use strict";
// Layer: simulation/system-creatures
// Owns Tarinai update cadence, Tarinai movement invalidation, and creature
// collision/interactions scheduled after individual updates.
(function (global) {
const helpers = () => global.TarinaiSimulationRuntime?.helpers || {};
const updatePolicy = () => global.TarinaiCreatureUpdatePolicy || {};
function updateCreatures(worldRef, dt) {
const h = helpers();
const end = global.TarinaiPerf?.begin?.("update.tarinai") || null;
const visibleRect = h.updateVisibleWorldRect?.(worldRef, 160) || { left: -Infinity, top: -Infinity, right: Infinity, bottom: Infinity };
try {
for (const t of worldRef.tarinai) {
if (!t || t.dead) continue;
const interval = updatePolicy().updateInterval?.(worldRef, t, visibleRect) ?? 0;
if (!Number.isFinite(interval)) continue;
if (interval <= 0) {
const runDt = Math.min(1.4, (t._updateAccum || 0) + dt);
t._updateAccum = 0;
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt);
else t.update(runDt);
continue;
}
t._updateAccum = Math.min(2.4, (t._updateAccum || 0) + dt);
t._nextLowFreqUpdateAt = Number.isFinite(t._nextLowFreqUpdateAt) ? t._nextLowFreqUpdateAt : (worldRef.time || 0) + interval * (0.65 + Math.random() * 0.7);
if ((worldRef.time || 0) >= t._nextLowFreqUpdateAt) {
const runDt = Math.max(dt, t._updateAccum || dt);
t._updateAccum = 0;
t._nextLowFreqUpdateAt = (worldRef.time || 0) + interval;
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt);
else t.update(runDt);
}
}
} finally {
if (end) end();
}
const now = worldRef.time || 0;
const bedConflictInterval = 3.2;
if (now >= (worldRef.nextBedConflictCheckAt || 0)) {
worldRef.nextBedConflictCheckAt = now + bedConflictInterval;
worldRef.workStats && (worldRef.workStats.bedConflictRuns = (worldRef.workStats.bedConflictRuns || 0) + 1);
worldRef.resolveOwnedBedSleepConflicts?.();
} else {
worldRef.workStats && (worldRef.workStats.bedConflictSkips = (worldRef.workStats.bedConflictSkips || 0) + 1);
}
h.markSpatialDirtyIfMoved?.(worldRef, worldRef.tarinai, "tarinai-moved", 0.25);
worldRef.ensureSpatial?.("post-tarinai-update");
worldRef.limitBallChasers();
worldRef.resolveBallInteractions(dt);
const collisionInterval = 1.8;
if (now >= (worldRef.nextTarinaiCollisionCheckAt || 0)) {
worldRef.nextTarinaiCollisionCheckAt = now + collisionInterval;
worldRef.workStats && (worldRef.workStats.collisionRuns = (worldRef.workStats.collisionRuns || 0) + 1);
worldRef.resolveTarinaiHighSpeedCollisions(dt);
} else {
worldRef.workStats && (worldRef.workStats.collisionSkips = (worldRef.workStats.collisionSkips || 0) + 1);
}
}
const phases = Object.freeze({ updateCreatures });
const helpersApi = Object.freeze({
updateInterval(worldRef, tarinai, visibleRect) {
return updatePolicy().updateInterval?.(worldRef, tarinai, visibleRect) ?? Infinity;
},
});
global.TarinaiCreatureSimulationSystem = Object.freeze({ phases, helpers: helpersApi });
})(typeof window !== "undefined" ? window : globalThis);