package sprite import ( "fmt" "image/color" ) // Sheet lays out several equally sized sprites in a row-major grid: // index 0 is top-left, then left-to-right, then next row. A 1D strip is // simply a sheet with one row (or one column). type Sheet struct { Sprites []*Sprite Cols, Rows int CellW, CellH int } // NewSheet composes sprites into a sheet with the given number of columns. // cols <= 0 puts everything in a single row. Every sprite must have the // same dimensions so the sheet can be indexed cell by cell. func NewSheet(sprites []*Sprite, cols int) (*Sheet, error) { if len(sprites) == 0 { return nil, fmt.Errorf("a sheet needs at least one sprite") } w, h := sprites[0].Bounds() for _, sp := range sprites[1:] { sw, sh := sp.Bounds() if sw != w || sh != h { return nil, fmt.Errorf("sprite %q is %dx%d but %q is %dx%d — all sprites in a sheet must be the same size", sp.Name, sw, sh, sprites[0].Name, w, h) } } if cols <= 0 || cols > len(sprites) { cols = len(sprites) } rows := (len(sprites) + cols - 1) / cols return &Sheet{Sprites: sprites, Cols: cols, Rows: rows, CellW: w, CellH: h}, nil } // Bounds returns the total sheet size in pixels. func (sh *Sheet) Bounds() (w, h int) { return sh.Cols * sh.CellW, sh.Rows * sh.CellH } // At returns the pixel at (x, y). Cells past the last sprite (when the // sprite count doesn't fill the grid) are transparent. func (sh *Sheet) At(x, y int) color.NRGBA { col, row := x/sh.CellW, y/sh.CellH idx := row*sh.Cols + col if idx >= len(sh.Sprites) { return Transparent } return sh.Sprites[idx].At(x%sh.CellW, y%sh.CellH) } // FileBase appends the layout to an output name so the file itself // documents cell size and orientation: _x_x // e.g. walk_16x16_4x2 = 16x16 cells, 4 columns, 2 rows, read row by row. func (sh *Sheet) FileBase(base string) string { return fmt.Sprintf("%s_%dx%d_%dx%d", base, sh.CellW, sh.CellH, sh.Cols, sh.Rows) }