# tiled

`import "github.com/matjam/bunyip/tiled"`

Package tiled reads maps saved by the Tiled editor and builds drawable levels from them. It decodes the JSON form (.tmj or .json maps, .tsj tilesets) and the XML form (.tmx maps, .tsx tilesets) into plain Go types. Parse distinguishes the forms by their first byte, and a map in one form may name an external tileset in the other. Parse and Load need no GPU. Build turns a Map into gfx tilemaps for drawing.

A Map has tile layers (CSV or base64 with zlib, gzip or zstd compression, flipped and rotated tiles), object layers (rectangles, ellipses, points, polygons and polylines with their names, types and custom properties, for spawn points, triggers and collision shapes), image layers and groups, and tilesets embedded or external with per-tile animations, collision shapes, properties and terrain sets from the terrain tool (a WangSet converts to grid/autotile rules with its Rules method, or RulesFor with the layout Map.Layout gives a hexagonal map). Build loads the tilesets' images, makes one gfx.Tilemap per tile layer with the animations wired up, and returns a Level whose Draw draws the layers in order on a rectangular grid. Parsing a map's orientation does not make Build render isometric or hexagonal layouts. Image layers and image-collection tilesets are parsed but not drawn by Build. Keep the object layers to place your own entities. Properties are typed (string, int, float, bool, colour, file, object) and read with the accessors on Properties.

## Constants

<a id="FlipX"></a>

<a id="FlipY"></a>

<a id="FlipDiag"></a>

```go
const (
	FlipX    uint32 = 0x80000000
	FlipY    uint32 = 0x40000000
	FlipDiag uint32 = 0x20000000
)
```

Flip bits Tiled stores above the tile id in a global id.

## Variables

<a id="ErrUnsupported"></a>

```go
var ErrUnsupported = errors.New("tiled: unsupported")
```

ErrUnsupported reports a map feature this package does not read, such as a layer encoding Tiled has added since.

## Functions

<a id="ParseColor"></a>

### ParseColor

```go
func ParseColor(s string) (color.RGBA, bool)
```

ParseColor reads Tiled's #AARRGGBB or #RRGGBB colour text.

<a id="SplitGID"></a>

### SplitGID

```go
func SplitGID(gid uint32) (id uint32, flipX, flipY, diagonal bool)
```

SplitGID separates a global id into the tile id and its horizontal, vertical and diagonal flip bits for rectangular maps. It strips the hexagonal 120-degree rotation bit without returning it; callers drawing hexagonal maps must interpret rotation flags from the original gid.

## Types

<a id="Frame"></a>

<a id="Frame.TileID"></a>

<a id="Frame.Duration"></a>

### Frame

```go
type Frame struct {
	TileID   int
	Duration float32 // seconds
}
```

Frame is one step of a tile animation.

<a id="Images"></a>

### Images

```go
type Images func(path string) (image.Image, error)
```

Images fetches a tileset or image layer picture by the path the map names, relative to the map's directory.

<a id="ImagesFrom"></a>

#### ImagesFrom

```go
func ImagesFrom(fs *asset.FS, dir string) Images
```

ImagesFrom reads images through an asset FS, with paths joined to the map's directory.

<a id="Layer"></a>

<a id="Layer.ID"></a>

<a id="Layer.Name"></a>

<a id="Layer.Kind"></a>

<a id="Layer.Width"></a>

<a id="Layer.Height"></a>

<a id="Layer.StartX"></a>

<a id="Layer.StartY"></a>

<a id="Layer.Data"></a>

<a id="Layer.Objects"></a>

<a id="Layer.Image"></a>

<a id="Layer.Layers"></a>

<a id="Layer.Visible"></a>

<a id="Layer.Opacity"></a>

<a id="Layer.OffsetX"></a>

<a id="Layer.OffsetY"></a>

<a id="Layer.Properties"></a>

### Layer

```go
type Layer struct {
	ID            int
	Name          string
	Kind          LayerKind
	Width, Height int // tile layers, in tiles
	// StartX and StartY are the map coordinates of Data[0]; they are
	// zero except for infinite maps, whose chunks are flattened into
	// Data and may begin at negative coordinates.
	StartX, StartY int
	// Data holds one global id per cell, row-major, with Tiled's flip
	// bits still set; zero is empty. SplitGID separates the parts.
	Data       []uint32
	Objects    []Object
	Image      string // image layers, relative to the map's directory
	Layers     []Layer
	Visible    bool    // parser default true; inherited visibility is applied by Build
	Opacity    float32 // 0..1; parser default 1, multiplied through groups by Build
	OffsetX    float32 // pixels relative to the parent group
	OffsetY    float32 // pixels relative to the parent group
	Properties Properties
}
```

Layer is one layer of a map. A tile layer holds Data; an object layer holds Objects; an image layer names an Image; a group holds Layers.

<a id="Layer.CellAt"></a>

#### Layer.CellAt

```go
func (l *Layer) CellAt(x, y int) uint32
```

CellAt returns the global id at map coordinates, or zero outside the layer or on a layer without tiles.

<a id="LayerKind"></a>

### LayerKind

```go
type LayerKind int
```

LayerKind is what a layer holds.

<a id="TileLayer"></a>

<a id="ObjectLayer"></a>

<a id="ImageLayer"></a>

<a id="GroupLayer"></a>

```go
const (
	TileLayer LayerKind = iota
	ObjectLayer
	ImageLayer
	GroupLayer
)
```

<a id="Level"></a>

<a id="Level.Map"></a>

<a id="Level.Layers"></a>

<a id="Level.Sheets"></a>

### Level

```go
type Level struct {
	Map    *Map
	Layers []LevelLayer
	// Sheets index Map.Tilesets; an image-collection tileset has none.
	Sheets []*gfx.Sheet
	// contains filtered or unexported fields
}
```

Level is a map uploaded for drawing: one tilemap per tileset a layer uses, in the map's layer order.

<a id="Build"></a>

#### Build

```go
func Build(g *gfx.Graphics, m *Map, images Images) (*Level, error)
```

Build uploads a map's tileset images (nearest filtered, no mipmaps), fills tilemaps from its tile layers, and registers tile animations. Image layers and image-collection tilesets are not drawn. The Level owns the textures; Destroy frees them. Drawing uses a rectangular grid regardless of Map.Orientation; isometric and hexagonal layouts need a custom drawing path. Object layers are retained for the game to process. Infinite tile layers are flattened by Parse, but Build does not apply their StartX/StartY cell origin. Apply that origin in a custom drawing path when infinite-map chunks do not start at (0, 0).

<a id="Level.Advance"></a>

#### Level.Advance

```go
func (lv *Level) Advance(dt float64)
```

Advance moves every tile animation forward by dt seconds.

<a id="Level.Destroy"></a>

#### Level.Destroy

```go
func (lv *Level) Destroy()
```

Destroy frees the tileset textures.

<a id="Level.Draw"></a>

#### Level.Draw

```go
func (lv *Level) Draw(g *gfx.Graphics, x, y float32, tint gfx.Color)
```

Draw draws every visible tile layer in order with the map's origin at (x, y). Layer opacity scales the tint's alpha.

<a id="Level.Layer"></a>

#### Level.Layer

```go
func (lv *Level) Layer(name string) *LevelLayer
```

Layer returns the first level layer with the name, or nil.

<a id="Level.Size"></a>

#### Level.Size

```go
func (lv *Level) Size() lin.Vec2
```

Size is the map's pixel size.

<a id="LevelLayer"></a>

<a id="LevelLayer.Name"></a>

<a id="LevelLayer.Kind"></a>

<a id="LevelLayer.Maps"></a>

<a id="LevelLayer.Objects"></a>

<a id="LevelLayer.Visible"></a>

<a id="LevelLayer.Opacity"></a>

<a id="LevelLayer.Offset"></a>

### LevelLayer

```go
type LevelLayer struct {
	Name string
	Kind LayerKind
	// Maps hold the layer's cells split by tileset, in first-use order
	// in the layer's cell data; a cell belonging to another
	// tileset is -1 in each.
	Maps    []*gfx.Tilemap
	Objects []Object
	Visible bool
	Opacity float32
	Offset  lin.Vec2
}
```

LevelLayer is one tile or object layer with the group state above it applied: a layer inside a hidden group is hidden, offsets add, and opacities multiply.

<a id="Map"></a>

<a id="Map.Width"></a>

<a id="Map.Height"></a>

<a id="Map.TileWidth"></a>

<a id="Map.TileHeight"></a>

<a id="Map.Orientation"></a>

<a id="Map.StaggerAxis"></a>

<a id="Map.StaggerIndex"></a>

<a id="Map.HexSideLength"></a>

<a id="Map.BackgroundColor"></a>

<a id="Map.Infinite"></a>

<a id="Map.Layers"></a>

<a id="Map.Tilesets"></a>

<a id="Map.Properties"></a>

### Map

```go
type Map struct {
	Width, Height         int // in tiles; the chunk bounds for infinite maps
	TileWidth, TileHeight int // in pixels
	// Orientation is "orthogonal", "isometric", "staggered" or
	// "hexagonal".
	Orientation string
	// StaggerAxis is "x" or "y" on a hexagonal or staggered map: which
	// axis the shifted rows or columns run along. It is empty otherwise.
	StaggerAxis string
	// StaggerIndex is "odd" or "even" on a hexagonal or staggered map:
	// which rows or columns are shifted. It is empty otherwise.
	StaggerIndex string
	// HexSideLength is the length in pixels of the hexagon side that lies
	// along the stagger axis. It is zero except on hexagonal maps.
	HexSideLength   int
	BackgroundColor color.RGBA // zero when the map has none
	Infinite        bool
	Layers          []Layer
	Tilesets        []Tileset // sorted by FirstGID
	Properties      Properties
}
```

Map is one Tiled map: its grid, layers in draw order, and tilesets.

<a id="Load"></a>

#### Load

```go
func Load(name string) (*Map, error)
```

Load reads a map in either form (.tmj or .json, .tmx), resolving external tilesets next to it.

<a id="LoadFS"></a>

#### LoadFS

```go
func LoadFS(fs *asset.FS, name string) (*Map, error)
```

LoadFS reads a map through an asset FS, resolving external tilesets relative to the map's directory.

<a id="Parse"></a>

#### Parse

```go
func Parse(data []byte, resolve Resolver) (*Map, error)
```

Parse decodes a map from memory, JSON or XML by its first byte. resolve may be nil when every tileset is embedded; an external tileset may be in either form whatever the map's. Paths in the result (tileset images, image layers) are relative to the map's directory, as the resolver's are.

<a id="Map.FindLayer"></a>

#### Map.FindLayer

```go
func (m *Map) FindLayer(name string) *Layer
```

FindLayer returns the first layer with the name at any depth, or nil.

<a id="Map.Layout"></a>

#### Map.Layout

```go
func (m *Map) Layout() autotile.Layout
```

Layout returns the autotile layout that matches the map's shape, for the Mapper that walks its cells and for WangSet.RulesFor. A hexagonal map gives the rows or columns layout its stagger axis and stagger index name. Every other orientation gives autotile.Square, isometric maps included: Tiled's terrain tool matches an isometric map on the plain grid neighbours, so a set painted there lines up with Square. A game whose isometric tiles are drawn by their direction on screen sets autotile.IsoDiamond on the Mapper itself.

<a id="Map.ObjectLayers"></a>

#### Map.ObjectLayers

```go
func (m *Map) ObjectLayers() []*Layer
```

ObjectLayers returns every object layer in order, descending into groups.

<a id="Map.TileLayers"></a>

#### Map.TileLayers

```go
func (m *Map) TileLayers() []*Layer
```

TileLayers returns every tile layer in draw order, descending into groups.

<a id="Map.TileProperties"></a>

#### Map.TileProperties

```go
func (m *Map) TileProperties(gid uint32) Properties
```

TileProperties returns the custom properties of the tile behind a global id, or nil when the tile has none.

<a id="Map.Tileset"></a>

#### Map.Tileset

```go
func (m *Map) Tileset(gid uint32) (*Tileset, int)
```

Tileset finds the tileset a global id belongs to and the tile's local id within it. An empty cell (zero) or an id past every tileset gives nil and -1.

<a id="Map.WangSet"></a>

#### Map.WangSet

```go
func (m *Map) WangSet(name string) (*Tileset, *WangSet)
```

WangSet finds a terrain set by name across the map's tilesets, or nil. The frames its Rules produce are local tile ids within the returned tileset.

<a id="Object"></a>

<a id="Object.ID"></a>

<a id="Object.Name"></a>

<a id="Object.Class"></a>

<a id="Object.X"></a>

<a id="Object.Y"></a>

<a id="Object.Width"></a>

<a id="Object.Height"></a>

<a id="Object.Rotation"></a>

<a id="Object.GID"></a>

<a id="Object.Visible"></a>

<a id="Object.Point"></a>

<a id="Object.Ellipse"></a>

<a id="Object.Polygon"></a>

<a id="Object.Polyline"></a>

<a id="Object.Text"></a>

<a id="Object.Properties"></a>

### Object

```go
type Object struct {
	ID       int
	Name     string
	Class    string
	X, Y     float32
	Width    float32
	Height   float32
	Rotation float32 // degrees, clockwise
	GID      uint32  // tile objects, with flip bits
	Visible  bool
	Point    bool
	Ellipse  bool
	Polygon  []lin.Vec2 // closed, relative to X and Y
	Polyline []lin.Vec2 // open, relative to X and Y
	Text     string
	// Properties are the object's custom properties.
	Properties Properties
}
```

Object is a shape placed on an object layer or a tile's collision group. X and Y are pixels; a tile object (GID set) is anchored at its bottom-left, everything else at its top-left.

<a id="Object.Rect"></a>

#### Object.Rect

```go
func (o Object) Rect() lin.Rect
```

Rect returns the stored X, Y, Width and Height as a rectangle. It does not apply rotation, polygon bounds, group offsets or the bottom-left anchor adjustment for a tile object.

<a id="Properties"></a>

### Properties

```go
type Properties map[string]any
```

Properties are custom properties by name. Values are bool, int, float64, string, or Properties for class values; colours and files are strings.

<a id="Properties.Bool"></a>

#### Properties.Bool

```go
func (p Properties) Bool(name string) bool
```

Bool returns a bool property, or false.

<a id="Properties.Class"></a>

#### Properties.Class

```go
func (p Properties) Class(name string) Properties
```

Class returns a nested class property, or nil.

<a id="Properties.Color"></a>

#### Properties.Color

```go
func (p Properties) Color(name string) color.RGBA
```

Color returns a colour property, or zero.

<a id="Properties.Float"></a>

#### Properties.Float

```go
func (p Properties) Float(name string) float64
```

Float returns a float property, or zero. Int values are converted.

<a id="Properties.Has"></a>

#### Properties.Has

```go
func (p Properties) Has(name string) bool
```

Has reports whether a property is set.

<a id="Properties.Int"></a>

#### Properties.Int

```go
func (p Properties) Int(name string) int
```

Int returns an int property, or zero. Float values are truncated.

<a id="Properties.String"></a>

#### Properties.String

```go
func (p Properties) String(name string) string
```

String returns a string property, or "".

<a id="Resolver"></a>

### Resolver

```go
type Resolver func(path string) ([]byte, error)
```

Resolver fetches the bytes behind a path an external tileset names, relative to the map's directory.

<a id="Tile"></a>

<a id="Tile.ID"></a>

<a id="Tile.Animation"></a>

<a id="Tile.Properties"></a>

<a id="Tile.Collision"></a>

<a id="Tile.Image"></a>

<a id="Tile.ImageWidth"></a>

<a id="Tile.ImageHeight"></a>

### Tile

```go
type Tile struct {
	ID          int
	Animation   []Frame
	Properties  Properties
	Collision   []Object // from the tile's object group
	Image       string   // image-collection tilesets
	ImageWidth  int
	ImageHeight int
}
```

Tile is the extra data a tileset attaches to one of its tiles.

<a id="Tileset"></a>

<a id="Tileset.FirstGID"></a>

<a id="Tileset.Name"></a>

<a id="Tileset.Image"></a>

<a id="Tileset.ImageWidth"></a>

<a id="Tileset.ImageHeight"></a>

<a id="Tileset.TileWidth"></a>

<a id="Tileset.TileHeight"></a>

<a id="Tileset.Columns"></a>

<a id="Tileset.TileCount"></a>

<a id="Tileset.Margin"></a>

<a id="Tileset.Spacing"></a>

<a id="Tileset.Tiles"></a>

<a id="Tileset.WangSets"></a>

<a id="Tileset.Properties"></a>

### Tileset

```go
type Tileset struct {
	FirstGID              uint32
	Name                  string
	Image                 string // relative to the map's directory
	ImageWidth            int
	ImageHeight           int
	TileWidth, TileHeight int
	Columns               int
	TileCount             int
	Margin, Spacing       int
	Tiles                 map[int]Tile // by local id; only tiles with extra data
	WangSets              []WangSet    // terrain sets from the Tiled terrain tool
	Properties            Properties
}
```

Tileset is a grid of tiles cut from one image, or a collection of tile images when Image is empty.

<a id="ParseTileset"></a>

#### ParseTileset

```go
func ParseTileset(data []byte) (*Tileset, error)
```

ParseTileset decodes a standalone tileset (.tsj or .json, .tsx) from memory. FirstGID is zero; paths stay relative to the tileset's own directory.

<a id="WangColor"></a>

<a id="WangColor.Name"></a>

<a id="WangColor.Color"></a>

<a id="WangColor.Tile"></a>

<a id="WangColor.Probability"></a>

### WangColor

```go
type WangColor struct {
	Name        string
	Color       color.RGBA
	Tile        int     // a representative tile id, or -1
	Probability float64 // relative chance among variants; zero counts as 1
}
```

WangColor is one terrain colour of a set. Colours are numbered from 1 in WangSetTile.WangID, in the order they appear here.

<a id="WangSet"></a>

<a id="WangSet.Name"></a>

<a id="WangSet.Type"></a>

<a id="WangSet.Colors"></a>

<a id="WangSet.Tiles"></a>

### WangSet

```go
type WangSet struct {
	Name string
	// Type is "corner", "edge" or "mixed", saying which positions the
	// set paints.
	Type   string
	Colors []WangColor
	Tiles  []WangSetTile
}
```

WangSet is one terrain set of a tileset, as drawn in the Tiled editor's terrain tool: named colours and, for each participating tile, the colour at each of its eight positions.

<a id="WangSet.Rules"></a>

#### WangSet.Rules

```go
func (ws *WangSet) Rules() *autotile.Rules
```

Rules converts the set to autotile rules for a square grid, with tile ids as frames: a tileset cut with gfx.NewSheet uses them directly. A "corner" set matches corners, an "edge" set edges, anything else all eight positions. A tile's weight is the product of its colours' probabilities, so variants keep the balance set in the editor. It is RulesFor(autotile.Square); a hexagonal map wants RulesFor(m.Layout()).

<a id="WangSet.RulesFor"></a>

#### WangSet.RulesFor

```go
func (ws *WangSet) RulesFor(layout autotile.Layout) *autotile.Rules
```

RulesFor converts the set to autotile rules for a layout, which the map supplies through Map.Layout. On a hexagonal layout it moves each colour into the direction slot the layout uses: Tiled stores a hexagon's six sides in the eight-slot wangid one place back, so the slot the editor calls the top holds the north-east side of a rows hexagon. Give the same layout to the Mapper that applies the rules.

<a id="WangSetTile"></a>

<a id="WangSetTile.TileID"></a>

<a id="WangSetTile.WangID"></a>

### WangSetTile

```go
type WangSetTile struct {
	TileID int
	WangID [8]int
}
```

WangSetTile gives one tile's colours, clockwise from north: N, NE, E, SE, S, SW, W, NW. Zero means the position has no colour.
