package main import ( "image/color" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/vector" ) // Rendering constants. All coordinate math goes through TilePx; // no code should reason about window pixels directly. const ( TilePx = 16 VirtualW = 640 VirtualH = 360 ) // roleColor maps a RoomRole to its tint. The mapping lives here so // that ship data stays free of any rendering concerns. func roleColor(role RoomRole) color.RGBA { switch role { case RolePilot: return color.RGBA{90, 130, 180, 255} // steel blue case RoleWeapons: return color.RGBA{170, 80, 70, 255} // dusty red case RoleShields: return color.RGBA{80, 140, 120, 255} // teal green case RoleMedBay: return color.RGBA{190, 160, 90, 255} // warm ochre case RoleEngines: return color.RGBA{140, 95, 160, 255} // muted violet default: return color.RGBA{120, 120, 120, 255} } } // drawShip draws every room of the ship. Rendering delegates to // drawRoom so per-room logic lives in one place. func drawShip(screen *ebiten.Image, s Ship) { for _, r := range s.Rooms { drawRoom(screen, r) } } // drawRoom draws a single room: a role-tinted fill, a 1-px border, // and the role name printed inside. func drawRoom(screen *ebiten.Image, r Room) { x := float32(r.GridX * TilePx) y := float32(r.GridY * TilePx) w := float32(r.GridW * TilePx) h := float32(r.GridH * TilePx) fill := roleColor(r.Role) vector.DrawFilledRect(screen, x, y, w, h, fill, false) border := color.RGBA{230, 230, 230, 255} // Four 1-px edges. vector.DrawFilledRect(screen, x, y, w, 1, border, false) vector.DrawFilledRect(screen, x, y+h-1, w, 1, border, false) vector.DrawFilledRect(screen, x, y, 1, h, border, false) vector.DrawFilledRect(screen, x+w-1, y, 1, h, border, false) // Label: a few pixels inside the top-left corner. ebitenutil.DebugPrintAt(screen, r.Name, int(x)+3, int(y)+2) }