tarinai/js/physics_projection_system.js

32 lines
1.5 KiB
JavaScript

"use strict";
// Layer: physics/projection-bridge
// Shared tiny helpers for positional projection used by links, mechanical
// bodies, and circle/circle collision code.
(function (global) {
function num(v, fallback = 0) { const n = Number(v); return Number.isFinite(n) ? n : fallback; }
function markSpatialDirty(worldRef, item, reason = "projection", threshold = 0.35, minInterval = 0.065) {
const world = worldRef || item?.world || null;
if (!world || !item) return false;
const now = Number(world.time || 0) || 0;
const x = num(item.x), y = num(item.y), r = num(item.r || item.radius || 0);
const lastX = Number(item._lastProjectionSpatialDirtyX);
const lastY = Number(item._lastProjectionSpatialDirtyY);
const lastR = Number(item._lastProjectionSpatialDirtyR);
const missing = !Number.isFinite(lastX) || !Number.isFinite(lastY) || !Number.isFinite(lastR);
const moved = missing || Math.hypot(x - lastX, y - lastY) > threshold || Math.abs(r - lastR) > threshold;
const due = now >= Number(item._nextProjectionSpatialDirtyAt || 0);
if (!moved && !due) return false;
item._lastProjectionSpatialDirtyX = x;
item._lastProjectionSpatialDirtyY = y;
item._lastProjectionSpatialDirtyR = r;
item._nextProjectionSpatialDirtyAt = now + Math.max(0.016, num(minInterval, 0.065));
world.markSpatialDirty?.(reason);
return true;
}
global.TarinaiPhysicsProjectionSystem = Object.freeze({
markSpatialDirty,
});
})(typeof window !== "undefined" ? window : globalThis);