BeeEngine logo BeeEngine JAVASCRIPT 2D ENGINE

Camera 2D in JavaScript: follow, scroll e screenToWorld

Documentazione – BeeEngine
v2.9.5

BeeCamera — Documentazione Tecnica

Inquadratura mondo: follow, tick dal loop se è gioco.camera, apply / screenToWorld

📁 Panoramica

BeeCamera è lo scroll 2D del mondo. Vive in src/graphics/BeeCamera.js. Il motore parte con gioco.camera = null: la crei e la agganci tu. Appena è gioco.camera, il loop fa host(true). Dopo scene, entità, fisica e gioco.update chiama update(dt, true) se non è in pausa e c’è un target.

Poi save → apply → mondo / tilemap / drawEntity (già con culling) → restore. HUD, BeeUI e overlay restano in pixel schermo, sopra lo scroll.

gioco.camera = new BeeCamera(gioco.canvas.width, gioco.canvas.height); gioco.camera .setBounds(0, 0, 1600, 900) .follow(hero, 0.08);

📁 Update

Centro del bersaglio: worldX/Y se sono numeri, senno x/y. Senza width/height: 0. Target destroyed o dt ≤ 0: non segue, ma reclampa sui bounds.

  1. 1. followUna volta (enter o update): setta target e smooth. follow(null) stacca.
  2. 2. updateHosted: no-op se non fromHost. smooth in (0, 1): lerp 1-(1-s)^(dt*60); senno snap.
  3. 3. applytranslate(-round(x), -round(y)). Il clamp tiene quel round dentro i bounds.

📁 Dove è facile sbagliare

follow basta su gioco.camera. Il loop la hosta e chiama update(dt, true) dopo gioco.update. Un camera.update(dt) a mano è no-op (evita il doppio lerp). Fuori da gioco.camera la ticks tu.

Size sul canvas. Ogni frame il motore fa setSize(canvas.width, canvas.height) sulla camera hostata. setSize ricalcola anche il clamp sui bounds.

Bounds. setBounds clampa subito (non aspetti l’update). Se il mondo è più stretto della vista, centra il rettangolo. setBounds(null) toglie i limiti; NaN o lati negativi lasciano quelli già settati. Il clamp tiene Math.round(x/y) dentro i bounds, così apply non esce di un pixel.

HUD e click. Dopo restore il canvas è in pixel schermo. Per un click nel mondo: screenToWorld (stesso round di apply).

📁 Esempio: follow sul player

gioco.camera = new BeeCamera(800, 600); gioco.camera.setBounds(0, 0, 1600, 900); gioco.camera.follow(hero, 0.08);

drawEntity e la tilemap già saltano ciò che sta fuori vista. Per un punto schermo (click, puntatore) usa screenToWorld.

const r = canvas.getBoundingClientRect(); const sx = (e.clientX – r.left) * (canvas.width / r.width); const sy = (e.clientY – r.top) * (canvas.height / r.height); const mondo = gioco.camera.screenToWorld(sx, sy);

📁 Riepilogo API

Non estende BeeEntity. Default costruttore 800×600 se w/h non sono numeri > 0.

Membro Ritorna Scopo
new BeeCamera(w?, h?) BeeCamera x/y 0. target null. smooth 0.1.
follow(target, smooth?) this Memorizza il bersaglio. follow(null) stacca. Secondo argomento omesso: tiene lo smooth attuale.
host(on) this true quando è gioco.camera. Il loop lo setta; al destroy lo toglie.
update(dt, fromHost?) this Muove e clamp. Hosted: no-op se fromHost non è true. Senza target, destroyed o dt ≤ 0: non segue, i bounds si riallineano lo stesso.
apply(ctx) this Translate arrotondato. Senza ctx: return.
setBounds(x, y, w, h) / setSize(w, h) this setBounds(null) toglie i limiti. NaN / lati < 0: ignora. Entrambi reclampano subito. Su gioco.camera w/h seguono il canvas ogni frame.
getViewBounds() / isRectVisible(x,y,w,h) rect / boolean Stesso round di apply. Width/height ≤ 0: non visibile.
screenToWorld(sx, sy) / worldToScreen(wx, wy) { x, y } Pixel canvas ↔ mondo, stesso round di apply.