123 lines
3.4 KiB
GDScript
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
|