Skip to main content

Module camera

Module camera 

Source
Expand description

A scrolling viewport into a world larger than the screen. A scrolling viewport into a world larger than the screen.

Camera is pure geometry: it converts between world coordinates (cells in some large space) and screen coordinates (cells in a Rect on the terminal), and reports which world cells are currently visible. It holds no rendering opinion, so it works with any drawing style and is testable without a backend.

 world space (Size)                      screen space (terminal cells)
 +--------------------------------+
 |                                |       viewport (a Rect on screen)
 |        origin                  |       +------------------+
 |          x----------------+    |       | (vp.left, vp.top)|
 |          | visible_bounds |    |  ==>  |   +----------+   |
 |          |   (clamped to  |    |       |   | drawn    |   |
 |          |    the world)  |    |       |   |  cells   |   |
 |          +----------------+    |       |   +----------+   |
 |                                |       +------------------+
 +--------------------------------+

 origin = world cell shown at the viewport's top-left, clamped to [0, world - viewport].
 world_to_screen(w) = viewport.top_left + (w - origin), culled to visible_bounds.
 screen_to_world(s) = origin + (s - viewport.top_left), culled to the world.

Centering clamps to the world edges (the “scrolling map” convention): the viewport never scrolls past [0, world), so the target stays centered except near the edges, where it drifts toward the corner. A world smaller than the viewport pins the origin at (0, 0), with all the slack on the right and bottom of the given viewport rect; use set_viewport_fitted instead of set_viewport when a world that may be smaller than its viewport (a fixed board, a generated map, a minimap) should be letterboxed and centered instead.

See the 12_dungeon_scroll example for Camera in action: https://main.retroglyph.dev/examples/12_dungeon_scroll/terminal/.

Grid::from_charmap builds a styled grid from an ASCII map or level string, one tile per character; combined with a Camera and multi-layer compositing, this is how a scrolling roguelike loads and follows a map larger than the screen (see the 11_sokoban example for from_charmap itself, and 15_outpost_dashboard for a Camera used alongside a UI).

§Example

use retroglyph_core::grid::{Pos, Rect, Size};
use retroglyph_ui::Camera;

// A 10x10 viewport onto a 100x100 world.
let mut cam = Camera::new(Rect::new(0, 0, 10, 10), Size::new(100, 100));
cam.center_on(Pos::new(50, 50));
assert_eq!(cam.origin(), Pos::new(45, 45));
assert_eq!(cam.world_to_screen(Pos::new(50, 50)), Some(Pos::new(5, 5)));
// Near an edge the view clamps rather than showing past the world.
cam.center_on(Pos::new(1, 1));
assert_eq!(cam.origin(), Pos::new(0, 0));

Structs§

Camera
A rectangular viewport onto a larger world, with world/screen conversions.