Bunyip a game engine in Go GitHub

Package github.com/matjam/bunyip/tiled

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.

Index

Constants

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

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

Variables

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

ParseColor source

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

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

SplitGID source

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

type Frame source

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

Frame is one step of a tile animation.

type Images source

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.

ImagesFrom source

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

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

type Layer source

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.

CellAt source

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.

type LayerKind source

type LayerKind int

LayerKind is what a layer holds.

const (
	TileLayer LayerKind = iota
	ObjectLayer
	ImageLayer
	GroupLayer
)

type Level source

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.

Build source

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).

Advance source

func (lv *Level) Advance(dt float64)

Advance moves every tile animation forward by dt seconds.

Destroy source

func (lv *Level) Destroy()

Destroy frees the tileset textures.

Draw source

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.

Layer source

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

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

Size source

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

Size is the map's pixel size.

type LevelLayer source

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.

type Map source

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.

Load source

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

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

LoadFS source

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.

Parse source

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.

FindLayer source

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

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

Layout source

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.

ObjectLayers source

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

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

TileLayers source

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

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

TileProperties source

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.

Tileset source

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.

WangSet source

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.

type Object source

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.

Rect source

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.

type Properties source

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.

Bool source

func (p Properties) Bool(name string) bool

Bool returns a bool property, or false.

Class source

func (p Properties) Class(name string) Properties

Class returns a nested class property, or nil.

Color source

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

Color returns a colour property, or zero.

Float source

func (p Properties) Float(name string) float64

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

Has source

func (p Properties) Has(name string) bool

Has reports whether a property is set.

Int source

func (p Properties) Int(name string) int

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

String source

func (p Properties) String(name string) string

String returns a string property, or "".

type Resolver source

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

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

type Tile source

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.

type Tileset source

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.

ParseTileset source

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.

type WangColor source

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.

type WangSet source

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.

Rules source

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()).

RulesFor source

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.

type WangSetTile source

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.

Source files

bench_test.go fuzz_test.go level.go parse.go review_test.go tiled.go tiled_test.go wang.go xml.go xml_test.go zstd_test.go