Removes internal process references so the repo is presentable to an outside audience: dropped the internal build-retrospective doc (process log with internal terms, not useful to an outside reader), and reworded remaining internal references in code comments and module docs (agents.md cards, architecture.md, MODULES.md, index.html, package.json) to generic descriptions of what changed and when, with no behavior change -- full 47/47 suite re-run green after the scrub, every edit verified comment/doc-only via diff. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
70 lines
2.8 KiB
JavaScript
70 lines
2.8 KiB
JavaScript
/* ISLE SLINGERS -- physics/camera/index.js (submodule: camera)
|
|
* Modularization pass (behavior-neutral split of the original
|
|
* js/core.js monolith). Installs its units into ONE shared physics scope `P`
|
|
* that every physics submodule sees -- the same single-scope semantics the
|
|
* monolith had. Must load before js/physics/index.js (the aggregator that
|
|
* attaches the public ISLE_CORE API). Surface installed: updatePopups, updateCameraTarget, decayCamera.
|
|
*/
|
|
(function (root, factory) {
|
|
var part = factory();
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = part;
|
|
else (root.ISLE_PHYSICS_PARTS = root.ISLE_PHYSICS_PARTS || []).push(part);
|
|
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
|
|
'use strict';
|
|
return function (P) {
|
|
P.updatePopups = function(g, dt) {
|
|
for (var i = g.scorePopups.length - 1; i >= 0; i--) {
|
|
g.scorePopups[i].age += dt;
|
|
g.scorePopups[i].y -= 40 * dt;
|
|
if (g.scorePopups[i].age > 1.4) g.scorePopups.splice(i, 1);
|
|
}
|
|
}
|
|
|
|
P.updateCameraTarget = function(g) {
|
|
var b = P.activeBird(g);
|
|
var cam = g.camera;
|
|
var tx, ty, tz;
|
|
if (b && b.state === 'flying') {
|
|
// in flight: follow the slinger 1:1 (the bird IS the point of interest)
|
|
tx = Math.max(420, Math.min(P.WORLD.w - 420, b.x + 220));
|
|
ty = Math.max(380, Math.min(P.WORLD.ground - 160, b.y + 60));
|
|
tz = 1;
|
|
} else {
|
|
// aiming / waiting: frame the slingshot AND the whole action zone
|
|
// (live blocks + enemies) so P.launch point and target are always
|
|
// visible at once — zooming out when the level needs it. Without
|
|
// this the sling was visible but the fort was off-screen (or
|
|
// vice-versa mid-flight), making aiming pure guesswork.
|
|
var left = g.level.sling.x - 190;
|
|
var right = left + 300;
|
|
for (var i = 0; i < g.blocks.length; i++) {
|
|
var bl = g.blocks[i];
|
|
if (bl.hp > 0) right = Math.max(right, bl.x + bl.w / 2 + 90);
|
|
}
|
|
for (var k = 0; k < g.enemies.length; k++) {
|
|
var en = g.enemies[k];
|
|
if (!en.dead) right = Math.max(right, en.x + en.r + 90);
|
|
}
|
|
var span = right - left;
|
|
tz = Math.min(1, P.VIEW.w / span);
|
|
tx = left + span / 2;
|
|
// ground at ~78% down the view, whatever the zoom
|
|
ty = Math.max(300, Math.min(P.WORLD.ground, P.WORLD.ground - (0.28 * P.VIEW.h) / tz));
|
|
}
|
|
if (cam.snap) { // first frame of a level: land on target, no pan
|
|
cam.x = tx; cam.y = ty; cam.zoom = tz; cam.snap = false;
|
|
return;
|
|
}
|
|
cam.x += (tx - cam.x) * 0.06;
|
|
cam.y += (ty - cam.y) * 0.06;
|
|
cam.zoom = (cam.zoom || 1) + (tz - (cam.zoom || 1)) * 0.08;
|
|
}
|
|
|
|
P.decayCamera = function(g, dt) {
|
|
if (g.camera.shake > 0) {
|
|
g.camera.shake *= Math.pow(0.03, dt); // fast decay
|
|
if (g.camera.shake < 0.3) g.camera.shake = 0;
|
|
}
|
|
}
|
|
};
|
|
});
|