// Genererar placeholder-grafik tills riktig pixel art finns: // // go run ./tools/genart // // Skriver resources/sprites/tiles.png (en remsa 16×16-rutor i ordningen // vägg, golv, start, perrong, spärr, automat, skylt) och // resources/sprites/player.png (3 bildrutor × 4 riktningar: ner, upp, // vänster, höger; kolumn 0 = stilla, 1–2 = gå). Ritas med enkla rektanglar // så att allt är deterministiskt och lätt att justera. package main import ( "fmt" "image" "image/color" "image/png" "os" "path/filepath" ) const T = 16 func rgb(r, g, b uint8) color.RGBA { return color.RGBA{r, g, b, 255} } var ( wallDark, wallMid, wallLight = rgb(38, 43, 68), rgb(58, 68, 102), rgb(90, 105, 136) floorA, floorB, grout = rgb(139, 155, 180), rgb(128, 143, 168), rgb(108, 121, 146) yellow, yellowDark = rgb(254, 174, 52), rgb(200, 130, 30) metal, metalDark = rgb(190, 198, 208), rgb(120, 130, 145) screenC, boxDark = rgb(44, 232, 245), rgb(50, 60, 80) signBoard, white = rgb(24, 60, 120), rgb(255, 255, 255) green, greenDark = rgb(99, 199, 77), rgb(60, 140, 50) skin, hair, capC, capDark = rgb(240, 200, 160), rgb(60, 40, 30), rgb(228, 59, 68), rgb(170, 40, 50) jacket, jacketDark = rgb(44, 232, 245), rgb(30, 170, 185) pants, shoe, eye = rgb(38, 43, 68), rgb(255, 255, 255), rgb(38, 43, 68) ) type canvas struct { img *image.NRGBA ox, oy int } func (c canvas) rect(x, y, w, h int, col color.RGBA) { for yy := y; yy < y+h; yy++ { for xx := x; xx < x+w; xx++ { c.img.SetNRGBA(c.ox+xx, c.oy+yy, color.NRGBA{col.R, col.G, col.B, col.A}) } } } func floor(c canvas) { c.rect(0, 0, 7, 7, floorA) c.rect(8, 0, 7, 7, floorB) c.rect(0, 8, 7, 7, floorB) c.rect(8, 8, 7, 7, floorA) c.rect(7, 0, 1, 16, grout) c.rect(15, 0, 1, 16, grout) c.rect(0, 7, 16, 1, grout) c.rect(0, 15, 16, 1, grout) } var tiles = []func(canvas){ func(c canvas) { // vägg c.rect(0, 0, 16, 16, wallMid) c.rect(0, 0, 16, 2, wallLight) c.rect(0, 14, 16, 2, wallDark) c.rect(0, 7, 16, 1, wallDark) c.rect(7, 2, 1, 5, wallDark) c.rect(3, 8, 1, 6, wallDark) c.rect(11, 8, 1, 6, wallDark) }, floor, // golv func(c canvas) { // start: golv + dörrmatta floor(c) c.rect(3, 10, 10, 4, green) c.rect(3, 10, 10, 1, greenDark) c.rect(3, 13, 10, 1, greenDark) }, func(c canvas) { // perrong: golv + gul ledlinje + kant floor(c) c.rect(0, 11, 16, 3, yellow) for x := 1; x < 16; x += 4 { c.rect(x, 12, 2, 1, yellowDark) } c.rect(0, 15, 16, 1, wallDark) }, func(c canvas) { // spärr: två stolpar med grön lampa floor(c) for _, x := range []int{1, 11} { c.rect(x, 1, 4, 13, metal) c.rect(x, 1, 4, 1, white) c.rect(x, 13, 4, 1, metalDark) c.rect(x+1, 3, 2, 2, green) } }, func(c canvas) { // automat floor(c) c.rect(3, 1, 10, 13, boxDark) c.rect(4, 2, 8, 5, screenC) c.rect(5, 9, 6, 1, metal) c.rect(5, 11, 2, 1, yellow) c.rect(8, 11, 2, 1, green) }, func(c canvas) { // skylt floor(c) c.rect(7, 7, 2, 9, boxDark) c.rect(2, 1, 12, 7, signBoard) c.rect(2, 1, 12, 1, white) c.rect(3, 3, 10, 1, white) c.rect(3, 5, 6, 1, white) }, } // player ritar en figur som tittar åt facing (0 ner, 1 upp, 2 vänster, 3 höger) // i bildruta frame (0 stilla, 1–2 gå). func player(c canvas, facing, frame int) { // ben + skor ly, ry := 11, 11 lx, rx := 5, 9 switch frame { case 1: ly = 10 case 2: ry = 10 } if facing >= 2 { // sidovy: benen närmare varandra, växelvis fram lx, rx = 6, 8 if frame == 1 { lx, rx = 5, 8 } else if frame == 2 { lx, rx = 6, 9 } } c.rect(lx, ly, 2, 14-ly, pants) c.rect(rx, ry, 2, 14-ry, pants) c.rect(lx, 14, 2, 1, shoe) c.rect(rx, 14, 2, 1, shoe) // kropp + armar c.rect(4, 6, 8, 5, jacket) c.rect(4, 6, 8, 1, jacketDark) c.rect(3, 7, 1, 3, jacket) c.rect(12, 7, 1, 3, jacket) // huvud switch facing { case 0: // ner c.rect(4, 1, 8, 5, skin) c.rect(3, 0, 10, 2, capC) c.rect(3, 2, 10, 1, capDark) c.rect(6, 4, 1, 1, eye) c.rect(9, 4, 1, 1, eye) case 1: // upp: bakhuvud c.rect(4, 1, 8, 5, hair) c.rect(3, 0, 10, 2, capC) c.rect(3, 2, 10, 1, capDark) case 2: // vänster c.rect(4, 1, 8, 5, skin) c.rect(9, 1, 3, 5, hair) c.rect(3, 0, 10, 2, capC) c.rect(1, 2, 8, 1, capDark) c.rect(5, 4, 1, 1, eye) case 3: // höger c.rect(4, 1, 8, 5, skin) c.rect(4, 1, 3, 5, hair) c.rect(3, 0, 10, 2, capC) c.rect(7, 2, 8, 1, capDark) c.rect(10, 4, 1, 1, eye) } } func main() { out := filepath.Join(repoRoot(), "resources", "sprites") tilesImg := image.NewNRGBA(image.Rect(0, 0, T*len(tiles), T)) for i, draw := range tiles { draw(canvas{tilesImg, i * T, 0}) } save(filepath.Join(out, "tiles.png"), tilesImg) playerImg := image.NewNRGBA(image.Rect(0, 0, T*3, T*4)) for facing := 0; facing < 4; facing++ { for frame := 0; frame < 3; frame++ { player(canvas{playerImg, frame * T, facing * T}, facing, frame) } } save(filepath.Join(out, "player.png"), playerImg) } func save(path string, img image.Image) { f, err := os.Create(path) if err != nil { fail(err) } defer f.Close() if err := png.Encode(f, img); err != nil { fail(err) } fmt.Println("skrev", path) } func repoRoot() string { dir, _ := os.Getwd() for { if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil { return dir } parent := filepath.Dir(dir) if parent == dir { fail(fmt.Errorf("hittade ingen go.mod")) } dir = parent } } func fail(err error) { fmt.Fprintln(os.Stderr, "genart:", err) os.Exit(1) }