fix(camera): sticky focusPoint + per-frame camera loop (stop corner-snap mid-run)

The player-centered camera snapped the dungeon to the top-left corner after a while: the
renderer nulled focusPoint on a transient player-less frame, so the transform lost its
translate. Fix: focusPoint is now sticky (keep the last if the player is momentarily
absent), and the SP bridge re-applies the camera every frame via its own RAF loop, so a
canvas resize or a stale frame can no longer break centering.
This commit is contained in:
jwinterm
2026-07-12 12:32:35 -04:00
parent dd7d70aec8
commit 03fd82c44c
3 changed files with 19 additions and 4 deletions
+2 -2
View File
@@ -268,12 +268,12 @@
}
}
}
this.focusPoint = null;
for (var i = 0; i < scene.entities.length; i++) {
var e = scene.entities[i];
p = this._project(e.x, e.y, originX, originY);
items.push({ type: 'entity', e: e, sx: p.x, sy: p.y, depth: e.x + e.y + 0.55 });
if (e.you || e.kind === 'player') this.focusPoint = { x: p.x, y: p.y + this.tileH }; // SP camera target
// Sticky camera target (keep last if the player is momentarily absent).
if (e.you || e.kind === 'player') this.focusPoint = { x: p.x, y: p.y + this.tileH };
}
items.sort(function (a, b) { return a.depth === b.depth ? (a.y || 0) - (b.y || 0) : a.depth - b.depth; });
+13
View File
@@ -128,9 +128,22 @@
host.style.display = 'block';
toggleLegacy(true);
SP._live = true;
SP._startCameraLoop();
return true;
};
// Re-apply the camera every frame while live — robust against the renderer resizing its canvas
// or a transient focusPoint, which was making the view snap to the corner mid-run.
SP._startCameraLoop = function () {
if (SP._camRaf != null) return;
function tick() {
if (!SP._live) { SP._camRaf = null; return; }
SP._applyCamera();
SP._camRaf = root.requestAnimationFrame(tick);
}
SP._camRaf = root.requestAnimationFrame(tick);
};
// Back to the ROT view (splash / win / lose). Call on game end.
SP.hide = function () {
SP._live = false;
+4 -2
View File
@@ -284,9 +284,11 @@
// Snapshot the base scene, then composite the torch light + vignette on top, and keep
// an animation loop running so the light flickers and embers drift between renders.
// Where the player is on this canvas — the SP camera centers the view on it.
// Where the player is on this canvas — the SP camera centers on it. Sticky: keep the last
// point if the player is momentarily absent (level transition), so the view never snaps to
// the corner.
var _fp = findPlayer(scene);
this.focusPoint = _fp ? { x: (_fp.x + 0.5) * cell, y: (_fp.y + 0.5) * cell } : null;
if (_fp) this.focusPoint = { x: (_fp.x + 0.5) * cell, y: (_fp.y + 0.5) * cell };
this._lastScene = scene;
this._collectEmitters(scene);