doctorlectro/level/level.go

157 lines
3.6 KiB
Go

package level
import (
"image"
"log"
"path/filepath"
"code.rocketnine.space/tslocum/doctorlectro/asset"
"code.rocketnine.space/tslocum/doctorlectro/component"
"code.rocketnine.space/tslocum/doctorlectro/world"
"code.rocketnine.space/tslocum/gohan"
"github.com/hajimehoshi/ebiten/v2"
"github.com/lafriks/go-tiled"
)
// TODO load player spawn coordinates from map
func LoadMap() {
filePath := "map/map.tmx"
// Parse .tmx file.
m, err := tiled.LoadFile(filePath, tiled.WithFileSystem(asset.FS))
if err != nil {
log.Fatalf("error parsing world: %+v", err)
}
// Load tileset.
tileset := m.Tilesets[0]
imgPath := filepath.Join("image/robot-tileset", tileset.Image.Source)
f, err := asset.FS.Open(filepath.FromSlash(imgPath))
if err != nil {
panic(err)
}
defer f.Close()
img, _, err := image.Decode(f)
if err != nil {
panic(err)
}
tilesetImg := ebiten.NewImageFromImage(img)
// Load tiles.
for i := uint32(0); i < uint32(tileset.TileCount); i++ {
rect := tileset.GetTileRect(i)
world.TileImages[i+tileset.FirstGID] = tilesetImg.SubImage(rect).(*ebiten.Image)
}
createTileEntity := func(t *tiled.LayerTile, x int, y int) gohan.Entity {
tileX, tileY := TileToGameCoords(x, y)
mapTile := gohan.NewEntity()
mapTile.AddComponent(&component.Position{
X: tileX,
Y: tileY,
})
sprite := &component.Sprite{
Image: world.TileImages[t.Tileset.FirstGID+t.ID],
HorizontalFlip: t.HorizontalFlip,
VerticalFlip: t.VerticalFlip,
DiagonalFlip: t.DiagonalFlip,
}
mapTile.AddComponent(sprite)
return mapTile
}
metalTiles := make([][]bool, m.Height)
for y := range metalTiles {
metalTiles[y] = make([]bool, m.Width)
}
var t *tiled.LayerTile
for _, layer := range m.Layers {
for y := 0; y < m.Height; y++ {
for x := 0; x < m.Width; x++ {
t = layer.Tiles[y*m.Width+x]
if t == nil || t.Nil {
continue // No tile at this position.
}
tileImg := world.TileImages[t.Tileset.FirstGID+t.ID]
if tileImg == nil {
continue
}
createTileEntity(t, x, y)
//TODO if metal tile
metalTiles[y][x] = true
}
}
}
// Load ObjectGroups.
var objects []*tiled.ObjectGroup
var loadObjects func(grp *tiled.Group)
loadObjects = func(grp *tiled.Group) {
for _, subGrp := range grp.Groups {
loadObjects(subGrp)
}
for _, objGrp := range grp.ObjectGroups {
objects = append(objects, objGrp)
}
}
for _, grp := range m.Groups {
loadObjects(grp)
}
for _, objGrp := range m.ObjectGroups {
objects = append(objects, objGrp)
}
world.Map = m
world.ObjectGroups = objects
for _, grp := range world.ObjectGroups {
if grp.Name == "TRIGGERS" {
for _, obj := range grp.Objects {
if obj.Name == "PLAYERSPAWN" {
world.SpawnX, world.SpawnY = obj.X, obj.Y
}
}
} else if grp.Name == "HAZARDS" {
/*for _, obj := range grp.Objects {
r := ObjectToRect(obj)
r.Min.Y += 32
r.Max.Y += 32
World.HazardRects = append(World.HazardRects, r)
}*/
}
}
// Add metal collision rects.
for y := range metalTiles {
for x, filled := range metalTiles[y] {
if filled {
r := image.Rect(x*world.TileSize, y*world.TileSize, (x+1)*world.TileSize-1, (y+1)*world.TileSize-1)
world.MetalRects = append(world.MetalRects, r)
}
}
}
}
func ObjectToRect(o *tiled.Object) image.Rectangle {
x, y, w, h := int(o.X), int(o.Y), int(o.Width), int(o.Height)
y -= 16
return image.Rect(x, y, x+w, y+h)
}
func TileToGameCoords(x, y int) (float64, float64) {
//return float64(x) * 32, float64(g.currentMap.Height*32) - float64(y)*32 - 32
return float64(x) * 16, float64(y) * 16
}