delaunay mapgen 1st version

This commit is contained in:
2019-11-13 23:03:16 +03:00
22 changed files with 633 additions and 31 deletions

View File

@ -1,4 +1,4 @@
package mapgens
package _default
import (
"fmt"

View File

@ -0,0 +1,196 @@
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 = 15
var maxrooms = 59
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 {
//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 {
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)
}
for _, edge := range delaunay.GetMst(centers, l.W, l.H) {
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)
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())
}
}
}

View File

@ -57,11 +57,12 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
panic(err)
}
//prepare actual legends
currentTileLegend := file.DefaultTileLegend
currentMobsLegend := file.DefaultMobsLegend
currentItemLegend := file.DefaultItemLegend
for _, rawPrefab := range file.Prefabs {
//prepare actual legends
currentTileLegend := file.DefaultTileLegend
currentMobsLegend := file.DefaultMobsLegend
currentItemLegend := file.DefaultItemLegend
for k,v := range rawPrefab.TileLegend {
currentTileLegend[k] = v
@ -99,7 +100,7 @@ func (pfbl PrefabLoader) PrefabRoomsList() []Room {
continue
}
if shortName == "connector" {
f = NewFloor
f = NewWall
room.Connectors = append(room.Connectors, types.Coords{i,j})
} else {
f, ok = TileTypeMap[shortName]
@ -122,4 +123,4 @@ var TileTypeMap = map[string]func()*Tile{
"decorated_wall": NewDecoratedWall,
"water": NewWaterTile,
"deep_water": NewDeepWaterTile,
}
}