class_name Chunk extends Node3D var grid_position := Vector3i.ZERO var mesh: ArrayMesh = ArrayMesh.new() @export var noise: FastNoiseLite @export var blocks: Array = [] func generate_block_data(row: int, column: int, depth: int, empty: bool = false): grid_position = Vector3i(row, column, depth) blocks = [] blocks.resize(Global.CHUNK_SIZE.x * Global.CHUNK_SIZE.y * Global.CHUNK_SIZE.z) for x in Global.CHUNK_SIZE.x: for z in Global.CHUNK_SIZE.z: var block_position := Vector3i(x, 0, z) var block_global_position := Vector3i( grid_position.x * Global.CHUNK_SIZE.x + block_position.x, 0, grid_position.z * Global.CHUNK_SIZE.z + block_position.z ) var height := Global.CHUNK_SIZE.y if grid_position.y >= Global.GROUND_LEVEL: var noise_2d := noise.get_noise_2d( block_global_position.x, block_global_position.z ) * 100 height = round(clamp(abs(noise_2d), 0, Global.CHUNK_SIZE.y)) for y in Global.CHUNK_SIZE.y: block_position.y = y block_global_position. y = grid_position.y * Global.CHUNK_SIZE.y + block_position.y var value = noise.get_noise_3d( block_global_position.x, block_global_position.y, block_global_position.z ) * 100 var type := Block.Type.AIR if height < y: type = Block.Type.AIR else: if value > -15: type = Block.Type.GRASS elif value > -20: type = Block.Type.STONE #if value > 4: #type = Block.Type.GRASS #if value < -4: #type = Block.Type.STONE ##if value < -16: ##type = Block.Type.DIRT #if value < -17 and value > -20: #type = Block.Type.SAND #if abs(value) > 21 and abs(value) < 21.25: #type = [Block.Type.STONE, Block.Type.YELLOW_STONE, Block.Type.BLUE_STONE, Block.Type.RED_STONE, Block.Type.BLACK_STONE].pick_random() ##print(value) var block = Block.new() block.position = block_position block.global_position = block_global_position block.type = type if empty or Global.MAX_HEIGHT < block.global_position.y: block.type = Block.Type.AIR var index := x + Global.CHUNK_SIZE.x * y + Global.CHUNK_SIZE.x * Global.CHUNK_SIZE.y * z blocks[index] = block func generate_mesh(): var material := preload("res://new_shader_material.tres") var st = SurfaceTool.new() st.begin(Mesh.PRIMITIVE_TRIANGLES) st.set_material(material) for index in blocks.size(): var block: Block = blocks[index] if block.type == Block.Type.AIR: continue var block_front: Block if is_chunk_border_face(block.position, Block.Face.BACK): if chunk_exists(grid_position + Vector3i(0, 0, 1)): var chunk_front := Global.chunks[grid_position + Vector3i(0, 0, 1)] if chunk_front.is_inside_tree(): block_front = chunk_front.get_block(Vector3i(block.position.x, block.position.y, 0)) else: block_front = get_block(block.position + Vector3i(0, 0, 1)) var block_back: Block if is_chunk_border_face(block.position, Block.Face.FRONT): if chunk_exists(grid_position + Vector3i(0, 0, -1)): var chunk_back := Global.chunks[grid_position + Vector3i(0, 0, -1)] if chunk_back.is_inside_tree(): block_back = chunk_back.get_block(Vector3i( block.position.x, block.position.y, Global.CHUNK_SIZE.z - 1) ) else: block_back = get_block(block.position + Vector3i(0, 0, -1)) var block_right: Block if is_chunk_border_face(block.position, Block.Face.RIGHT): if chunk_exists(grid_position + Vector3i(1, 0, 0)): var chunk_right := Global.chunks[grid_position + Vector3i(1, 0, 0)] if chunk_right.is_inside_tree(): block_right = chunk_right.get_block(Vector3i(0, block.position.y, block.position.z)) else: block_right = get_block(block.position + Vector3i(1, 0, 0)) var block_left: Block if is_chunk_border_face(block.position, Block.Face.LEFT): if chunk_exists(grid_position + Vector3i(-1, 0, 0)): var chunk_left := Global.chunks[grid_position + Vector3i(-1, 0, 0)] if chunk_left.is_inside_tree(): block_left = chunk_left.get_block(Vector3i( Global.CHUNK_SIZE.x - 1, block.position.y, block.position.z) ) else: block_left = get_block(block.position + Vector3i(-1, 0, 0)) var block_top: Block if is_chunk_border_face(block.position, Block.Face.TOP): if chunk_exists(grid_position + Vector3i(0, 1, 0)): var chunk_top := Global.chunks[grid_position + Vector3i(0, 1, 0)] if chunk_top.is_inside_tree(): block_top = chunk_top.get_block(Vector3i(block.position.x, 0, block.position.z)) else: block_top = get_block(block.position + Vector3i(0, 1, 0)) var block_bottom: Block if is_chunk_border_face(block.position, Block.Face.BOTTOM): if chunk_exists(grid_position + Vector3i(0, -1, 0)): var chunk_bottom := Global.chunks[grid_position + Vector3i(0, -1, 0)] if chunk_bottom.is_inside_tree(): block_bottom = chunk_bottom.get_block(Vector3i( block.position.x, Global.CHUNK_SIZE.y - 1, block.position.z) ) else: block_bottom = get_block(block.position + Vector3i(0, -1, 0)) 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 elif block.type == Block.Type.DIRT: if not block_top or block_top.type == Block.Type.AIR: block.type = Block.Type.GRASS 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_back or block_back.type == Block.Type.AIR: block.add_face(st, Block.Face.BACK) if not block_right or block_right.type == Block.Type.AIR: block.add_face(st, Block.Face.RIGHT) 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 = st.commit() func update_mesh() -> void: $MeshInstance3D.mesh = mesh var shape := ConcavePolygonShape3D.new() var faces := mesh.get_faces() if faces.size() > 0: shape.set_faces(mesh.get_faces()) $StaticBody3D/CollisionShape3D.shape = shape func add_to(node: Node) -> void: name = "Chunk_%s_%s_%s" % [grid_position.x, grid_position.y, grid_position.z] node.add_child(self, true) update_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(block_position) block.global_position = Vector3i( grid_position.x * Global.CHUNK_SIZE.x + block.position.x, grid_position.y * Global.CHUNK_SIZE.y + block.position.y, grid_position.z * Global.CHUNK_SIZE.z + block.position.z ) block.type = block_type #blocks[block_position.x][block_position.y][block_position.z] = block set_block(block.position, 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 var block := get_block(block_position) block.type = Block.Type.AIR set_block(block.position, block) print(block_position) func get_block(p: Vector3i) -> Block: return blocks[p.x + Global.CHUNK_SIZE.x * p.y + Global.CHUNK_SIZE.x * Global.CHUNK_SIZE.y * p.z] func set_block(p: Vector3i, block: Block) -> void: blocks[p.x + Global.CHUNK_SIZE.x * p.y + Global.CHUNK_SIZE.x * Global.CHUNK_SIZE.y * p.z] = block static func chunk_exists(chunk_position: Vector3i): return Global.chunks.has(chunk_position) #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(p: Vector3i): return p.x == 0 or p.x == Global.CHUNK_SIZE.x - 1 or p.y == 0 or p.y == Global.CHUNK_SIZE.y - 1 or p.z == 0 or p.z == Global.CHUNK_SIZE.z - 1 func is_chunk_border_face(block_position: Vector3i, face: Block.Face) -> bool: if face == Block.Face.FRONT: return block_position.z == 0 elif face == Block.Face.BACK: return block_position.z == Global.CHUNK_SIZE.z - 1 elif face == Block.Face.LEFT: return block_position.x == 0 elif face == Block.Face.RIGHT: return block_position.x == Global.CHUNK_SIZE.z - 1 elif face == Block.Face.BOTTOM: return block_position.y == 0 elif face == Block.Face.TOP: return block_position.y == Global.CHUNK_SIZE.y - 1 return false func get_bordering_chunks(block_position: Vector3i) -> Array[Vector3i]: var bordering_chunks := [] as Array[Vector3i] if not is_chunk_border(block_position): return bordering_chunks if block_position.z == 0: bordering_chunks.append(grid_position + Vector3i(0, 0, -1)) elif block_position.z == Global.CHUNK_SIZE.z - 1: bordering_chunks.append(grid_position + Vector3i(0, 0, 1)) if block_position.x == 0: bordering_chunks.append(grid_position + Vector3i(-1, 0, 0)) elif block_position.x == Global.CHUNK_SIZE.x - 1: bordering_chunks.append(grid_position + Vector3i(1, 0, 0)) if block_position.y == 0: bordering_chunks.append(grid_position + Vector3i(0, -1, 0)) elif block_position.y == Global.CHUNK_SIZE.y - 1: bordering_chunks.append(grid_position + Vector3i(0, 1, 0)) return bordering_chunks func get_neighboring_blocks(_block_position: Vector3i) -> Array[Vector3i]: return [] @warning_ignore("shadowed_variable_base_class") static func global_to_chunk(global_position: Vector3, normal: Vector3) -> Vector3i: return floor((global_position - normal * (Block.BLOCK_SIZE * 0.5)) / Vector3(Global.CHUNK_SIZE)) @warning_ignore("shadowed_variable_base_class") static func global_to_chunk_block(global_position: Vector3, normal: Vector3) -> Vector3i: return global_to_block(global_position, normal) - Global.CHUNK_SIZE * global_to_chunk(global_position, normal) @warning_ignore("shadowed_variable_base_class") static func global_to_block(global_position: Vector3, normal: Vector3) -> Vector3i: return floor(global_position - normal * (Block.BLOCK_SIZE * 0.5))