Implementerat Tiled JSON Map parser med portaler mellan 2 st hundramappars rum
This commit is contained in:
@@ -1,6 +1,156 @@
|
||||
package entities
|
||||
|
||||
import "github.com/go-gl/mathgl/mgl64"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
)
|
||||
|
||||
const (
|
||||
TileSize = 32.0 // Varje block ar 32x32 world units
|
||||
)
|
||||
|
||||
type World struct {
|
||||
Width, Height, Depth int
|
||||
Grid [][][]Entity
|
||||
PortalTrigger string // Håller reda på om vi ska byta rum
|
||||
}
|
||||
|
||||
func NewWorld(w, h, d int) *World {
|
||||
grid := make([][][]Entity, w)
|
||||
for x := 0; x < w; x++ {
|
||||
grid[x] = make([][]Entity, h)
|
||||
for y := 0; y < h; y++ {
|
||||
grid[x][y] = make([]Entity, d)
|
||||
}
|
||||
}
|
||||
return &World{Width: w, Height: h, Depth: d, Grid: grid, PortalTrigger: ""}
|
||||
}
|
||||
|
||||
func (w *World) GetEntityAt(x, y, z int) Entity {
|
||||
if x < 0 || x >= w.Width || y < 0 || y >= w.Height || z < 0 || z >= w.Depth {
|
||||
return nil
|
||||
}
|
||||
return w.Grid[x][y][z]
|
||||
}
|
||||
|
||||
func (w *World) SetEntityAt(x, y, z int, e Entity) {
|
||||
if x < 0 || x >= w.Width || y < 0 || y >= w.Height || z < 0 || z >= w.Depth {
|
||||
return
|
||||
}
|
||||
w.Grid[x][y][z] = e
|
||||
if e != nil {
|
||||
e.SetPos(mgl64.Vec3{float64(x), float64(y), float64(z)})
|
||||
}
|
||||
}
|
||||
|
||||
// Convert absolute 3D position to Grid index
|
||||
func ToGridIndex(pos mgl64.Vec3) (int, int, int) {
|
||||
return int(pos[0]/TileSize), int(pos[1]/TileSize), int(pos[2]/TileSize)
|
||||
}
|
||||
|
||||
type TiledLayer struct {
|
||||
Data []int `json:"data"`
|
||||
Height int `json:"height"`
|
||||
Name string `json:"name"`
|
||||
Width int `json:"width"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type TiledMap struct {
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
Layers []TiledLayer `json:"layers"`
|
||||
}
|
||||
|
||||
type Portal struct {
|
||||
pos mgl64.Vec3
|
||||
TargetMap string
|
||||
}
|
||||
func (p *Portal) Pos() mgl64.Vec3 { return p.pos }
|
||||
func (p *Portal) SetPos(pos mgl64.Vec3) { p.pos = pos }
|
||||
func (p *Portal) IsBlocking() bool { return false }
|
||||
func (p *Portal) IsMovable() bool { return false }
|
||||
func (p *Portal) Move(dx, dy, dz float64) {}
|
||||
func (p *Portal) Damage(amount int) {}
|
||||
func (p *Portal) Pickup() bool { return false }
|
||||
func (p *Portal) GetHealth() int { return 100 }
|
||||
func (p *Portal) DrawSide(screen interface{}, x, y float64) {}
|
||||
func (p *Portal) DrawTop(screen interface{}, x, y float64) {}
|
||||
|
||||
// Ladda en värld från Tiled Export (.tmj)
|
||||
func LoadWorldFromTiled(tmjPath string) (*World, error) {
|
||||
fileData, err := os.ReadFile(tmjPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("kunde inte lasa map %s: %v", tmjPath, err)
|
||||
}
|
||||
|
||||
var tMap TiledMap
|
||||
if err := json.Unmarshal(fileData, &tMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := NewWorld(tMap.Width, 10, tMap.Height) // 10 i djup(height y), tileHeight z = height i Json
|
||||
|
||||
tile12, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_12.png")
|
||||
tile02, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_02.png")
|
||||
tile31, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_31.png")
|
||||
|
||||
for _, layer := range tMap.Layers {
|
||||
if layer.Type != "tilelayer" {
|
||||
continue
|
||||
}
|
||||
|
||||
var yLevel int
|
||||
fmt.Sscanf(layer.Name, "Y%d", &yLevel)
|
||||
if yLevel < 0 || yLevel >= 10 {
|
||||
continue
|
||||
}
|
||||
|
||||
for i, tileID := range layer.Data {
|
||||
if tileID == 0 {
|
||||
continue
|
||||
}
|
||||
x := i % layer.Width
|
||||
z := i / layer.Width
|
||||
|
||||
var ent Entity
|
||||
|
||||
if tileID == 3 { // Portal ID
|
||||
target := "room2"
|
||||
if tmjPath == "mapp-maker/room2.tmj" {
|
||||
target = "room1"
|
||||
}
|
||||
ent = &Portal{ TargetMap: target }
|
||||
} else {
|
||||
// Mark
|
||||
if yLevel < 9 {
|
||||
ent = &Tile{ SideImg: tile12, TopImg: tile12 }
|
||||
} else {
|
||||
ent = &Tile{ SideImg: tile02, TopImg: tile31 }
|
||||
}
|
||||
}
|
||||
|
||||
w.SetEntityAt(x, yLevel, z, ent)
|
||||
}
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}package entities
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
)
|
||||
|
||||
const (
|
||||
TileSize = 32.0 // Varje block ar 32x32 world units
|
||||
@@ -9,6 +159,7 @@ TileSize = 32.0 // Varje block ar 32x32 world units
|
||||
type World struct {
|
||||
Width, Height, Depth int
|
||||
Grid [][][]Entity
|
||||
PortalTrigger string // Håller reda på om vi ska byta rum
|
||||
}
|
||||
|
||||
func NewWorld(w, h, d int) *World {
|
||||
@@ -19,7 +170,7 @@ for y := 0; y < h; y++ {
|
||||
grid[x][y] = make([]Entity, d)
|
||||
}
|
||||
}
|
||||
return &World{Width: w, Height: h, Depth: d, Grid: grid}
|
||||
return &World{Width: w, Height: h, Depth: d, Grid: grid, PortalTrigger: ""}
|
||||
}
|
||||
|
||||
func (w *World) GetEntityAt(x, y, z int) Entity {
|
||||
@@ -43,3 +194,93 @@ e.SetPos(mgl64.Vec3{float64(x), float64(y), float64(z)})
|
||||
func ToGridIndex(pos mgl64.Vec3) (int, int, int) {
|
||||
return int(pos[0]), int(pos[1]), int(pos[2])
|
||||
}
|
||||
|
||||
type TiledLayer struct {
|
||||
Data []int `json:"data"`
|
||||
Height int `json:"height"`
|
||||
Name string `json:"name"`
|
||||
Width int `json:"width"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type TiledMap struct {
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
Layers []TiledLayer `json:"layers"`
|
||||
}
|
||||
|
||||
type Portal struct {
|
||||
pos mgl64.Vec3
|
||||
TargetMap string
|
||||
}
|
||||
func (p *Portal) Pos() mgl64.Vec3 { return p.pos }
|
||||
func (p *Portal) SetPos(pos mgl64.Vec3) { p.pos = pos }
|
||||
func (p *Portal) IsBlocking() bool { return false }
|
||||
func (p *Portal) IsMovable() bool { return false }
|
||||
func (p *Portal) Move(dx, dy, dz float64) {}
|
||||
func (p *Portal) Damage(amount int) {}
|
||||
func (p *Portal) Pickup() bool { return false }
|
||||
func (p *Portal) GetHealth() int { return 100 }
|
||||
func (p *Portal) DrawSide(screen interface{}, x, y float64) {}
|
||||
func (p *Portal) DrawTop(screen interface{}, x, y float64) {}
|
||||
|
||||
// Ladda en värld från Tiled Export (.tmj)
|
||||
func LoadWorldFromTiled(tmjPath string) (*World, error) {
|
||||
fileData, err := os.ReadFile(tmjPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("kunde inte lasa map %s: %v", tmjPath, err)
|
||||
}
|
||||
|
||||
var tMap TiledMap
|
||||
if err := json.Unmarshal(fileData, &tMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w := NewWorld(tMap.Width, 10, tMap.Height) // 10 i djup(height y), tileHeight z = height i Json
|
||||
|
||||
tile12, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_12.png")
|
||||
tile02, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_02.png")
|
||||
tile31, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_31.png")
|
||||
|
||||
for _, layer := range tMap.Layers {
|
||||
if layer.Type != "tilelayer" {
|
||||
continue
|
||||
}
|
||||
|
||||
var yLevel int
|
||||
fmt.Sscanf(layer.Name, "Y%d", &yLevel)
|
||||
if yLevel < 0 || yLevel >= 10 {
|
||||
continue
|
||||
}
|
||||
|
||||
for i, tileID := range layer.Data {
|
||||
if tileID == 0 {
|
||||
continue
|
||||
}
|
||||
x := i % layer.Width
|
||||
z := i / layer.Width
|
||||
|
||||
var ent Entity
|
||||
|
||||
if tileID == 3 { // Portal ID
|
||||
log.Println("Hittade portal vid", x, yLevel, z)
|
||||
target := "room2"
|
||||
if tmjPath == "mapp-maker/room2.tmj" {
|
||||
target = "room1"
|
||||
}
|
||||
ent = &Portal{ TargetMap: target }
|
||||
} else {
|
||||
// Mark
|
||||
if yLevel < 9 {
|
||||
ent = &Tile{ SideImg: tile12, TopImg: tile12 }
|
||||
} else {
|
||||
ent = &Tile{ SideImg: tile02, TopImg: tile31 }
|
||||
}
|
||||
}
|
||||
|
||||
w.SetEntityAt(x, yLevel, z, ent)
|
||||
}
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
@@ -46,25 +46,10 @@ type PlayScene struct {
|
||||
}
|
||||
|
||||
func NewPlayScene() *PlayScene {
|
||||
w := entities.NewWorld(10, 10, 10)
|
||||
|
||||
tile12, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_12.png")
|
||||
tile02, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_02.png")
|
||||
tile31, _, _ := ebitenutil.NewImageFromFile("assets/images/1 Tiles/Tile_31.png")
|
||||
|
||||
for x := 0; x < 10; x++ {
|
||||
for z := 0; z < 10; z++ {
|
||||
// Surface grass
|
||||
w.SetEntityAt(x, 9, z, &entities.Tile{
|
||||
SideImg: tile02,
|
||||
TopImg: tile31,
|
||||
})
|
||||
// Sub dirt
|
||||
w.SetEntityAt(x, 8, z, &entities.Tile{
|
||||
SideImg: tile12,
|
||||
TopImg: tile12,
|
||||
})
|
||||
}
|
||||
w, err := entities.LoadWorldFromTiled("mapp-maker/room1.tmj")
|
||||
if err != nil {
|
||||
log.Println("Kunde inte ladda room1:", err)
|
||||
w = entities.NewWorld(100, 10, 100) // Fallback tom värd om JSON saknas
|
||||
}
|
||||
|
||||
pRun, _, err := ebitenutil.NewImageFromFile("assets/images/Warrior_1/Run.png")
|
||||
@@ -77,13 +62,13 @@ func NewPlayScene() *PlayScene {
|
||||
pIdle = pRun
|
||||
}
|
||||
|
||||
pTop := ebiten.NewImage(32, 32)
|
||||
pTop := ebiten.NewImage(96, 96)
|
||||
pTop.Fill(color.RGBA{255, 255, 0, 255})
|
||||
|
||||
player := &Player{
|
||||
Pos: mgl64.Vec3{4.0 * entities.TileSize, 7.0 * entities.TileSize, 4.0 * entities.TileSize},
|
||||
Width: 20,
|
||||
Height: 40,
|
||||
Pos: mgl64.Vec3{50.0 * entities.TileSize, 6.0 * entities.TileSize, 50.0 * entities.TileSize},
|
||||
Width: 96,
|
||||
Height: 96,
|
||||
SpriteRun: pRun,
|
||||
SpriteIdle: pIdle,
|
||||
SpriteTop: pTop,
|
||||
@@ -154,6 +139,22 @@ func (s *PlayScene) Update() error {
|
||||
p.Pos[1] = nextY
|
||||
p.Pos[2] = nextZ
|
||||
|
||||
// Kolla ifall vi står på en portal
|
||||
standEnt := s.world.GetEntityAt(gridX, gridY, gridZ)
|
||||
if prt, ok := standEnt.(*entities.Portal); ok {
|
||||
log.Println("Byter rum till: ", prt.TargetMap)
|
||||
newW, err := entities.LoadWorldFromTiled("mapp-maker/" + prt.TargetMap + ".tmj")
|
||||
if err == nil {
|
||||
s.world = newW
|
||||
// Reset player position for new map
|
||||
if prt.TargetMap == "room1" {
|
||||
p.Pos = mgl64.Vec3{80.0 * entities.TileSize, 6.0 * entities.TileSize, 10.0 * entities.TileSize}
|
||||
} else {
|
||||
p.Pos = mgl64.Vec3{40.0 * entities.TileSize, 6.0 * entities.TileSize, 65.0 * entities.TileSize}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isMoving {
|
||||
p.AnimationCounter++
|
||||
if p.AnimationCounter > 5 {
|
||||
@@ -244,8 +245,8 @@ func (s *PlayScene) drawPlayerSide(screen *ebiten.Image, camX, camY float64) {
|
||||
op.GeoM.Translate(96, 0)
|
||||
}
|
||||
|
||||
drawX := p.Pos[0] - camX - 38
|
||||
drawY := p.Pos[1] - camY - 56
|
||||
drawX := p.Pos[0] - camX
|
||||
drawY := p.Pos[1] - camY
|
||||
|
||||
op.GeoM.Translate(drawX, drawY)
|
||||
screen.DrawImage(subImg, op)
|
||||
|
||||
14
mapp-maker/R.M.O.T.tiled-project
Normal file
14
mapp-maker/R.M.O.T.tiled-project
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"automappingRulesFile": "",
|
||||
"commands": [
|
||||
],
|
||||
"compatibilityVersion": 1100,
|
||||
"extensionsPath": "extensions",
|
||||
"folders": [
|
||||
"."
|
||||
],
|
||||
"properties": [
|
||||
],
|
||||
"propertyTypes": [
|
||||
]
|
||||
}
|
||||
18
mapp-maker/R.M.O.T.tiled-session
Normal file
18
mapp-maker/R.M.O.T.tiled-session
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"activeFile": "",
|
||||
"expandedProjectPaths": [
|
||||
],
|
||||
"fileStates": {
|
||||
"start.tsx": {
|
||||
"dynamicWrapping": true
|
||||
}
|
||||
},
|
||||
"last.imagePath": "/home/brasse/repos/Regin_mountain_of_treasures/assets/images/1 Tiles",
|
||||
"openFiles": [
|
||||
],
|
||||
"project": "R.M.O.T.tiled-project",
|
||||
"recentFiles": [
|
||||
],
|
||||
"tileset.lastUsedFormat": "tsx",
|
||||
"tileset.type": 1
|
||||
}
|
||||
100143
mapp-maker/room1.tmj
Normal file
100143
mapp-maker/room1.tmj
Normal file
File diff suppressed because it is too large
Load Diff
100143
mapp-maker/room2.tmj
Normal file
100143
mapp-maker/room2.tmj
Normal file
File diff suppressed because it is too large
Load Diff
6
mapp-maker/start.tsx
Normal file
6
mapp-maker/start.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.10" tiledversion="1.12.1" name="start" class="ground_1" tilewidth="32" tileheight="32" tilecount="1" columns="0">
|
||||
<tile id="0">
|
||||
<image source="../assets/images/1 Tiles/Tile_31.png" width="32" height="32"/>
|
||||
</tile>
|
||||
</tileset>
|
||||
12
mapp-maker/tileset.tsj
Normal file
12
mapp-maker/tileset.tsj
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"columns": 1,
|
||||
"image": "../assets/images/1 Tiles/Tile_12.png",
|
||||
"imageheight": 32,
|
||||
"imagewidth": 32,
|
||||
"name": "MainTileset",
|
||||
"tilecount": 1,
|
||||
"tileheight": 32,
|
||||
"tilewidth": 32,
|
||||
"type": "tileset",
|
||||
"version": "1.9"
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user