157 lines
3.6 KiB
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
|
|
}
|