clean up slightly
This commit is contained in:
parent
0f367eaf96
commit
3560be99a1
22
TODO
22
TODO
@ -1,5 +1,5 @@
|
|||||||
Basics:
|
Basics:
|
||||||
- Items:
|
Items:
|
||||||
- place
|
- place
|
||||||
- pickup
|
- pickup
|
||||||
- drop
|
- drop
|
||||||
@ -8,7 +8,13 @@ Basics:
|
|||||||
- Character Screen
|
- Character Screen
|
||||||
- Common letter/string selector for menus to separate struct/file (use it in inventory, title at least)
|
- Common letter/string selector for menus to separate struct/file (use it in inventory, title at least)
|
||||||
- Move scrollBar ro separate struct/file/function
|
- Move scrollBar ro separate struct/file/function
|
||||||
|
Mobs:
|
||||||
|
basic:
|
||||||
|
- place mobs
|
||||||
|
- move mobs
|
||||||
|
advanced:
|
||||||
|
- ai
|
||||||
|
- dijkstra maps
|
||||||
|
|
||||||
Assets and i18n:
|
Assets and i18n:
|
||||||
- move tile settings to json, generate from there (part of prefabs)
|
- move tile settings to json, generate from there (part of prefabs)
|
||||||
@ -16,7 +22,7 @@ Assets and i18n:
|
|||||||
- all texts (terrain, mobs, quests) also in at least 2 languages
|
- all texts (terrain, mobs, quests) also in at least 2 languages
|
||||||
|
|
||||||
ECS & engine:
|
ECS & engine:
|
||||||
- implement time queue (how to deal with closures?) (?) github.com/thefish/sheduleq - get rid od time.Now inside
|
- implement time queue (how to deal with closures?) (?) github.com/thefish/scheduleq - get rid od time.Now inside
|
||||||
- move all rendering to systems
|
- move all rendering to systems
|
||||||
- try to move input handling to systems
|
- try to move input handling to systems
|
||||||
|
|
||||||
@ -30,7 +36,7 @@ Dungeon and branches:
|
|||||||
+ compose from gens and prefabs
|
+ compose from gens and prefabs
|
||||||
- editor for prefabs
|
- editor for prefabs
|
||||||
Mapgen:
|
Mapgen:
|
||||||
- use delaunay -> minimum spanning tree for room connection (Краскал в gonum)
|
+ use delaunay -> minimum spanning tree for room connection (Краскал в gonum)
|
||||||
github.com/algds/kruskals - MST
|
github.com/algds/kruskals - MST
|
||||||
github.com/esimov/triangle - delaunay
|
github.com/esimov/triangle - delaunay
|
||||||
- или граф относительных окрестностей (?)
|
- или граф относительных окрестностей (?)
|
||||||
@ -43,13 +49,7 @@ Combat:
|
|||||||
- damage from skill / mass / speed / material density
|
- damage from skill / mass / speed / material density
|
||||||
- no hitpoints! blood is the life source
|
- no hitpoints! blood is the life source
|
||||||
|
|
||||||
Mobs:
|
|
||||||
basic:
|
|
||||||
- place mobs
|
|
||||||
- move mobs
|
|
||||||
advanced:
|
|
||||||
- ai
|
|
||||||
- dijkstra maps
|
|
||||||
|
|
||||||
Quest engine:
|
Quest engine:
|
||||||
- look at parsers like URQL etc
|
- look at parsers like URQL etc
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
"lab.zaar.be/thefish/alchemyst-go/engine/ecs"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap/mapgens/delaunaymst"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap/mapgens"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamestate"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob/movement"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob/movement"
|
||||||
@ -71,7 +71,7 @@ func main() {
|
|||||||
|
|
||||||
//fixme set up (load / generate) level - move to game / enter or title / exit
|
//fixme set up (load / generate) level - move to game / enter or title / exit
|
||||||
//level, rooms := _default.DefaultGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
//level, rooms := _default.DefaultGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
||||||
level, rooms := delaunaymst.DelaunayMstGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
level, rooms := mapgens.DelaunayMstGen(mainCtx, gamemap.NewLevel(mainCtx, "test", 1))
|
||||||
State.Level = level
|
State.Level = level
|
||||||
|
|
||||||
sidebarWidth := 0
|
sidebarWidth := 0
|
||||||
|
176
engine/gamemap/mapgens/common.go
Normal file
176
engine/gamemap/mapgens/common.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package mapgens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
|
)
|
||||||
|
|
||||||
|
//fixme move to config
|
||||||
|
var minRoomSize = 5
|
||||||
|
var maxRoomSize = 25
|
||||||
|
var maxrooms = 200
|
||||||
|
|
||||||
|
var fges = map[int]types.RectFill{
|
||||||
|
1: types.RectFill{
|
||||||
|
Top: gamemap.NewWall,
|
||||||
|
Bottom: gamemap.NewWall,
|
||||||
|
Left: gamemap.NewWall,
|
||||||
|
Right: gamemap.NewWall,
|
||||||
|
BottomLeft: gamemap.NewWall,
|
||||||
|
BottomRight: gamemap.NewWall,
|
||||||
|
TopLeft: gamemap.NewWall,
|
||||||
|
TopRight: gamemap.NewWall,
|
||||||
|
Body: gamemap.NewFloor,
|
||||||
|
},
|
||||||
|
|
||||||
|
2: types.RectFill{
|
||||||
|
Top: gamemap.NewWaterTile,
|
||||||
|
Bottom: gamemap.NewWaterTile,
|
||||||
|
Left: gamemap.NewWaterTile,
|
||||||
|
Right: gamemap.NewWaterTile,
|
||||||
|
BottomLeft: gamemap.NewWaterTile,
|
||||||
|
BottomRight: gamemap.NewWaterTile,
|
||||||
|
TopLeft: gamemap.NewWaterTile,
|
||||||
|
TopRight: gamemap.NewWaterTile,
|
||||||
|
Body: gamemap.NewDeepWaterTile,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRandomRoomList(ctx appctx.ClientCtx, rng *util.RNG, l *gamemap.Level, maxRooms, minRoomSize, maxRoomSize int, ) []gamemap.Room{
|
||||||
|
rooms := make([]gamemap.Room, 0)
|
||||||
|
pfLoader := gamemap.NewPrefabLoader(ctx)
|
||||||
|
pfRooms := pfLoader.PrefabRoomsList()
|
||||||
|
|
||||||
|
var fillage types.RectFill
|
||||||
|
prefabUsed := false
|
||||||
|
|
||||||
|
for i := 0; i < maxRooms; i++ {
|
||||||
|
failed := false
|
||||||
|
fillage = fges[rng.GetWeightedEntity(map[int]int{1: 10, 2: 1})]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var newRoom = gamemap.Room{}
|
||||||
|
if !prefabUsed || rng.Range(0, 5) > 3 {
|
||||||
|
//if prefabUsed {
|
||||||
|
//prefab
|
||||||
|
prefabUsed = true
|
||||||
|
|
||||||
|
r := pfRooms[rng.Range(0, len(pfRooms))] //copy to local scope
|
||||||
|
newRoom = gamemap.Room{
|
||||||
|
Rect: r.Rect,
|
||||||
|
Center: r.Center,
|
||||||
|
Geometry: r.Geometry,
|
||||||
|
Items: r.Items,
|
||||||
|
Mobs: r.Mobs,
|
||||||
|
Connectors: make([]types.Coords,0),
|
||||||
|
}
|
||||||
|
for _, coord := range r.Connectors {
|
||||||
|
newRoom.Connectors = append(newRoom.Connectors, coord)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newRoom = gamemap.NewRandomRectRoom(
|
||||||
|
rng,
|
||||||
|
rng.Range(minRoomSize, maxRoomSize),
|
||||||
|
rng.Range(minRoomSize, maxRoomSize),
|
||||||
|
fillage,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
where := types.Coords{
|
||||||
|
rng.Range(1, l.W-2-newRoom.W),
|
||||||
|
rng.Range(1, l.H-2-newRoom.H),
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoom.MoveToCoords(where)
|
||||||
|
|
||||||
|
for _, otherRoom := range rooms {
|
||||||
|
if otherRoom.Intersects(newRoom.Rect) {
|
||||||
|
failed = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if failed {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(newRoom.Connectors) > 0 {
|
||||||
|
rooms = append(rooms, newRoom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rooms
|
||||||
|
}
|
||||||
|
|
||||||
|
//delaunay helper funcs
|
||||||
|
|
||||||
|
func FindNearestConnector(midpoint types.Coords, room gamemap.Room) types.Coords {
|
||||||
|
var nearest types.Coords
|
||||||
|
for _, con := range room.Connectors {
|
||||||
|
if nearest.X == 0 {
|
||||||
|
nearest = con
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if midpoint.DistanceTo(con) < midpoint.DistanceTo(nearest) {
|
||||||
|
nearest = con
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearest
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectStraight(rng *util.RNG, l *gamemap.Level, from, to, midpoint types.Coords) {
|
||||||
|
toss := rng.Range(0, 1)
|
||||||
|
if toss == 0 {
|
||||||
|
DigHTunnel(l, from.X, midpoint.X, from.Y)
|
||||||
|
DigVTunnel(l, from.Y, to.Y, midpoint.X)
|
||||||
|
DigHTunnel(l, midpoint.X, to.X, to.Y)
|
||||||
|
} else {
|
||||||
|
DigVTunnel(l, from.Y, midpoint.Y, from.X)
|
||||||
|
DigHTunnel(l, from.X, to.X, midpoint.Y)
|
||||||
|
DigVTunnel(l, midpoint.Y, to.Y, to.X)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DigHTunnel(l *gamemap.Level, x1, x2, y int) {
|
||||||
|
var start, finish int
|
||||||
|
if x1 < x2 {
|
||||||
|
start = x1
|
||||||
|
finish = x2
|
||||||
|
} else {
|
||||||
|
start = x2
|
||||||
|
finish = x1
|
||||||
|
}
|
||||||
|
for i := start; i <= finish; i++ {
|
||||||
|
if l.InBounds(types.Coords{i, y}) {
|
||||||
|
l.SetTileByXY(i, y, gamemap.NewFloor())
|
||||||
|
//l.Tiles[i][y] = gamemap.NewFloor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DigVTunnel(l *gamemap.Level, y1, y2, x int) {
|
||||||
|
var start, finish int
|
||||||
|
if y1 < y2 {
|
||||||
|
start = y1
|
||||||
|
finish = y2
|
||||||
|
} else {
|
||||||
|
start = y2
|
||||||
|
finish = y1
|
||||||
|
}
|
||||||
|
for i := start; i <= finish; i++ {
|
||||||
|
if l.InBounds(types.Coords{x, i}) {
|
||||||
|
l.SetTileByXY(x, i, gamemap.NewFloor())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//default helper
|
||||||
|
|
||||||
|
func ConnectRoomCenters(l *gamemap.Level, room, otherRoom gamemap.Room, toss int) {
|
||||||
|
if toss == 0 {
|
||||||
|
DigHTunnel(l, room.Center.X, otherRoom.Center.X, room.Center.Y)
|
||||||
|
DigVTunnel(l, room.Center.Y, otherRoom.Center.Y, otherRoom.Center.X)
|
||||||
|
} else {
|
||||||
|
DigVTunnel(l, room.Center.Y, otherRoom.Center.Y, room.Center.Y)
|
||||||
|
DigHTunnel(l, room.Center.X, otherRoom.Center.X, otherRoom.Center.Y)
|
||||||
|
}
|
||||||
|
}
|
38
engine/gamemap/mapgens/default.go
Normal file
38
engine/gamemap/mapgens/default.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package mapgens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DefaultGen(ctx appctx.ClientCtx,l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
||||||
|
|
||||||
|
rng := util.NewRNG()
|
||||||
|
|
||||||
|
//fill with walls
|
||||||
|
for i := 0; i < l.W; i ++ {
|
||||||
|
for j := 0; j < l.H; j++ {
|
||||||
|
l.SetTileByXY(i, j, gamemap.NewWall())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rooms := GetRandomRoomList(ctx, rng, l, maxrooms, minRoomSize, maxRoomSize)
|
||||||
|
|
||||||
|
for _, room := range rooms {
|
||||||
|
err := room.BlitToLevel(l)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx, room := range rooms {
|
||||||
|
if idx > 0 {
|
||||||
|
ConnectRoomCenters(l, room, rooms[idx-1], rng.Range(0, 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, rooms
|
||||||
|
}
|
||||||
|
|
@ -1,162 +0,0 @@
|
|||||||
package _default
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
|
||||||
)
|
|
||||||
|
|
||||||
//fixme move to config
|
|
||||||
var minRoomSize = 3
|
|
||||||
var maxRoomSize = 15
|
|
||||||
var maxrooms = 50
|
|
||||||
|
|
||||||
var fges = map[int]types.RectFill{
|
|
||||||
1: types.RectFill{
|
|
||||||
Top: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Bottom: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Left: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Right: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
BottomLeft: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
BottomRight: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
TopLeft: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
TopRight: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Body: func() *gamemap.Tile { return gamemap.NewFloor() },
|
|
||||||
},
|
|
||||||
|
|
||||||
2: types.RectFill{
|
|
||||||
Top: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Bottom: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Left: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Right: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
BottomLeft: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
BottomRight: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
TopLeft: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
TopRight: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Body: func() *gamemap.Tile { return gamemap.NewDeepWaterTile() },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultGen(ctx appctx.ClientCtx,l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
|
||||||
|
|
||||||
rng := util.NewRNG()
|
|
||||||
|
|
||||||
//load prefabs
|
|
||||||
pfLoader := gamemap.NewPrefabLoader(ctx)
|
|
||||||
pfRooms := pfLoader.PrefabRoomsList()
|
|
||||||
|
|
||||||
|
|
||||||
//fill with walls
|
|
||||||
for i := 0; i < l.W; i ++ {
|
|
||||||
for j := 0; j < l.H; j++ {
|
|
||||||
l.SetTileByXY(i, j, gamemap.NewWall())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rooms := make([]gamemap.Room, 0)
|
|
||||||
prefabUsed := false
|
|
||||||
for i := 0; i < maxrooms; i++ {
|
|
||||||
failed := false
|
|
||||||
var fillage types.RectFill
|
|
||||||
fillage = fges[rng.GetWeightedEntity(map[int]int{1: 10, 2: 1})]
|
|
||||||
var newRoom gamemap.Room
|
|
||||||
if !prefabUsed || rng.Range(0,5) > 3 {
|
|
||||||
//prefab
|
|
||||||
prefabUsed = true
|
|
||||||
r := pfRooms[rng.Range(0, len(pfRooms))] //copy to local scope
|
|
||||||
newRoom = r
|
|
||||||
} else {
|
|
||||||
newRoom = gamemap.NewRandomRectRoom(
|
|
||||||
rng,
|
|
||||||
rng.Range(minRoomSize, maxRoomSize),
|
|
||||||
rng.Range(minRoomSize, maxRoomSize),
|
|
||||||
fillage,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
where := types.Coords{
|
|
||||||
rng.Range(1, l.W -2 - newRoom.W),
|
|
||||||
rng.Range(1, l.H - 2 - newRoom.H),
|
|
||||||
}
|
|
||||||
|
|
||||||
newRoom.MoveToCoords(where)
|
|
||||||
|
|
||||||
for _, otherRoom := range rooms {
|
|
||||||
if otherRoom.Intersects(newRoom.Rect) {
|
|
||||||
failed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !failed {
|
|
||||||
rooms = append(rooms, newRoom)
|
|
||||||
}
|
|
||||||
|
|
||||||
//addStairs(rooms)
|
|
||||||
//itemize(rooms)
|
|
||||||
}
|
|
||||||
|
|
||||||
//build delannay graph from room center
|
|
||||||
|
|
||||||
//refine it to minimum spanning tree
|
|
||||||
|
|
||||||
//connect accordingly
|
|
||||||
for _, room := range rooms {
|
|
||||||
err := room.BlitToLevel(l)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for idx, room := range rooms {
|
|
||||||
if idx > 0 {
|
|
||||||
connectRooms(l, room, rooms[idx-1], rng.Range(0, 1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return l, rooms
|
|
||||||
}
|
|
||||||
|
|
||||||
func connectRooms(l *gamemap.Level, room, otherRoom gamemap.Room, toss int) {
|
|
||||||
if toss == 0 {
|
|
||||||
digHTunnel(l, room.Center.X, otherRoom.Center.X, room.Center.Y)
|
|
||||||
digVTunnel(l, room.Center.Y, otherRoom.Center.Y, otherRoom.Center.X)
|
|
||||||
} else {
|
|
||||||
digVTunnel(l, room.Center.Y, otherRoom.Center.Y, room.Center.Y)
|
|
||||||
digHTunnel(l, room.Center.X, otherRoom.Center.X, otherRoom.Center.Y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func digHTunnel(l *gamemap.Level, x1, x2, y int) {
|
|
||||||
var start, finish int
|
|
||||||
if x1 < x2 {
|
|
||||||
start = x1
|
|
||||||
finish = x2
|
|
||||||
} else {
|
|
||||||
start = x2
|
|
||||||
finish = x1
|
|
||||||
}
|
|
||||||
for i := start; i <= finish; i++ {
|
|
||||||
if l.InBounds(types.Coords{i, y}) {
|
|
||||||
l.SetTileByXY(i, y, gamemap.NewFloor())
|
|
||||||
//l.Tiles[i][y] = gamemap.NewFloor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func digVTunnel(l *gamemap.Level, y1, y2, x int) {
|
|
||||||
var start, finish int
|
|
||||||
if y1 < y2 {
|
|
||||||
start = y1
|
|
||||||
finish = y2
|
|
||||||
} else {
|
|
||||||
start = y2
|
|
||||||
finish = y1
|
|
||||||
}
|
|
||||||
for i := start; i <= finish; i++ {
|
|
||||||
if l.InBounds(types.Coords{x, i}) {
|
|
||||||
l.SetTileByXY(x, i, gamemap.NewFloor())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
67
engine/gamemap/mapgens/delaunay_mst.go
Normal file
67
engine/gamemap/mapgens/delaunay_mst.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package mapgens
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
||||||
|
"lab.zaar.be/thefish/alchemyst-go/util/delaunay"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DelaunayMstGen(ctx appctx.ClientCtx, l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
||||||
|
|
||||||
|
rng := util.NewRNG()
|
||||||
|
|
||||||
|
//fill with walls
|
||||||
|
for i := 0; i < l.W; i ++ {
|
||||||
|
for j := 0; j < l.H; j++ {
|
||||||
|
l.SetTileByXY(i, j, gamemap.NewWall())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rooms := GetRandomRoomList(ctx, rng, l, maxrooms, minRoomSize, maxRoomSize)
|
||||||
|
|
||||||
|
|
||||||
|
for _, room := range rooms {
|
||||||
|
err := room.BlitToLevel(l)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
centers := make([]types.Coords, 0)
|
||||||
|
for _, room := range rooms {
|
||||||
|
centers = append(centers, room.Center)
|
||||||
|
}
|
||||||
|
edges := delaunay.GetMst(centers, l.W, l.H)
|
||||||
|
for _, edge := range edges {
|
||||||
|
MedianStraight(rng, l, rooms, centers, edge)
|
||||||
|
}
|
||||||
|
|
||||||
|
return l, rooms
|
||||||
|
}
|
||||||
|
|
||||||
|
func MedianStraight(rng *util.RNG, l *gamemap.Level, rooms []gamemap.Room, centers []types.Coords, edge types.Edge) {
|
||||||
|
//find connected rooms
|
||||||
|
var fromRoom, toRoom gamemap.Room
|
||||||
|
for _, room := range rooms {
|
||||||
|
if room.Center == edge.From {
|
||||||
|
fromRoom = room
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if room.Center == edge.To {
|
||||||
|
toRoom = room
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(fromRoom.Connectors) > 0 && len(toRoom.Connectors) > 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
midpoint := edge.Midpoint()
|
||||||
|
fromConnector := FindNearestConnector(midpoint, fromRoom)
|
||||||
|
toConnector := FindNearestConnector(midpoint, toRoom)
|
||||||
|
ConnectStraight(rng, l, fromConnector, toConnector, midpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,229 +0,0 @@
|
|||||||
package delaunaymst
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/types"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/appctx"
|
|
||||||
"lab.zaar.be/thefish/alchemyst-go/util/delaunay"
|
|
||||||
)
|
|
||||||
|
|
||||||
//fixme move to config
|
|
||||||
var minRoomSize = 5
|
|
||||||
var maxRoomSize = 25
|
|
||||||
var maxrooms = 200
|
|
||||||
|
|
||||||
var fges = map[int]types.RectFill{
|
|
||||||
1: types.RectFill{
|
|
||||||
Top: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Bottom: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Left: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Right: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
BottomLeft: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
BottomRight: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
TopLeft: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
TopRight: func() *gamemap.Tile { return gamemap.NewWall() },
|
|
||||||
Body: func() *gamemap.Tile { return gamemap.NewFloor() },
|
|
||||||
},
|
|
||||||
|
|
||||||
2: types.RectFill{
|
|
||||||
Top: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Bottom: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Left: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Right: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
BottomLeft: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
BottomRight: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
TopLeft: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
TopRight: func() *gamemap.Tile { return gamemap.NewWaterTile() },
|
|
||||||
Body: func() *gamemap.Tile { return gamemap.NewDeepWaterTile() },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func DelaunayMstGen(ctx appctx.ClientCtx, l *gamemap.Level) (*gamemap.Level, []gamemap.Room) {
|
|
||||||
rng := util.NewRNG()
|
|
||||||
//load prefabs
|
|
||||||
pfLoader := gamemap.NewPrefabLoader(ctx)
|
|
||||||
pfRooms := pfLoader.PrefabRoomsList()
|
|
||||||
|
|
||||||
//fill with walls
|
|
||||||
for i := 0; i < l.W; i ++ {
|
|
||||||
for j := 0; j < l.H; j++ {
|
|
||||||
l.SetTileByXY(i, j, gamemap.NewWall())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rooms := make([]gamemap.Room, 0)
|
|
||||||
prefabUsed := false
|
|
||||||
for i := 0; i < maxrooms; i++ {
|
|
||||||
failed := false
|
|
||||||
var fillage types.RectFill
|
|
||||||
fillage = fges[rng.GetWeightedEntity(map[int]int{1: 10, 2: 1})]
|
|
||||||
var newRoom = gamemap.Room{}
|
|
||||||
if !prefabUsed || rng.Range(0, 5) > 3 {
|
|
||||||
//if prefabUsed {
|
|
||||||
//prefab
|
|
||||||
prefabUsed = true
|
|
||||||
fmt.Printf("\n\n------USING PREFAB-----\n")
|
|
||||||
r := pfRooms[rng.Range(0, len(pfRooms))] //copy to local scope
|
|
||||||
newRoom = gamemap.Room{
|
|
||||||
Rect: r.Rect,
|
|
||||||
Center: r.Center,
|
|
||||||
Geometry: r.Geometry,
|
|
||||||
Items: r.Items,
|
|
||||||
Mobs: r.Mobs,
|
|
||||||
Connectors: make([]types.Coords,0),
|
|
||||||
}
|
|
||||||
for _, coord := range r.Connectors {
|
|
||||||
newRoom.Connectors = append(newRoom.Connectors, coord)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newRoom = gamemap.NewRandomRectRoom(
|
|
||||||
rng,
|
|
||||||
rng.Range(minRoomSize, maxRoomSize),
|
|
||||||
rng.Range(minRoomSize, maxRoomSize),
|
|
||||||
fillage,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
where := types.Coords{
|
|
||||||
rng.Range(1, l.W-2-newRoom.W),
|
|
||||||
rng.Range(1, l.H-2-newRoom.H),
|
|
||||||
}
|
|
||||||
|
|
||||||
newRoom.MoveToCoords(where)
|
|
||||||
|
|
||||||
for _, otherRoom := range rooms {
|
|
||||||
if otherRoom.Intersects(newRoom.Rect) {
|
|
||||||
failed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if failed {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(newRoom.Connectors) > 0 {
|
|
||||||
rooms = append(rooms, newRoom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, room := range rooms {
|
|
||||||
err := room.BlitToLevel(l)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
centers := make([]types.Coords, 0)
|
|
||||||
for _, room := range rooms {
|
|
||||||
centers = append(centers, room.Center)
|
|
||||||
}
|
|
||||||
edges := delaunay.GetMst(centers, l.W, l.H)
|
|
||||||
fmt.Printf("edges: ", edges)
|
|
||||||
for _, edge := range edges {
|
|
||||||
MedianStraight(rng, l, rooms, centers, edge)
|
|
||||||
}
|
|
||||||
|
|
||||||
return l, rooms
|
|
||||||
}
|
|
||||||
|
|
||||||
func MedianStraight(rng *util.RNG, l *gamemap.Level, rooms []gamemap.Room, centers []types.Coords, edge types.Edge) {
|
|
||||||
//find connected rooms
|
|
||||||
var fromRoom, toRoom gamemap.Room
|
|
||||||
for _, room := range rooms {
|
|
||||||
if room.Center == edge.From {
|
|
||||||
fromRoom = room
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if room.Center == edge.To {
|
|
||||||
toRoom = room
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(fromRoom.Connectors) > 0 && len(toRoom.Connectors) > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
midpoint := edge.Midpoint()
|
|
||||||
fromConnector := findNearestCoonector(midpoint, fromRoom)
|
|
||||||
toConnector := findNearestCoonector(midpoint, toRoom)
|
|
||||||
if (!l.InBounds(midpoint)) {
|
|
||||||
//fmt.Printf("rooms: ", rooms)
|
|
||||||
fmt.Printf("\nedges: ", edge)
|
|
||||||
fmt.Printf("\nmidpoint: ", midpoint)
|
|
||||||
panic(fmt.Errorf("midpoint out of level bounds!"))
|
|
||||||
}
|
|
||||||
if (!l.InBounds(fromConnector)) {
|
|
||||||
fmt.Printf("\nfrom room: ", fromRoom.String())
|
|
||||||
fmt.Printf("\nedges: ", edge)
|
|
||||||
fmt.Printf("\nfromConnector: ", fromConnector)
|
|
||||||
panic(fmt.Errorf("fromConnector out of level bounds!"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!l.InBounds(toConnector)) {
|
|
||||||
fmt.Printf("\nto room: ", toRoom.String())
|
|
||||||
fmt.Printf("\nedges: ", edge)
|
|
||||||
fmt.Printf("\ntoConnector: ", toConnector)
|
|
||||||
panic(fmt.Errorf("toConnector out of level bounds!"))
|
|
||||||
}
|
|
||||||
|
|
||||||
connectStraight(rng, l, fromConnector, toConnector, midpoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findNearestCoonector(midpoint types.Coords, room gamemap.Room) types.Coords {
|
|
||||||
var nearest types.Coords
|
|
||||||
for _, con := range room.Connectors {
|
|
||||||
if nearest.X == 0 {
|
|
||||||
nearest = con
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if midpoint.DistanceTo(con) < midpoint.DistanceTo(nearest) {
|
|
||||||
nearest = con
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nearest
|
|
||||||
}
|
|
||||||
|
|
||||||
func connectStraight(rng *util.RNG, l *gamemap.Level, from, to, midpoint types.Coords) {
|
|
||||||
toss := rng.Range(0, 1)
|
|
||||||
if toss == 0 {
|
|
||||||
digHTunnel(l, from.X, midpoint.X, from.Y)
|
|
||||||
digVTunnel(l, from.Y, to.Y, midpoint.X)
|
|
||||||
digHTunnel(l, midpoint.X, to.X, to.Y)
|
|
||||||
} else {
|
|
||||||
digVTunnel(l, from.Y, midpoint.Y, from.X)
|
|
||||||
digHTunnel(l, from.X, to.X, midpoint.Y)
|
|
||||||
digVTunnel(l, midpoint.Y, to.Y, to.X)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func digHTunnel(l *gamemap.Level, x1, x2, y int) {
|
|
||||||
var start, finish int
|
|
||||||
if x1 < x2 {
|
|
||||||
start = x1
|
|
||||||
finish = x2
|
|
||||||
} else {
|
|
||||||
start = x2
|
|
||||||
finish = x1
|
|
||||||
}
|
|
||||||
for i := start; i <= finish; i++ {
|
|
||||||
if l.InBounds(types.Coords{i, y}) {
|
|
||||||
l.SetTileByXY(i, y, gamemap.NewFloor())
|
|
||||||
//l.Tiles[i][y] = gamemap.NewFloor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func digVTunnel(l *gamemap.Level, y1, y2, x int) {
|
|
||||||
var start, finish int
|
|
||||||
if y1 < y2 {
|
|
||||||
start = y1
|
|
||||||
finish = y2
|
|
||||||
} else {
|
|
||||||
start = y2
|
|
||||||
finish = y1
|
|
||||||
}
|
|
||||||
for i := start; i <= finish; i++ {
|
|
||||||
if l.InBounds(types.Coords{x, i}) {
|
|
||||||
l.SetTileByXY(x, i, gamemap.NewFloor())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,6 @@ package gamemap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
"lab.zaar.be/thefish/alchemyst-go/engine/items"
|
||||||
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
"lab.zaar.be/thefish/alchemyst-go/engine/mob"
|
||||||
@ -113,8 +112,6 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//add room to list
|
//add room to list
|
||||||
fmt.Printf("PREFAB room append: ", room.String())
|
|
||||||
|
|
||||||
rooms = append(rooms, room)
|
rooms = append(rooms, room)
|
||||||
}
|
}
|
||||||
return rooms
|
return rooms
|
||||||
|
@ -60,8 +60,6 @@ func (room *Room) BlitToLevel(l *Level) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (room *Room) MoveToCoords(where types.Coords) *Room {
|
func (room *Room) MoveToCoords(where types.Coords) *Room {
|
||||||
fmt.Printf("\n MOVING room :", room.String())
|
|
||||||
fmt.Printf("\nmovin room to %v", where)
|
|
||||||
//update room coords?
|
//update room coords?
|
||||||
room.X = where.X
|
room.X = where.X
|
||||||
room.Y = where.Y
|
room.Y = where.Y
|
||||||
@ -70,14 +68,11 @@ func (room *Room) MoveToCoords(where types.Coords) *Room {
|
|||||||
room.Center.Y = room.Center.Y + where.Y
|
room.Center.Y = room.Center.Y + where.Y
|
||||||
//update connector?
|
//update connector?
|
||||||
for i, coords := range room.Connectors {
|
for i, coords := range room.Connectors {
|
||||||
fmt.Printf("\nupdating coords ", coords)
|
|
||||||
coords.X = coords.X + where.X
|
coords.X = coords.X + where.X
|
||||||
coords.Y = coords.Y + where.Y
|
coords.Y = coords.Y + where.Y
|
||||||
fmt.Printf("\nupdated coords ", coords)
|
|
||||||
room.Connectors[i] = coords
|
room.Connectors[i] = coords
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\nROOM MOVED to %v \n\n", room)
|
|
||||||
return room
|
return room
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,4 +169,9 @@ func (tr *TerrainRender) Render() {
|
|||||||
**вдвое**. Это удобная штука, не спорю, но пользоваться ей надо при загрузке ресурсов, при сохранении/загрузке состояния
|
**вдвое**. Это удобная штука, не спорю, но пользоваться ей надо при загрузке ресурсов, при сохранении/загрузке состояния
|
||||||
приложения - т.е. при разовых операциях. Как оказалось, она _очень_ дорогая по CPU. Кто пользоуется ей в main loop, ORM
|
приложения - т.е. при разовых операциях. Как оказалось, она _очень_ дорогая по CPU. Кто пользоуется ей в main loop, ORM
|
||||||
и прочих нагруженных местах - да будет предан анафеме.
|
и прочих нагруженных местах - да будет предан анафеме.
|
||||||
|
|
||||||
|
|
||||||
|
Обратить внимание
|
||||||
|
===
|
||||||
|
При казалось бы передаче по значению слайсы - всё равно передаются по ссылке! (пример с комнатами и выходами)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user