Camera2D
The orthographic camera of a Scene2D: which part of the 2D world is on screen,
how far it is zoomed in, and the conversion between screen and world points. Every scene owns one
— scene.camera; you never construct a Camera2D. The 3D camera is Camera.
- make the camera follow the player
- zoom in for pixel art, pan or rotate the view
- turn a screen point (a tap, a drag) into a point in the 2D world
- find where a world point is on the screen
Platforms: iOS, Android, desktop, the web player, the le.codes viewer app; not on the web (Web
Lite, lecodes web). In headless tests screenToWorld / worldToScreen work against a 1×1 view
and return wrong points.
At a glance
async function main() {
const scene = new Scene2D()
scene.camera.zoom = 2 // 2× magnification — pixel-art friendly
scene.camera.position = [0, 0] // the world point at the center of the screen
const tex = await Texture2D.load(asset('./hero.png'))
const hero = new Sprite({ texture: tex })
scene.add(hero)
// a drag reports screen points; the camera turns them into world points
scene.addEventListener('touchstart', ev => {
ev.track({ onMove: p => { hero.position = scene.camera.screenToWorld(p.clientX, p.clientY) } })
})
scene.open()
}
main()Pan, zoom and rotate the view: position, zoom, rotation
camera.position = [x, y] // world units — the point at the center of the screen
camera.zoom = 2 // magnification; at 1, 1 world unit = 1 logical px. Default 1
camera.rotation = 15 // degrees, CCW. Default 0Getters return fresh values; camera.position.x = 3 written directly compiles to a camera write, a
stored copy stays a copy — see conventions.
rotation turns the camera, so the world turns the other way on screen: at 90, world +X points
down the screen.
Make the camera follow the player
There is no follow(): an aspect on the player whose update(dt) — the late phase, after physics
— eases the camera toward the node. It goes away with the node; there is nothing to dispose.
class Follow extends Aspect<'follow', Node2D> {
camera!: Camera2D
update(dt: number) { // late phase: after physics, before the draw
this.camera.position = this.camera.position.lerp(this.node.worldPosition, 10 * dt)
}
}
async function main() {
const scene = new Scene2D()
scene.camera.zoom = 2
const tex = await Texture2D.load(asset('./hero.png'))
const hero = new Sprite({ texture: tex }).aspect(Follow, { camera: scene.camera })
scene.add(hero)
scene.open()
}
main()The built-in CameraFollow does the same and adds pixel snapping:
use(CameraFollow, …) in a .scene2d.ts file, or hero.aspect(CameraFollow, { scene }) in code
(which runs, but a project's type-check currently rejects it — see its note).
Turn a tap into a world point: screenToWorld / worldToScreen
Convert a tap or drag position on the screen to a point in the 2D world, and back.
camera.screenToWorld(screenX, screenY): Vec2 // logical px → world units
camera.worldToScreen(worldX, worldY): Vec2 // world units → logical pxscreenToWorld turns a tap or drag point (clientX / clientY) into the world: feed it to
scene.pick() or Physics2D.overlapPoint(). A scene's own click /
touchstart already carry ev.worldX / ev.worldY. Screen Y points down, world Y points up —
the conversion handles the flip.
both use the size of the view the scene is drawn in, so they are meaningful once the scene is on screen — before its first frame they work against a 1×1 view.
See also
- Scene2D — the owning scene,
pick() - 2D scene files —
CameraFollow, camera nodes - 2D physics —
overlapPoint,raycast - Pointer events & gestures —
clientX/clientYare logical px