feat: Enhance terrain generation with new types and drawing mechanics

This commit is contained in:
Kacper Kostka (aider)
2025-04-02 12:18:52 +02:00
parent 3fa8a695b3
commit a4ef5e0f40
5 changed files with 264 additions and 17 deletions

View File

@@ -90,6 +90,9 @@ class Perlin {
// Terrain types
const TERRAIN_WATER = 0;
const TERRAIN_GRASS = 1;
const TERRAIN_SAND = 2;
const TERRAIN_DIRT = 3;
const TERRAIN_STONE = 4;
// Generate terrain map
function generateTerrain(width, height, scale) {
@@ -108,30 +111,113 @@ function generateTerrain(width, height, scale) {
value += 0.25 * perlin.noise(nx * 4, ny * 4);
value /= 1.75; // Normalize
// Generate a second noise value for stone distribution
let stoneNoise = perlin.noise(nx * 3, ny * 3);
// Determine terrain type based on noise value
// Lower water threshold to create more land areas
if (value < -0.3) { // Changed from 0.0 to -0.3 to reduce water
// Adjusted to get more water
if (value < -0.2) { // More water
terrain[x][y] = TERRAIN_WATER;
} else {
// Check for sand near water (beach)
let sandCheck = perlin.noise((nx + 0.1) * 8, (ny + 0.1) * 8);
if (value > -0.25 && sandCheck > 0) {
terrain[x][y] = TERRAIN_SAND;
}
} else if (value < 0.0) {
// Sand appears near water
terrain[x][y] = TERRAIN_SAND;
} else if (value < 0.3) {
// Grass in middle elevations
terrain[x][y] = TERRAIN_GRASS;
} else if (stoneNoise > 0.3) {
// Stone in higher elevations with specific noise pattern
terrain[x][y] = TERRAIN_STONE;
} else {
// Dirt in higher elevations
terrain[x][y] = TERRAIN_DIRT;
}
}
}
// Second pass to smooth terrain and create better beaches
smoothTerrain(terrain, width, height);
return terrain;
}
function smoothTerrain(terrain, width, height) {
// Create sand around water
for (let x = 1; x < width - 1; x++) {
for (let y = 1; y < height - 1; y++) {
if (terrain[x][y] !== TERRAIN_WATER) {
// Check if adjacent to water
let adjacentToWater = false;
for (let dx = -1; dx <= 1; dx++) {
for (let dy = -1; dy <= 1; dy++) {
if (x + dx >= 0 && x + dx < width && y + dy >= 0 && y + dy < height) {
if (terrain[x + dx][y + dy] === TERRAIN_WATER) {
adjacentToWater = true;
break;
}
}
}
if (adjacentToWater) break;
}
// If adjacent to water and not already sand, make it sand
if (adjacentToWater && terrain[x][y] !== TERRAIN_SAND && Math.random() > 0.3) {
terrain[x][y] = TERRAIN_SAND;
}
}
}
}
}
// Check if a position is in water
function isWater(x, y) {
return getTerrainType(x, y) === TERRAIN_WATER;
}
// Get terrain type at a position
function getTerrainType(x, y) {
// Convert world coordinates to terrain grid coordinates
const gridX = Math.floor((x + 2000) / 10);
const gridY = Math.floor((y + 2000) / 10);
// Check bounds
if (gridX < 0 || gridX >= terrainWidth || gridY < 0 || gridY >= terrainHeight) {
return false; // Default to land if out of bounds
return TERRAIN_GRASS; // Default to grass if out of bounds
}
return terrainMap[gridX][gridY] === TERRAIN_WATER;
return terrainMap[gridX][gridY];
}
// Set terrain type at a position
function setTerrainType(x, y, type) {
// Convert world coordinates to terrain grid coordinates
const gridX = Math.floor((x + 2000) / 10);
const gridY = Math.floor((y + 2000) / 10);
// Check bounds
if (gridX < 0 || gridX >= terrainWidth || gridY < 0 || gridY >= terrainHeight) {
return false; // Can't set if out of bounds
}
terrainMap[gridX][gridY] = type;
return true;
}
// Get terrain name from type
function getTerrainName(type) {
switch(type) {
case TERRAIN_WATER: return "Water";
case TERRAIN_GRASS: return "Grass";
case TERRAIN_SAND: return "Sand";
case TERRAIN_DIRT: return "Dirt";
case TERRAIN_STONE: return "Stone";
default: return "Unknown";
}
}
// Terrain dimensions