diff options
-rw-r--r-- | Chunk.tscn | 19 | ||||
-rw-r--r-- | ChunkGen.gd | 35 | ||||
-rw-r--r-- | ChunkLoader.gd | 66 | ||||
-rw-r--r-- | ChunkedCSGMesh.gd | 6 | ||||
-rw-r--r-- | ChunkedMeshInstance.gd | 6 | ||||
-rw-r--r-- | ChunkedSprite3D.gd | 6 | ||||
-rw-r--r-- | World.gd | 60 | ||||
-rw-r--r-- | World.tscn | 22 | ||||
-rw-r--r-- | project.godot | 4 |
9 files changed, 169 insertions, 55 deletions
@@ -1,33 +1,34 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=7 format=2] -[ext_resource path="res://Chunk.gd" type="Script" id=1] +[ext_resource path="res://ChunkedCSGMesh.gd" type="Script" id=3] [sub_resource type="SphereShape" id=1] radius = 50.0 -[sub_resource type="PlaneMesh" id=2] -size = Vector2( 100, 100 ) - [sub_resource type="SpatialMaterial" id=3] flags_unshaded = true params_cull_mode = 2 albedo_color = Color( 0.937255, 0, 1, 1 ) +[sub_resource type="PlaneMesh" id=2] +size = Vector2( 100, 100 ) + [sub_resource type="PlaneMesh" id=4] size = Vector2( 98, 98 ) [node name="Chunk" type="Area"] collision_layer = 32 collision_mask = 0 -script = ExtResource( 1 ) [node name="Size" type="CollisionShape" parent="."] shape = SubResource( 1 ) [node name="Border" type="CSGMesh" parent="."] -mesh = SubResource( 2 ) -material = SubResource( 3 ) +material_override = SubResource( 3 ) +script = ExtResource( 3 ) +_mesh = SubResource( 2 ) [node name="CSGMesh" type="CSGMesh" parent="Border"] operation = 2 -mesh = SubResource( 4 ) +script = ExtResource( 3 ) +_mesh = SubResource( 4 ) diff --git a/ChunkGen.gd b/ChunkGen.gd new file mode 100644 index 0000000..6e1f0eb --- /dev/null +++ b/ChunkGen.gd @@ -0,0 +1,35 @@ +extends Node + +var chunk_half_size setget _set_chunk_size +var chunk_size + +func _set_chunk_size(val): + chunk_half_size = val + chunk_size = val * 2.0 + +onready var noise = OpenSimplexNoise.new() + +func _ready(): + randomize() + noise.seed = randi() + noise.octaves = 4 + noise.period = 64 + noise.persistence = 0.001 + noise.lacunarity = 2.0 + +func gen_chunk(chunk): + var gen_tree = Spatial.new() + gen_tree.name = "gen_tree" + chunk.add_child(gen_tree) + +func v2_coords(coords:Vector3): + return Vector2(coords.x,coords.z) + +func v3_coords(coords:Vector2): + return Vector3(coords.x,0.0,coords.y) + +func iterate_chunk(chunk,step:Vector2,cb:FuncRef): + var chunk_size_rounded = Vector2(chunk_half_size,chunk_half_size).snapped(step) + for x in range(-chunk_size_rounded.x,chunk_size_rounded.x,step.x): + for y in range(-chunk_size_rounded.y,chunk_size_rounded.y,step.y): + cb.call_func(chunk,Vector2(x,y)) diff --git a/ChunkLoader.gd b/ChunkLoader.gd new file mode 100644 index 0000000..90cac4f --- /dev/null +++ b/ChunkLoader.gd @@ -0,0 +1,66 @@ +extends Node + +var world = null + +var Chunk = preload("res://Chunk.tscn") +var chunks = {} +var loaded_chunks = {} +var chunk_thread = Thread.new() +var mtx = Mutex.new() +var sgnl = Semaphore.new() +var exit = false +var chunk_to_load = null + +func _ready(): + chunk_thread.start(self, "chunk_loader") + +func _exit_tree(): + mtx.lock() + exit = true + sgnl.post() + mtx.unlock() + chunk_thread.wait_to_finish() + +func add_chunk(coords:Vector2): + chunks[coords] = coords.length() + +func chunk_update(): + var closest_unloaded_chunk = null + var closest_len = 0.0 + for chunk in chunks.keys(): + if !loaded_chunks.has(chunk): + if closest_unloaded_chunk == null || closest_len > chunks[chunk]: + closest_unloaded_chunk = chunk + closest_len = chunks[chunk] + if closest_unloaded_chunk != null: + mtx.lock() + if chunk_to_load == null: + chunk_to_load = closest_unloaded_chunk + sgnl.post() + mtx.unlock() + for chunk in loaded_chunks.keys(): + if !chunks.has(chunk): + var c = loaded_chunks[chunk].get_ref() + if c != null: + c.queue_free() + loaded_chunks.erase(chunk) + chunks = {} + +func chunk_loader(): + while true: + sgnl.wait() + mtx.lock() + var x = exit + var coords = chunk_to_load + chunk_to_load = null + mtx.unlock() + if x: + break + var chunk = Chunk.instance() + chunk.transform.origin = Vector3(coords.x,0.0,coords.y) + ChunkGen.gen_chunk(chunk) + self.call_deferred("finish_chunk", chunk) + +func finish_chunk(chunk): + world.get_node("Chunks").add_child(chunk) + loaded_chunks[Vector2(chunk.transform.origin.x,chunk.transform.origin.z)] = weakref(chunk) diff --git a/ChunkedCSGMesh.gd b/ChunkedCSGMesh.gd new file mode 100644 index 0000000..2b8c6db --- /dev/null +++ b/ChunkedCSGMesh.gd @@ -0,0 +1,6 @@ +extends CSGMesh + +export(Mesh) var _mesh + +func _ready(): + self.mesh = _mesh diff --git a/ChunkedMeshInstance.gd b/ChunkedMeshInstance.gd new file mode 100644 index 0000000..dde7eda --- /dev/null +++ b/ChunkedMeshInstance.gd @@ -0,0 +1,6 @@ +extends MeshInstance + +export(Mesh) var _mesh + +func _ready(): + self.mesh = _mesh diff --git a/ChunkedSprite3D.gd b/ChunkedSprite3D.gd new file mode 100644 index 0000000..c9e0be9 --- /dev/null +++ b/ChunkedSprite3D.gd @@ -0,0 +1,6 @@ +extends Sprite3D + +export(Texture) var _tex + +func _ready(): + self.texture = _tex @@ -4,45 +4,17 @@ export(NodePath) var traveler = null onready var _traveler = get_node(traveler) export var acceleration = 10.0 -onready var Chunk = preload("res://Chunk.tscn") -onready var chunk_size = $"Chunks/Chunk/Size".shape.radius*2.0 -var chunks = {} +onready var chunk_render_distance = $"ChunkRenderDistance/Radius".shape.radius -func v2_coords(coords:Vector3): - return Vector2(coords.x,coords.z) - -func v3_coords(coords:Vector2): - return Vector3(coords.x,0.0,coords.y) +onready var chunk_half_size = $"Chunks/Chunk/Size".shape.radius +onready var chunk_size = chunk_half_size * 2.0 -func chunk_coords(coords:Vector2): - return coords.snapped(Vector2(chunk_size,chunk_size)) - -func gen_chunk(coords:Vector2): - var chunk = Chunk.instance() - chunk.transform.origin = v3_coords(coords) - $"Chunks".add_child(chunk) - chunks[coords] = chunk - -func gen_chunks(): - var gen_center = -v2_coords($"Chunks".transform.origin) - var gen_radius = $"ChunkRenderDistance/Radius".shape.radius - var gen_radius_rounded = stepify(gen_radius, chunk_size) - for x in range(-gen_radius_rounded, gen_radius_rounded+chunk_size, chunk_size): - for y in range(-gen_radius_rounded, gen_radius_rounded+chunk_size, chunk_size): - var gen_coords = Vector2(x,y) - if gen_coords.length() > gen_radius: - continue - var coords = chunk_coords(gen_coords + gen_center) - if !chunks.has(coords): - gen_chunk(coords) +func _ready(): + ChunkLoader.world = self + ChunkGen.chunk_half_size = self.chunk_half_size func _on_ChunkRenderDistance_area_exited(area:Area): - gen_chunks() area.queue_free() - chunks.erase(v2_coords(area.transform.origin)) - -func _ready(): - gen_chunks() func travel(direction:Vector3): var heading = _traveler.global_transform.basis @@ -53,6 +25,26 @@ func travel(direction:Vector3): $"Chunks".add_central_force(direction*acceleration) func _physics_process(_state): + chunk_process() var stick = Input.get_axis("ship_down","ship_up") if stick != 0.0: self.travel(Vector3.FORWARD*stick) + +func v2_coords(coords:Vector3): + return Vector2(coords.x,coords.z) + +func chunk_coords(coords:Vector2): + return coords.snapped(Vector2(chunk_size,chunk_size)) + +func chunk_process(): + var gen_center = -v2_coords($"Chunks".transform.origin) + var gen_radius = chunk_render_distance + var gen_radius_rounded = stepify(gen_radius, chunk_size) + for x in range(-gen_radius_rounded, gen_radius_rounded+chunk_size, chunk_size): + for y in range(-gen_radius_rounded, gen_radius_rounded+chunk_size, chunk_size): + var gen_coords = Vector2(x,y) + if gen_coords.length() > gen_radius: + continue + var coords = chunk_coords(gen_coords + gen_center) + ChunkLoader.add_chunk(coords) + ChunkLoader.chunk_update() @@ -1,17 +1,24 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=9 format=2] [ext_resource path="res://World.gd" type="Script" id=1] [ext_resource path="res://Chunk.tscn" type="PackedScene" id=3] -[sub_resource type="BoxShape" id=23] - [sub_resource type="SphereShape" id=24] -radius = 300.0 +radius = 500.0 + +[sub_resource type="BoxShape" id=23] [node name="World" type="Spatial"] script = ExtResource( 1 ) acceleration = 50.0 +[node name="ChunkRenderDistance" type="Area" parent="."] +collision_layer = 0 +collision_mask = 32 + +[node name="Radius" type="CollisionShape" parent="ChunkRenderDistance"] +shape = SubResource( 24 ) + [node name="Chunks" type="RigidBody" parent="."] collision_layer = 0 collision_mask = 0 @@ -29,11 +36,4 @@ shape = SubResource( 23 ) visible = false collision_layer = 0 -[node name="ChunkRenderDistance" type="Area" parent="."] -collision_layer = 0 -collision_mask = 32 - -[node name="Radius" type="CollisionShape" parent="ChunkRenderDistance"] -shape = SubResource( 24 ) - [connection signal="area_exited" from="ChunkRenderDistance" to="." method="_on_ChunkRenderDistance_area_exited"] diff --git a/project.godot b/project.godot index 34e666b..a22cfe0 100644 --- a/project.godot +++ b/project.godot @@ -27,7 +27,8 @@ config/icon="res://icon.png" [autoload] Settings="*res://singletons/settings.gd" -WorldGenRNG="*res://WorldGenRNG.gd" +ChunkLoader="*res://ChunkLoader.gd" +ChunkGen="*res://ChunkGen.gd" [display] @@ -121,5 +122,6 @@ common/enable_pause_aware_picking=true [rendering] +threads/thread_model=2 quality/filters/msaa=3 environment/default_environment="res://default_env.tres" |