tarinai/js/simulation_runtime_helpers.js

76 lines
2.8 KiB
JavaScript
Raw Normal View History

2026-06-26 12:46:32 +09:00
"use strict";
// Layer: simulation/helpers
// Shared, UI-free helpers used by the concrete simulation systems.
(function (global) {
2026-06-29 16:21:58 +09:00
const policy = global.TarinaiItemUpdatePolicy;
2026-06-26 12:46:32 +09:00
function forScheduledItems(worldRef, visitor) {
2026-06-29 16:21:58 +09:00
return policy.forScheduledItems(worldRef, visitor);
2026-06-26 12:46:32 +09:00
}
function updateItemsScheduled(worldRef, dt) {
2026-06-29 16:21:58 +09:00
return global.TarinaiItemRuntime.updateScheduled(worldRef, dt);
2026-06-26 12:46:32 +09:00
}
2026-07-01 14:41:05 +09:00
function trackSpatialEntityMoved(entity, thresholdSq) {
if (!entity || entity.dead) return false;
const x = Number.isFinite(entity.x) ? entity.x : 0;
const y = Number.isFinite(entity.y) ? entity.y : 0;
const oldX = entity._spatialTrackX;
const oldY = entity._spatialTrackY;
if (!Number.isFinite(oldX) || !Number.isFinite(oldY)) {
entity._spatialTrackX = x;
entity._spatialTrackY = y;
return true;
}
const dx = x - oldX;
const dy = y - oldY;
if (dx * dx + dy * dy <= thresholdSq) return false;
entity._spatialTrackX = x;
entity._spatialTrackY = y;
return true;
}
2026-06-26 12:46:32 +09:00
function markSpatialDirtyIfMoved(worldRef, list, reason = "moved", threshold = 0.35) {
if (!worldRef || !Array.isArray(list) || !list.length) return false;
const thresholdSq = threshold * threshold;
let moved = false;
2026-07-01 14:41:05 +09:00
for (const entity of list) moved = trackSpatialEntityMoved(entity, thresholdSq) || moved;
2026-06-26 12:46:32 +09:00
if (moved) worldRef.markSpatialDirty?.(reason);
return moved;
}
function markScheduledItemsMoved(worldRef, reason = "items-moved", threshold = 0.35) {
if (!worldRef) return false;
const thresholdSq = threshold * threshold;
let moved = false;
2026-06-29 16:21:58 +09:00
const tracked = global.TarinaiItemRuntime.trackedDynamicItems(worldRef);
2026-06-26 12:46:32 +09:00
const source = tracked && tracked.length ? tracked : null;
2026-07-01 14:41:05 +09:00
const visit = (entity) => { moved = trackSpatialEntityMoved(entity, thresholdSq) || moved; };
if (source) for (const entity of source) visit(entity);
else forScheduledItems(worldRef, visit);
2026-06-26 12:46:32 +09:00
if (moved) worldRef.markSpatialDirty?.(reason);
return moved;
}
function updateVisibleWorldRect(worldRef, margin = 120) {
const scale = worldRef.viewScale ? worldRef.viewScale() : 1;
const vw = (worldRef.viewportW || worldRef.w || 1000) / Math.max(0.01, scale);
const vh = (worldRef.viewportH || worldRef.h || 720) / Math.max(0.01, scale);
const cameraX = worldRef.cameraX || 0;
const cameraY = worldRef.cameraY || 0;
return { left: cameraX - margin, top: cameraY - margin, right: cameraX + vw + margin, bottom: cameraY + vh + margin };
}
const helpers = Object.freeze({
updateItemsScheduled,
markSpatialDirtyIfMoved,
markScheduledItemsMoved,
updateVisibleWorldRect,
});
global.TarinaiSimulationRuntime = Object.freeze({
2026-06-29 16:21:58 +09:00
helpers
2026-06-26 12:46:32 +09:00
});
})(typeof window !== "undefined" ? window : globalThis);