diff --git a/project.godot b/project.godot index f7a4337..9e58484 100644 --- a/project.godot +++ b/project.godot @@ -19,6 +19,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://utils/camera/outline.gd" }, { +"base": "Spatial", +"class": "Chunk", +"language": "GDScript", +"path": "res://world/Chunk.gd" +}, { "base": "Reference", "class": "Delaunator", "language": "GDScript", @@ -52,6 +57,7 @@ _global_script_classes=[ { _global_script_class_icons={ "CameraController": "", "CameraOutline": "", +"Chunk": "", "Delaunator": "", "LoadingHelper": "", "PoissonDiscSampling": "", diff --git a/utils/world_generation/WorldGeneration.gd b/utils/world_generation/WorldGeneration.gd index 2543b7a..397edaa 100644 --- a/utils/world_generation/WorldGeneration.gd +++ b/utils/world_generation/WorldGeneration.gd @@ -260,7 +260,7 @@ func fill_oceans(): stack.append(first_center.get_index()) while stack.size(): - var current_point_id = stack.pop_back() + var current_point_id = stack.pop_front() Global.terrain.get_point(current_point_id).set_data("ocean", true) for neighbour in Global.terrain.get_point(current_point_id).points_around(): if neighbour.get_data("water") and not neighbour.get_data("ocean"): diff --git a/world/Chunk.gd b/world/Chunk.gd new file mode 100644 index 0000000..3db65f7 --- /dev/null +++ b/world/Chunk.gd @@ -0,0 +1,77 @@ +extends Spatial +class_name Chunk + +var noise +var should_remove = true +var x +var z +var empty = true + +func _init(x, z): + self.x = x + self.z = z + +func _ready(): + generate_chunk() + pass +func generate_chunk(): + var file = File.new() + file.open("res://world/materials/materials.json", File.READ) + var materials = JSON.parse(file.get_as_text()).result + + var st = SurfaceTool.new() + + st.begin(Mesh.PRIMITIVE_TRIANGLES) + var factor = Vector3(1, 120, 1) + # print(x) + # print(z) + for center in Global.terrain.get_chunk(Vector2(x, z)): + # print(center.get_data("water")) + if not center.get_data("water"): + empty = false + # print(center.get_data("material")) + var material_id = materials[center.get_data("material")] + var top_uv = Vector2(0, float(material_id) / (materials.size()-1)) + var border_uv = Vector2(1, float(material_id) / (materials.size()-1)) + + for edge in center.borders(): + if edge.end_center().get_elevation() < edge.start_center().get_elevation(): + var top = edge.start_center().get_elevation() + # if edge.start_center().get_data("ocean"): + # top = -1.0 + var bottom = edge.end_center().get_elevation() + if edge.end_center().get_data("ocean"): + bottom = 0.0 + st.add_uv(border_uv) + st.add_vertex(Vector3(edge.start_corner().point3d().x, bottom, edge.start_corner().point3d().z) * factor) + st.add_vertex(Vector3(edge.end_corner().point3d().x, top, edge.end_corner().point3d().z) * factor) + st.add_vertex(Vector3(edge.start_corner().point3d().x, top, edge.start_corner().point3d().z) * factor) + + st.add_vertex(Vector3(edge.start_corner().point3d().x, bottom, edge.start_corner().point3d().z) * factor) + st.add_vertex(Vector3(edge.end_corner().point3d().x, bottom, edge.end_corner().point3d().z) * factor) + st.add_vertex(Vector3(edge.end_corner().point3d().x, top, edge.end_corner().point3d().z) * factor) + + for corner_count in center.corners().size(): + var current_corner = center.corners()[corner_count] + var next_corner + if corner_count < center.corners().size() - 1: + next_corner = center.corners()[corner_count+1] + else: + next_corner = center.corners()[0] + + st.add_uv(Vector2(top_uv)) + st.add_vertex(Vector3(current_corner.point2d().x, center.get_elevation(), current_corner.point2d().y) * factor) + st.add_vertex(Vector3(next_corner.point2d().x, center.get_elevation(), next_corner.point2d().y) * factor) + st.add_vertex(Vector3(center.point2d().x, center.get_elevation(), center.point2d().y) * factor) + + if not empty: + st.generate_normals() + st.index() + + var mi = MeshInstance.new() + mi.mesh = st.commit() + var material = load("res://world/materials/world.material") + mi.set_surface_material(0, material) + mi.create_trimesh_collision() + mi.cast_shadow = GeometryInstance.SHADOW_CASTING_SETTING_ON + add_child(mi) diff --git a/world/World3d.gd b/world/World3d.gd index e7c5792..469051b 100644 --- a/world/World3d.gd +++ b/world/World3d.gd @@ -8,7 +8,8 @@ var unready_chunks = {} var thread func _ready(): - add_world() + # add_world() + thread = Thread.new() add_trees() func add_world(): @@ -40,3 +41,95 @@ func add_trees(): tree.rotate_y(rng.randi_range(0, 2*PI)) tree.translation = Vector3(point.x, center.get_elevation() * 120, point.y) add_child(tree) + + +func add_chunk(x, z): + var key = str(x) + "," + str(z) + if chunks.has(key) or unready_chunks.has(key): + return + + if not thread.is_active(): + thread.start(self, "load_chunk", [thread, x, z]) + unready_chunks[key] = 1 + +func load_chunk(array): + var thread = array[0] + var x = array[1] + var z = array[2] + + # print(x) + # print(z) + + var chunk = Chunk.new(x * chunk_size, z * chunk_size) + + # chunk.translation = Vector3(x * chunk_size, 0, z * chunk_size) + + call_deferred("load_done", chunk, thread) + +func load_done(chunk, thread): + add_child(chunk) + var key = str(chunk.x / chunk_size) + "," + str(chunk.z / chunk_size) + chunks[key] = chunk + unready_chunks.erase(key) + thread.wait_to_finish() + +func get_chunk(x, z): + var key = str(x) + "," + str(z) + if chunks.has(key): + return chunks.get(key) + + return null + +func _process(delta): + update_chunks() + clean_up_chunks() + reset_chunks() + +func update_chunks(): + var camera_translation = $CamBase/Camera.translation + var c_x = int(camera_translation.x) / chunk_size + var c_z = int(camera_translation.y) / chunk_size * -1 + + var stack = [] + var used = [] + + stack.append(Vector2(c_x, c_z)) + while stack.size(): + var current_vector = stack.pop_back() + used.append(current_vector) + add_chunk(current_vector.x, current_vector.y) + var chunk = get_chunk(current_vector.x, current_vector.y) + if chunk != null: + chunk.should_remove = false + + var neighbours = [ + Vector2(current_vector.x, current_vector.y - 1), # n + Vector2(current_vector.x + 1, current_vector.y - 1), # n_e + Vector2(current_vector.x + 1, current_vector.y), # e + Vector2(current_vector.x + 1, current_vector.y + 1), # s_e + Vector2(current_vector.x, current_vector.y + 1), # s + Vector2(current_vector.x - 1, current_vector.y + 1), # s_w + Vector2(current_vector.x - 1, current_vector.y), # w + Vector2(current_vector.x - 1, current_vector.y - 1) # n_w + ] + + for neighbour in neighbours: + if( + neighbour.x >= c_x - chunk_amount * 0.5 + and neighbour.x <= c_x + chunk_amount * 0.5 + and neighbour.y >= c_z - chunk_amount * 0.5 + and neighbour.y <= c_z + chunk_amount * 0.53 + and not neighbour in used + ): + stack.append(neighbour) + +func clean_up_chunks(): + for key in chunks: + var chunk = chunks[key] + if chunk.should_remove: + chunk.queue_free() + chunks.erase(key) + +func reset_chunks(): + for key in chunks: + chunks[key].should_remove = true