GodotShade/world.gd
2025-11-26 19:07:10 +01:00

123 lines
3.4 KiB
GDScript

@tool
extends Node3D
@export var clear_chunks: bool
@export var generate_chunks: bool
@export var chunk_size: int
@export var world_size: Vector3i
var chunks = {}
@export var world_seed: int
@export var noise_frequency: float
@export var noise_threshold: float
@export var cave_noise_frequency: float
@export var cave_noise_threshold: float
var noise
var cave_noise
var chunks_tagged_for_regen = []
var chunk_prototype = preload("res://chunk.tscn")
func _ready() -> void:
generate_chunks = true
func _process(_delta: float) -> void:
if clear_chunks:
clear_chunks = false
clearChunks()
if generate_chunks:
noise = FastNoiseLite.new()
noise.frequency = noise_frequency
noise.seed = world_seed
cave_noise = FastNoiseLite.new()
cave_noise.frequency = cave_noise_frequency
cave_noise.seed = world_seed
generateChunks()
generate_chunks = false
for chunk in chunks_tagged_for_regen:
chunk.generate_chunk()
chunks_tagged_for_regen.clear()
func clearChunks():
print("clearing chunk...")
var children = get_children()
for child in children:
child.free()
func generateChunks():
for x in range(world_size.x):
for y in range(world_size.y):
for z in range(world_size.z):
generateChunk(Vector3i(x * chunk_size, y * chunk_size, z * chunk_size))
await Engine.get_main_loop().process_frame
func generateChunk(pos: Vector3i):
var chunk = chunk_prototype.instantiate()
chunk.position = pos
add_child(chunk)
chunks[pos] = chunk
chunk.init_blocks(chunk_size, pos)
chunk.generate_chunk()
func SetBlockAtPosition(pos: Vector3i, block_type: Block.BlockType):
var chunk_pos = worldPosToChunkPos(pos)
var local_pos = pos - chunk_pos
if chunks.has(chunk_pos):
chunks[chunk_pos].SetBlockAtPosition(local_pos, block_type)
chunks_tagged_for_regen.append(chunks[chunk_pos])
var adjacent_chunks_masks = getAdjacentChunksFromBlockPos(local_pos)
for adjacent_chunk_mask in adjacent_chunks_masks:
var adjacent_chunk_pos = chunk_pos + adjacent_chunk_mask * chunk_size
if chunks.has(adjacent_chunk_pos):
chunks_tagged_for_regen.append(chunks[adjacent_chunk_pos])
func getAdjacentChunksFromBlockPos(pos: Vector3i):
var chunk_masks = []
#adjacent to chunk on left
if pos.x == 0:
chunk_masks.append(Vector3i(-1, 0, 0))
# chunk below
if pos.y == 0:
chunk_masks.append(Vector3i(0, -1, 0))
# chunk behind
if pos.z == 0:
chunk_masks.append(Vector3i(0, 0, -1))
# chunk on the right
if pos.x == chunk_size -1:
chunk_masks.append(Vector3i(1, 0, 0))
# chunk above
if pos.y == chunk_size -1:
chunk_masks.append(Vector3i(0, 1, 0))
# chunk on the right
if pos.z == chunk_size -1:
chunk_masks.append(Vector3i(0, 0, 1))
return chunk_masks
func worldPosToChunkPos(pos: Vector3i):
return (pos / chunk_size) * chunk_size
func GetBlock(pos: Vector3i, from_noise = false):
var chunk_pos = worldPosToChunkPos(pos)
var local_pos = pos - chunk_pos
# there is air at edges of world
if pos.x < 0 or pos.y < 0 or pos.z < 0 or pos.x >= world_size.x * chunk_size or pos.y >= world_size.y * chunk_size or pos.z >= world_size.z * chunk_size:
return Block.BlockType.Air
if not from_noise:
if chunks.has(chunk_pos):
return chunks[chunk_pos].GetBlockAtPosition(local_pos)
#
if ((noise.get_noise_2d(pos.x, pos.z) + 1) * chunk_size > pos.y + noise_threshold * 10) and (cave_noise.get_noise_3d(pos.x, pos.y, pos.z) > cave_noise_threshold):
return Block.BlockType.Dirt
else:
return Block.BlockType.Air