package main import ( "github.com/aquilax/go-perlin" "github.com/veandco/go-sdl2/sdl" "image/color" "sync" "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) width uint32 height uint32 } 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 { if x < 0 || x >= int32(gameMap.width) || y < 0 || y >= int32(gameMap.height) { return GetTileColorValue(5) } else { tileValue := gameMap.tiles[x][y] return GetTileColorValue(tileValue) } } func (gameMap *GameMap) createGameMap(withData bool) { // Initialize the 2D slice for game tiles gameMap.tiles = make([][]uint8, serverConfig.MapWidth) // Create Perlin noise generators perlinNoiseRock := perlin.NewPerlin(2, 4, 8, time.Now().Unix()) perlinNoiseSoil := perlin.NewPerlin(2, 8, 4, time.Now().Unix()) // WaitGroup to synchronize goroutines var wg sync.WaitGroup // Loop over the rows for i := range gameMap.tiles { 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 } else { 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 } } } }(i) } else { for x := uint32(0); x < serverConfig.MapWidth; x++ { gameMap.tiles[x] = make([]uint8, serverConfig.MapHeight) } } } // Wait for all goroutines to finish wg.Wait() // Set the dimensions of the game map gameMap.width = serverConfig.MapWidth gameMap.height = serverConfig.MapHeight } 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 // Create a WaitGroup to wait for all goroutines to finish var wg sync.WaitGroup // Process columns instead of individual pixels for x := fromX; x < toX; x++ { // 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 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) } // Wait for all goroutines to finish wg.Wait() } func (gameMap *GameMap) checkCollision(posX, posY int32) uint8 { //0 no collision //1 destructible collision //2 rock collision //3 indestructible collision if posX >= int32(gameMap.width) || posX < 0 || posY >= int32(gameMap.height) || posY < 0 { 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 } }