fixed up comments
This commit is contained in:
+33
-8
@@ -8,14 +8,18 @@ import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// GenerateBuildings creates and places buildings on the map.
|
||||
func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, roadPixels, allWaterPixels []image.Point, seed int64) []image.Point {
|
||||
// Early exit if no buildings are to be generated
|
||||
if settings.NumBuildings == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Initialize random number generator
|
||||
randSrc := rand.New(rand.NewSource(seed))
|
||||
buildingColor := color.RGBA{R: 128, G: 128, B: 128, A: 255} // Gray color for buildings
|
||||
|
||||
// Create lookup maps for water and road pixels for efficient collision detection
|
||||
isWater := make(map[image.Point]bool)
|
||||
for _, p := range allWaterPixels {
|
||||
isWater[p] = true
|
||||
@@ -26,9 +30,12 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
|
||||
isRoad[p] = true
|
||||
}
|
||||
|
||||
// Initialize building data structures
|
||||
isBuilding := make(map[image.Point]bool)
|
||||
var buildingPixels []image.Point
|
||||
var anchorPoints []image.Point
|
||||
|
||||
// Determine anchor points for building placement
|
||||
if len(roadPixels) > 0 {
|
||||
anchorPoints = roadPixels
|
||||
} else {
|
||||
@@ -42,16 +49,20 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Early exit if no anchor points are available
|
||||
if len(anchorPoints) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Sort anchor points to have a deterministic order if needed, although we are selecting randomly
|
||||
// Sort anchor points for deterministic placement
|
||||
sort.Slice(anchorPoints, func(i, j int) bool {
|
||||
if anchorPoints[i].Y != anchorPoints[j].Y {
|
||||
return anchorPoints[i].Y < anchorPoints[j].Y
|
||||
}
|
||||
return anchorPoints[i].X < anchorPoints[j].X
|
||||
})
|
||||
|
||||
// Collect all land points for random placement
|
||||
landPoints := make([]image.Point, 0, width*height)
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
@@ -61,25 +72,29 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main loop for placing buildings
|
||||
buildingsPlaced := 0
|
||||
searchTries := 100 // Number of attempts to find a spot for a building
|
||||
searchTries := 100 // Number of attempts to find a spot for a building around an anchor
|
||||
maxPlacementAttempts := settings.NumBuildings * 5 // To prevent infinite loops
|
||||
|
||||
for buildingsPlaced < settings.NumBuildings && maxPlacementAttempts > 0 {
|
||||
maxPlacementAttempts--
|
||||
|
||||
// Select an anchor point for the new building
|
||||
var anchor image.Point
|
||||
if randSrc.Float64() > settings.BuildingDistribution/100.0 {
|
||||
// Place near roads
|
||||
// Place near roads or other existing features
|
||||
anchor = anchorPoints[randSrc.Intn(len(anchorPoints))]
|
||||
} else {
|
||||
// Place randomly on land
|
||||
// Place randomly on any available land
|
||||
if len(landPoints) == 0 {
|
||||
continue // No land to place buildings on
|
||||
}
|
||||
anchor = landPoints[randSrc.Intn(len(landPoints))]
|
||||
}
|
||||
|
||||
// Search for a valid building location around the anchor
|
||||
for i := 0; i < searchTries; i++ {
|
||||
searchRadius := float64(i) * 2.0 // Search in expanding circles
|
||||
angle := randSrc.Float64() * 2 * math.Pi
|
||||
@@ -88,6 +103,7 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
|
||||
X: anchor.X + int(dist*math.Cos(angle)),
|
||||
Y: anchor.Y + int(dist*math.Sin(angle)),
|
||||
}
|
||||
// For fully random distribution, pick any point on the map
|
||||
if settings.BuildingDistribution == 100 {
|
||||
center = image.Point{
|
||||
X: randSrc.Intn(width),
|
||||
@@ -95,36 +111,42 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the center point is within the map boundaries
|
||||
if center.X < 0 || center.Y < 0 || center.X >= width || center.Y >= height {
|
||||
continue
|
||||
}
|
||||
|
||||
// Attempt to create a building at the selected center
|
||||
size := settings.MinBuildingSize + randSrc.Float64()*(settings.MaxBuildingSize-settings.MinBuildingSize)
|
||||
pixels, ok := getBuildingPixels(center, size, settings.BuildingShape, isWater, isRoad, isBuilding, width, height, randSrc)
|
||||
if ok {
|
||||
// If successful, draw the building and update data structures
|
||||
for _, p := range pixels {
|
||||
img.Set(p.X, p.Y, buildingColor)
|
||||
isBuilding[p] = true
|
||||
buildingPixels = append(buildingPixels, p)
|
||||
}
|
||||
buildingsPlaced++
|
||||
break // Found a spot, move to next building
|
||||
break // Move to the next building
|
||||
}
|
||||
}
|
||||
}
|
||||
return buildingPixels
|
||||
}
|
||||
|
||||
// getBuildingPixels determines the pixels for a single building based on its shape and checks for collisions.
|
||||
func getBuildingPixels(center image.Point, size float64, shape string, isWater, isRoad, isBuilding map[image.Point]bool, width, height int, randSrc *rand.Rand) ([]image.Point, bool) {
|
||||
var pixels []image.Point
|
||||
var halfSize = int(size / 2)
|
||||
|
||||
// Generate pixels based on the selected building shape
|
||||
switch shape {
|
||||
case "squares":
|
||||
for y := center.Y - halfSize; y <= center.Y+halfSize; y++ {
|
||||
for x := center.X - halfSize; x <= center.X+halfSize; x++ {
|
||||
p := image.Point{X: x, Y: y}
|
||||
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
|
||||
return nil, false
|
||||
return nil, false // Collision detected
|
||||
}
|
||||
pixels = append(pixels, p)
|
||||
}
|
||||
@@ -137,13 +159,14 @@ func getBuildingPixels(center image.Point, size float64, shape string, isWater,
|
||||
if dx*dx+dy*dy <= r2 {
|
||||
p := image.Point{X: x, Y: y}
|
||||
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
|
||||
return nil, false
|
||||
return nil, false // Collision detected
|
||||
}
|
||||
pixels = append(pixels, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "rectangles":
|
||||
// Create rectangles with varied aspect ratios
|
||||
longSide := size
|
||||
shortSide := randSrc.Float64()*(size-float64(halfSize)) + float64(halfSize)
|
||||
var w, h int
|
||||
@@ -154,17 +177,19 @@ func getBuildingPixels(center image.Point, size float64, shape string, isWater,
|
||||
}
|
||||
halfW, halfH := w/2, h/2
|
||||
|
||||
// Check for collisions and gather pixels
|
||||
for y := center.Y - halfH; y <= center.Y+halfH; y++ {
|
||||
for x := center.X - halfW; x <= center.X+halfW; x++ {
|
||||
p := image.Point{X: x, Y: y}
|
||||
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
|
||||
return nil, false
|
||||
return nil, false // Collision detected
|
||||
}
|
||||
pixels = append(pixels, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Final check to ensure pixels were generated
|
||||
if len(pixels) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user