class_name Chunk extends Node static var chunks: Array = [] const CHUNK_SIZE := Vector3i(16, 16, 16) var position := Vector3i.ZERO var mesh := MeshInstance3D.new() @export var noise: FastNoiseLite @export var blocks: Array = [] func generate_block_data(row: int, column: int, depth: int, empty: bool = false): position = Vector3i(row, column, depth) blocks = [] for x in CHUNK_SIZE.x: blocks.append([]) for y in CHUNK_SIZE.y: blocks[x].append([]) for z in CHUNK_SIZE.z: var block_position = Vector3i( position.x * CHUNK_SIZE.x + x, position.y * CHUNK_SIZE.y + y, position.z * CHUNK_SIZE.z + z )# * 2 var value = noise.get_noise_3d(block_position.x, block_position.y, block_position.z) * 100 var type = Block.Type.AIR if value > -15: type = Block.Type.GRASS elif value > -20: type = Block.Type.STONE var block = Block.new() block.position = block_position block.type = type if empty: block.type = Block.Type.AIR blocks[x][y].append(block) func generate_mesh() -> MeshInstance3D: var material := preload("res://new_shader_material.tres") var st = SurfaceTool.new() st.begin(Mesh.PRIMITIVE_TRIANGLES) st.set_material(material) for x in blocks.size(): for y in blocks[x].size(): for z in blocks[x][y].size(): var block: Block = blocks[x][y][z] var block_front: Block if block_exists(x, y, z + 1): block_front = blocks[x][y][z + 1] elif is_chunk_border(x, y, z) and chunk_exists(position.x, position.y, position.z + 1): block_front = chunks[position.x][position.y][position.z + 1].blocks[x][y][0] var block_back: Block if block_exists(x, y, z - 1): block_back = blocks[x][y][z - 1] elif is_chunk_border(x, y, z) and chunk_exists(position.x, position.y, position.z - 1): block_back = chunks[position.x][position.y][position.z - 1].blocks[x][y][CHUNK_SIZE.z - 1] var block_left: Block if block_exists(x - 1, y, z): block_left = blocks[x - 1][y][z] elif is_chunk_border(x, y, z) and chunk_exists(position.x - 1, position.y, position.z): block_left = chunks[position.x - 1][position.y][position.z].blocks[CHUNK_SIZE.x - 1][y][z] var block_right: Block if block_exists(x + 1, y, z): block_right = blocks[x + 1][y][z] elif is_chunk_border(x, y, z) and chunk_exists(position.x + 1, position.y, position.z): block_right = chunks[position.x + 1][position.y][position.z].blocks[0][y][z] var block_top: Block if block_exists(x, y + 1, z): block_top = blocks[x][y + 1][z] elif is_chunk_border(x, y, z) and chunk_exists(position.x, position.y + 1, position.z): block_top = chunks[position.x][position.y + 1][position.z].blocks[x][0][z] var block_bottom: Block if block_exists(x, y - 1, z): block_bottom = blocks[x][y - 1][z] elif is_chunk_border(x, y, z) and chunk_exists(position.x, position.y - 1, position.z): block_bottom = chunks[position.x][position.y - 1][position.z].blocks[x][CHUNK_SIZE.y - 1][z] if not block.type == Block.Type.AIR: if block.type == Block.Type.GRASS: if block_top and block_top.type != Block.Type.AIR: block.type = Block.Type.DIRT var rng = RandomNumberGenerator.new() rng.seed = randi() st.set_color(Color(rng.randf(), rng.randf(), rng.randf())) st.set_uv(Vector2(0, 0)) if not block_front or block_front.type == Block.Type.AIR: block.add_face(st, Block.Face.FRONT) if not block_right or block_right.type == Block.Type.AIR: block.add_face(st, Block.Face.RIGHT) if not block_back or block_back.type == Block.Type.AIR: block.add_face(st, Block.Face.BACK) if not block_left or block_left.type == Block.Type.AIR: block.add_face(st, Block.Face.LEFT) if not block_top or block_top.type == Block.Type.AIR: block.add_face(st, Block.Face.TOP) if not block_bottom or block_bottom.type == Block.Type.AIR: block.add_face(st, Block.Face.BOTTOM) #st.generate_normals() #mesh = MeshInstance3D.new() mesh.mesh = st.commit() for child in mesh.get_children(): child.queue_free() mesh.create_trimesh_collision.call_deferred() mesh.set_meta("chunk", self) return mesh func generate_chunk(row: int, column: int, depth: int): if blocks.is_empty(): generate_block_data(row, column, depth) generate_mesh() func add_block(block_position: Vector3, block_type: Block.Type = Block.Type.GRASS) -> void: var block = Block.new() block.position = Vector3i( position.x * CHUNK_SIZE.x + block_position.x, position.y * CHUNK_SIZE.y + block_position.y, position.z * CHUNK_SIZE.z + block_position.z ) block.type = block_type blocks[block_position.x][block_position.y][block_position.z] = block generate_mesh.call_deferred() func remove_block(block_position: Vector3) -> void: blocks[block_position.x][block_position.y][block_position.z].type = Block.Type.AIR generate_mesh.call_deferred() static func chunk_exists(x: int, y: int, z: int): return x >= 0 and chunks.size() - 1 >= x and y >= 0 and chunks[x].size() - 1 >= y and z >= 0 and chunks[x][y].size() - 1 >= z func block_exists(x: int, y: int, z: int): return x >= 0 and blocks.size() - 1 >= x and y >= 0 and blocks[x].size() - 1 >= y and z >= 0 and blocks[x][y].size() - 1 >= z func is_chunk_border(x: int, y: int, z: int): return x == 0 or x == CHUNK_SIZE.x - 1 or y == 0 or y == CHUNK_SIZE.y - 1 or z == 0 or z == CHUNK_SIZE.z - 1 static func global_to_chunk(global_position: Vector3) -> Vector3i: return floor(global_position / Vector3(CHUNK_SIZE)) static func global_to_chunk_block(global_position: Vector3) -> Vector3i: return global_to_block(global_position) - CHUNK_SIZE * global_to_chunk(global_position) static func global_to_block(global_position: Vector3) -> Vector3i: return floor(global_position)