feat(world): voxel chunks + procedural underwater generation + biomes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Floppyrj45
2026-04-19 17:06:35 +02:00
parent 77b1df6060
commit 1c1ff67d88
6 changed files with 537 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
class_name WorldGenerator
const CHUNK_SIZE: int = 16
static func generate_chunk(chunk_x: int, chunk_y: int, chunk_z: int, seed: int) -> PackedInt32Array:
var data: PackedInt32Array = PackedInt32Array()
data.resize(4096)
var noise_surface: FastNoiseLite = FastNoiseLite.new()
noise_surface.seed = seed
noise_surface.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
noise_surface.frequency = 0.015
var noise_biome: FastNoiseLite = FastNoiseLite.new()
noise_biome.seed = seed + 1337
noise_biome.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
noise_biome.frequency = 0.004
var noise_detail: FastNoiseLite = FastNoiseLite.new()
noise_detail.seed = seed + 42
noise_detail.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH
noise_detail.frequency = 0.05
var noise_wreck: FastNoiseLite = FastNoiseLite.new()
noise_wreck.seed = seed + 999
noise_wreck.noise_type = FastNoiseLite.TYPE_CELLULAR
noise_wreck.frequency = 0.03
for lx: int in range(CHUNK_SIZE):
for lz: int in range(CHUNK_SIZE):
var wx: int = chunk_x * CHUNK_SIZE + lx
var wz: int = chunk_z * CHUNK_SIZE + lz
var surface_val: float = noise_surface.get_noise_2d(float(wx), float(wz))
var ground_height: int = int(-20.0 + surface_val * 20.0)
var biome_val: float = noise_biome.get_noise_2d(float(wx), float(wz))
var biome: int = _get_biome(biome_val, ground_height)
var wreck_val: float = noise_wreck.get_noise_2d(float(wx), float(wz))
var is_wreck_center: bool = wreck_val > 0.75
for ly: int in range(CHUNK_SIZE):
var wy: int = chunk_y * CHUNK_SIZE + ly
var idx: int = lx + ly * CHUNK_SIZE + lz * 256
data[idx] = _get_block_at(wy, ground_height, biome, wx, wz, lx, lz,
is_wreck_center, noise_detail, seed)
return data
static func _get_biome(biome_val: float, ground_height: int) -> int:
if biome_val > 0.5:
return 0
elif biome_val > 0.0:
return 1
elif biome_val > -0.5:
return 2
else:
return 3
static func _get_block_at(wy: int, ground_height: int, biome: int,
wx: int, wz: int, lx: int, lz: int,
is_wreck_center: bool, noise_detail: FastNoiseLite, seed: int) -> int:
if wy <= -60:
return BlockDatabase.BlockType.BEDROCK
if wy < ground_height - 5:
return BlockDatabase.BlockType.ROCK
if wy < ground_height:
return BlockDatabase.BlockType.SAND
if wy == ground_height:
return _surface_block(biome, wx, wz, noise_detail)
if wy == ground_height + 1:
return _decoration_block(biome, wx, wz, noise_detail, seed)
if wy > ground_height + 1 and wy <= ground_height + 6:
if biome == 1:
var kelp_height: int = _kelp_height(wx, wz, seed)
if wy <= ground_height + kelp_height:
return BlockDatabase.BlockType.KELP
if wy > 60:
return BlockDatabase.BlockType.AIR
if wy >= 58:
var ice_noise: float = noise_detail.get_noise_2d(float(wx) * 0.5, float(wz) * 0.5)
if ice_noise > 0.6:
return BlockDatabase.BlockType.ICE
return BlockDatabase.BlockType.WATER
if wy > ground_height:
if is_wreck_center and biome == 3:
var rel_y: int = wy - ground_height - 1
if rel_y >= 0 and rel_y < 3:
var rel_x: int = (wx % 5 + 5) % 5
var rel_z: int = (wz % 3 + 3) % 3
if rel_x < 5 and rel_z < 3:
if rel_y == 0 or rel_y == 2 or rel_x == 0 or rel_x == 4 or rel_z == 0 or rel_z == 2:
return BlockDatabase.BlockType.WRECK_WOOD
return BlockDatabase.BlockType.WATER
return BlockDatabase.BlockType.WATER
static func _surface_block(biome: int, wx: int, wz: int, noise_detail: FastNoiseLite) -> int:
match biome:
0:
return BlockDatabase.BlockType.SAND
1:
return BlockDatabase.BlockType.SAND
2:
return BlockDatabase.BlockType.ROCK
3:
return BlockDatabase.BlockType.SAND
_:
return BlockDatabase.BlockType.SAND
static func _decoration_block(biome: int, wx: int, wz: int, noise_detail: FastNoiseLite, seed: int) -> int:
match biome:
0:
var coral_noise: float = noise_detail.get_noise_2d(float(wx + seed % 100), float(wz + seed % 100))
if coral_noise > 0.4:
if (wx + wz) % 2 == 0:
return BlockDatabase.BlockType.CORAL_RED
else:
return BlockDatabase.BlockType.CORAL_BLUE
_:
pass
return BlockDatabase.BlockType.WATER
static func _kelp_height(wx: int, wz: int, seed: int) -> int:
var h: int = ((wx * 73856093) ^ (wz * 19349663) ^ seed) % 4
return 3 + h