2024-08-29 00:05:28 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/aquilax/go-perlin"
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
|
|
"image/color"
|
2024-08-29 21:12:18 +02:00
|
|
|
"sync"
|
2024-08-29 00:05:28 +02:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type GameMap struct {
|
|
|
|
tiles [][]uint8
|
|
|
|
//tile 0 - air
|
|
|
|
//tile 1 - rock
|
|
|
|
//tile 2 - soil 1
|
|
|
|
//tile 3 - soil 2
|
|
|
|
//tile 4 - base
|
|
|
|
//tile 5 - world edge (should not be present in the map object)
|
2024-08-30 19:07:56 +02:00
|
|
|
width uint32
|
|
|
|
height uint32
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetTileColorValue(value uint8) color.Color {
|
|
|
|
switch value {
|
|
|
|
case 0:
|
|
|
|
return color.RGBA{}
|
|
|
|
case 1:
|
|
|
|
return color.RGBA{R: 154, G: 154, B: 154, A: 255}
|
|
|
|
case 2:
|
|
|
|
return color.RGBA{R: 195, G: 121, B: 48, A: 255}
|
|
|
|
case 3:
|
|
|
|
return color.RGBA{R: 186, G: 89, B: 4, A: 255}
|
|
|
|
case 4:
|
|
|
|
return color.RGBA{R: 255, G: 44, B: 255, A: 255}
|
|
|
|
case 5:
|
|
|
|
return color.RGBA{R: 86, G: 86, B: 86, A: 255}
|
|
|
|
default:
|
|
|
|
return color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gameMap *GameMap) getTileColor(x int32, y int32) color.Color {
|
2024-08-30 19:07:56 +02:00
|
|
|
if x < 0 || x >= int32(gameMap.width) || y < 0 || y >= int32(gameMap.height) {
|
2024-08-29 00:05:28 +02:00
|
|
|
return GetTileColorValue(5)
|
|
|
|
} else {
|
|
|
|
tileValue := gameMap.tiles[x][y]
|
|
|
|
return GetTileColorValue(tileValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (gameMap *GameMap) createGameMap(withData bool) {
|
2024-08-29 21:12:18 +02:00
|
|
|
// Initialize the 2D slice for game tiles
|
2024-08-30 19:07:56 +02:00
|
|
|
gameMap.tiles = make([][]uint8, serverConfig.MapWidth)
|
2024-08-29 21:12:18 +02:00
|
|
|
// Create Perlin noise generators
|
2024-08-29 18:48:27 +02:00
|
|
|
perlinNoiseRock := perlin.NewPerlin(2, 4, 8, time.Now().Unix())
|
2024-08-29 00:05:28 +02:00
|
|
|
perlinNoiseSoil := perlin.NewPerlin(2, 8, 4, time.Now().Unix())
|
2024-08-29 21:12:18 +02:00
|
|
|
|
|
|
|
// WaitGroup to synchronize goroutines
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
// Loop over the rows
|
2024-08-29 00:05:28 +02:00
|
|
|
for i := range gameMap.tiles {
|
2024-08-29 21:12:18 +02:00
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
if withData {
|
|
|
|
// Launch a goroutine for each row
|
|
|
|
// Increment WaitGroup counter for each goroutine
|
|
|
|
wg.Add(1)
|
|
|
|
go func(i int) {
|
|
|
|
defer wg.Done() // Signal that this goroutine is done
|
|
|
|
|
|
|
|
// Initialize the row
|
|
|
|
gameMap.tiles[i] = make([]uint8, serverConfig.MapHeight)
|
|
|
|
|
|
|
|
// Process each tile in the row
|
|
|
|
for j := range gameMap.tiles[i] {
|
|
|
|
perlinRock := perlinNoiseRock.Noise2D(float64(i)/float64(serverConfig.MapWidth)*6, float64(j)/float64(serverConfig.MapHeight)*6)
|
|
|
|
if perlinRock > 0.2 {
|
|
|
|
gameMap.tiles[i][j] = 1
|
2024-08-29 21:12:18 +02:00
|
|
|
} else {
|
2024-08-30 19:07:56 +02:00
|
|
|
perlinSoil := perlinNoiseSoil.Noise2D(float64(i)/float64(serverConfig.MapWidth)*10, float64(j)/float64(serverConfig.MapHeight)*10)
|
|
|
|
if perlinSoil >= 0 {
|
|
|
|
gameMap.tiles[i][j] = 2
|
|
|
|
} else {
|
|
|
|
gameMap.tiles[i][j] = 3
|
|
|
|
}
|
2024-08-29 21:12:18 +02:00
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
}(i)
|
|
|
|
} else {
|
|
|
|
for x := uint32(0); x < serverConfig.MapWidth; x++ {
|
|
|
|
gameMap.tiles[x] = make([]uint8, serverConfig.MapHeight)
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-29 21:12:18 +02:00
|
|
|
|
|
|
|
// Wait for all goroutines to finish
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
// Set the dimensions of the game map
|
2024-08-30 19:07:56 +02:00
|
|
|
gameMap.width = serverConfig.MapWidth
|
|
|
|
gameMap.height = serverConfig.MapHeight
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (gameMap *GameMap) render(camera *sdl.Rect, surface *sdl.Surface) {
|
|
|
|
fromX := camera.X
|
|
|
|
fromY := camera.Y
|
|
|
|
toX := camera.X + camera.W
|
|
|
|
toY := camera.Y + camera.H
|
2024-08-29 21:12:18 +02:00
|
|
|
|
|
|
|
// Create a WaitGroup to wait for all goroutines to finish
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
// Process columns instead of individual pixels
|
2024-08-29 00:05:28 +02:00
|
|
|
for x := fromX; x < toX; x++ {
|
2024-08-29 21:12:18 +02:00
|
|
|
// Increment the WaitGroup counter
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
// Launch a goroutine for each column
|
|
|
|
go func(x int32) {
|
|
|
|
defer wg.Done() // Decrement the counter when the goroutine completes
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 21:12:18 +02:00
|
|
|
for y := fromY; y < toY; y++ {
|
|
|
|
cameraY := y - camera.Y
|
|
|
|
cameraX := x - camera.X
|
|
|
|
pixelColor := gameMap.getTileColor(x, y)
|
|
|
|
surface.Set(int(cameraX), int(cameraY), pixelColor)
|
|
|
|
}
|
|
|
|
}(x)
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
2024-08-29 21:12:18 +02:00
|
|
|
// Wait for all goroutines to finish
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
func (gameMap *GameMap) checkCollision(posX, posY int32) uint8 {
|
|
|
|
//0 no collision
|
|
|
|
//1 destructible collision
|
|
|
|
//2 rock collision
|
|
|
|
//3 indestructible collision
|
2024-08-30 19:07:56 +02:00
|
|
|
if posX >= int32(gameMap.width) || posX < 0 || posY >= int32(gameMap.height) || posY < 0 {
|
2024-08-29 00:05:28 +02:00
|
|
|
return 3
|
|
|
|
}
|
|
|
|
switch gameMap.tiles[posX][posY] {
|
|
|
|
case 0:
|
|
|
|
return 0
|
|
|
|
case 1:
|
|
|
|
return 2
|
|
|
|
case 2:
|
|
|
|
return 1
|
|
|
|
case 3:
|
|
|
|
return 1
|
|
|
|
case 4:
|
|
|
|
return 3
|
|
|
|
case 5:
|
|
|
|
return 3
|
|
|
|
default:
|
|
|
|
return 3
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|