Cauldron2D.Camera (Cauldron2D v0.1.3)

Copy Markdown View Source

Resolves which part of a world is on screen.

Cauldron2D.Camera.view(
  focus: {x, y},
  size: {columns, rows},
  cell: fn {x, y} -> cell end
)

:cell is called exactly once per visible tile, with that tile's world coordinate, and returns a Cauldron2D.Surface.cell/0. It is the only thing the engine asks of a game.

The viewport is always centred on :focus: at a world's edge, or zoomed out past it, the coordinates asked for run outside the world and :cell answers for them (:void, or a wrapped tile) — the focus never moves off the centre to keep the world on screen.

A tile occupies two terminal cells across and one down. columns_for/1 and rows_for/1 convert a pane's size in cells into a viewport size in tiles; zoomed/2 scales that size for a zoom — how many times larger than native a tile is drawn — and tile_at/3 and zoom_about/6 map cells back through it. A :size may be fractional: the origin centres the focus exactly, and the tiles read cover the fraction.

Summary

Functions

How many tiles wide a pane width terminal cells across can show; always at least 1.

Where a viewport size tiles across sits in world coordinates when focus is at its exact centre, as floats.

The view as glyphs and colours, for renderers that draw characters.

Where a viewport size tiles across sits in world coordinates when centred on focus.

How many tiles tall a pane height terminal cells high can show; always at least 1.

The world tile under {column, row}, given in terminal cells relative to the pane's top-left corner, for a viewport whose origin is the first argument.

tile_at/2 through a zoom: a tile drawn zoom times its native size spans 2 * zoom cells across and zoom down.

Resolve the viewport and read every tile in it.

The focus that keeps the world under cell where it is on screen when a pane of native size goes from from to to zoom, centred on focus before. Zooming back the same way about the same cell returns to the focus it started from.

The viewport in tiles of a pane size tiles across at native size, drawn at zoom.

Types

point()

@type point() :: {integer(), integer()}

t()

@type t() :: %Cauldron2D.Camera{
  cells: [[Cauldron2D.Surface.cell()]],
  columns: pos_integer(),
  origin: point(),
  rows: pos_integer(),
  scroll: {float(), float()}
}

Functions

columns_for(width)

@spec columns_for(non_neg_integer()) :: pos_integer()

How many tiles wide a pane width terminal cells across can show; always at least 1.

exact_origin(arg1, arg2)

@spec exact_origin({number(), number()}, {number(), number()}) :: {float(), float()}

Where a viewport size tiles across sits in world coordinates when focus is at its exact centre, as floats.

glyphs(atlas, camera)

The view as glyphs and colours, for renderers that draw characters.

Each cell becomes {glyph, {r, g, b}} with the tint already applied, in the same row and column order as :cells. A cell with overlays takes the glyph and colour of its topmost overlay; :void becomes two spaces in the atlas's void colour.

origin(arg1, arg2)

@spec origin(point(), {pos_integer(), pos_integer()}) :: point()

Where a viewport size tiles across sits in world coordinates when centred on focus.

This is the :origin view/1 produces for the same arguments, so a caller mapping a screen position back to the world resolves against the same tiles that were drawn.

A fractional focus is rounded to the nearest tile first.

rows_for(height)

@spec rows_for(non_neg_integer()) :: pos_integer()

How many tiles tall a pane height terminal cells high can show; always at least 1.

tile_at(arg1, arg2)

@spec tile_at(point(), {number(), number()}) :: {float(), float()}

The world tile under {column, row}, given in terminal cells relative to the pane's top-left corner, for a viewport whose origin is the first argument.

The result is fractional and resolves to the centre of the cell, so trunc/1 on either coordinate gives the whole tile the cell belongs to. The column is halved, since a tile is two cells wide: cells 0 and 1 both fall in tile 0, at 0.25 and 0.75.

Pair with origin/3 to map a pointer position back to the world it is over.

tile_at(arg1, arg2, zoom)

@spec tile_at({number(), number()}, {number(), number()}, number()) ::
  {float(), float()}

tile_at/2 through a zoom: a tile drawn zoom times its native size spans 2 * zoom cells across and zoom down.

view(opts)

@spec view(keyword()) :: t()

Resolve the viewport and read every tile in it.

Returns a t/0 whose :cells is a list of rows rows, each of columns cells, in top-to-bottom and left-to-right order, and whose :origin is the world coordinate of the top-left tile.

Options

  • :focus — the {x, y} world point to centre on, required
  • :size{columns, rows} in tiles, required, both positive, whole or not
  • :cellfn {x, y} -> cell end, required
  • :scrolltrue to keep the focus at the exact centre: :origin is then the exact origin rounded down, :cells holds one more column and one more row than :size, and :scroll is the fraction of a tile, {0.0..1.0, 0.0..1.0}, the cells are to be shifted left and up by. Default false: :origin is origin/3, :cells is exactly :size, :scroll is {0.0, 0.0}

zoom_about(focus, cell, size, from, to)

@spec zoom_about(
  {number(), number()},
  {number(), number()},
  {number(), number()},
  number(),
  number()
) ::
  {float(), float()}

The focus that keeps the world under cell where it is on screen when a pane of native size goes from from to to zoom, centred on focus before. Zooming back the same way about the same cell returns to the focus it started from.

zoomed(arg, zoom)

@spec zoomed({number(), number()}, number()) :: {float(), float()}

The viewport in tiles of a pane size tiles across at native size, drawn at zoom.