Composes a view of the world as an isometric picture: floors as diamonds, standing arts as blocks with a top and two shaded sides, movers and flat overlays as upright sprites, painted back to front.
Cauldron2D.Projection.Iso.compose(:my_game,
focus: {12.5, 8.5},
cell: &MyGame.cell/1,
size: {320, 200},
facing: 1,
movers: [{:hero, {12.5, 8.5}, heading}]
)A tile of t pixels is drawn as a diamond 2t wide and t * tilt tall, rounded to an
even number of pixels so neighbouring diamonds meet, and a storey is t tall. The
focus sits at the centre of the picture. facing turns the world a quarter turn at a
time by default: at facing 0 world +x runs down-right and +y down-left.
facings makes a turn out of more steps than four.
Up to 32 facings the view is blitted from stamps, one set per art per facing, built
on first use and kept in the atlas cache; a :facing between two steps is drawn at the
nearer. Above 32, and with facings: :free, the ground and the standing arts are
sampled a pixel at a time instead, which turns to any angle at all and costs upwards of
fifteen times as much a frame.
Options
:focus—{x, y}in tiles, the world point at the picture's centre, required:cell—fn {x, y} -> cell end, asCauldron2D.Surfacetakes cells, required:size—{width, height}of the picture in pixels, required:facing— which step of a turn the view is at,0tofacings - 1, clockwise. A fraction is drawn at the nearer step, unless the view samples, where it turns by part of a step. Default0:facings— how many steps make a full turn, at least4;:freefor a view that turns to any angle. Up to32the view is stamped, above it sampled. Default4:tilt— the diamond's height as a fraction of the tile size,0.5..1.5. Default1.0, a 2:1 diamond:shrink—1,2or4; the whole picture at that fraction of its size, so the same pixels show that many more tiles. Default1:movers—[{art, {x, y}}]or[{art, {x, y}, heading}]in tiles,headingin radians with0along+x. A mover shows its:frontpose when heading towards the camera and:backwhen away, mirrored when heading left; with no heading it faces the camera. Default[]:labels—[{text, {x, y}, colour}]or with a fourth element of options asCauldron2D.Surface.compose/4takes them, positioned by the tile. Default[]:volumes— coloured regions of space, asCauldron2D.Projection.Volumedescribes them, each tinting what is drawn behind it. Default[]:at— the time in milliseconds an animated art's frame is chosen for. Default0
project/2, unproject/2 and tile_at/2 map between picture pixels and world tiles
for the same options.
Summary
Functions
The cells this picture shows, each as {position, tile} with the tile the :cell
function gave for it.
The picture, as the module documentation describes.
The ground as a straight walk across the picture: {origin, across, down}, the world
point at the top-left pixel and the world it moves one pixel right and one pixel down.
Where world point {x, y} lands in the picture, in pixels from its top-left corner.
The tile under picture pixel {px, py}.
The world point under picture pixel {px, py}, on the ground.
The heading in radians, 0 along +x, a game walks for the :up action at the
:facing and :facings given, so that pressing up moves the same way across the
picture however far the view has turned. :down is against it and :left and
:right across it.
Types
@type option() :: {:focus, {number(), number()}} | {:cell, ({integer(), integer()} -> Cauldron2D.Surface.cell())} | {:size, {pos_integer(), pos_integer()}} | {:facing, 0..3} | {:tilt, number()} | {:shrink, 1 | 2 | 4} | {:movers, [tuple()]} | {:labels, [tuple()]} | {:volumes, [map()]} | {:at, integer()}
Functions
@spec cells(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), [option()]) :: [ {{integer(), integer()}, term()} ]
The cells this picture shows, each as {position, tile} with the tile the :cell
function gave for it.
Cells the function answered :void for are left out, and so is everything outside the
picture.
@spec compose(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), [option()]) :: FrenchCurve.Raster.t()
The picture, as the module documentation describes.
@spec ground_map(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), [option()]) :: {{float(), float()}, {float(), float()}, {float(), float()}}
The ground as a straight walk across the picture: {origin, across, down}, the world
point at the top-left pixel and the world it moves one pixel right and one pixel down.
The ground map is exact, so origin + px * across + py * down is the world point
unproject/3 answers for {px, py}. A caller drawing a grid can take the map once and
add.
@spec project(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), {number(), number()}, [ option() ]) :: {float(), float()}
Where world point {x, y} lands in the picture, in pixels from its top-left corner.
@spec tile_at(Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), {number(), number()}, [ option() ]) :: {integer(), integer()}
The tile under picture pixel {px, py}.
@spec unproject( Cauldron2D.Atlas.name() | Cauldron2D.Atlas.t(), {number(), number()}, [option()] ) :: {float(), float()}
The world point under picture pixel {px, py}, on the ground.
The heading in radians, 0 along +x, a game walks for the :up action at the
:facing and :facings given, so that pressing up moves the same way across the
picture however far the view has turned. :down is against it and :left and
:right across it.
Cauldron2D.Projection.Iso.up(facing: 5, facings: 16)