diff options
-rw-r--r-- | project.godot | 12 | ||||
-rw-r--r-- | world/World.gd | 4 | ||||
-rw-r--r-- | world/World.tscn | 7 | ||||
-rw-r--r-- | world/chunk/ChunkGen.gd | 51 | ||||
-rw-r--r-- | world/chunk/ChunkLoader.gd | 64 | ||||
-rw-r--r-- | world/monuments/Dock.tscn | 163 | ||||
-rw-r--r-- | world/monuments/DockMonument.gd | 19 | ||||
-rw-r--r-- | world/monuments/Monument.gd | 21 |
8 files changed, 306 insertions, 35 deletions
diff --git a/project.godot b/project.godot index 26f3e5b..67ac57f 100644 --- a/project.godot +++ b/project.godot @@ -9,12 +9,24 @@ config_version=4 _global_script_classes=[ { +"base": "Monument", +"class": "DockMonument", +"language": "GDScript", +"path": "res://world/monuments/DockMonument.gd" +}, { +"base": "Reference", +"class": "Monument", +"language": "GDScript", +"path": "res://world/monuments/Monument.gd" +}, { "base": "Resource", "class": "Wave", "language": "GDScript", "path": "res://water/Wave.gd" } ] _global_script_class_icons={ +"DockMonument": "", +"Monument": "", "Wave": "" } diff --git a/world/World.gd b/world/World.gd index 04c3ef1..3afc4eb 100644 --- a/world/World.gd +++ b/world/World.gd @@ -12,12 +12,12 @@ onready var lod_distance = chunk_render_distance.get_node("Radius").shape.radius onready var lod_mid = chunk_render_mid.get_node("Radius").shape.radius onready var lod_close = chunk_render_close.get_node("Radius").shape.radius -onready var chunk_half_size = $"Chunks/Chunk/Size".shape.radius +onready var chunk_half_size = $"Chunk/Size".shape.radius onready var chunk_size = chunk_half_size * 2.0 func _ready(): ChunkLoader.world = self - ChunkGen.chunk_half_size = self.chunk_half_size + ChunkGen.setup_monuments() func _on_ChunkRenderDistance_area_entered(area:Area): if area.lod < area.LOD.DISTANCE: diff --git a/world/World.tscn b/world/World.tscn index 647f47b..e5b4a67 100644 --- a/world/World.tscn +++ b/world/World.tscn @@ -39,6 +39,10 @@ collision_mask = 32 [node name="Radius" type="CollisionShape" parent="ChunkRenderClose"] shape = SubResource( 26 ) +[node name="Chunk" parent="." instance=ExtResource( 3 )] +visible = false +collision_layer = 0 + [node name="Chunks" type="RigidBody" parent="."] collision_layer = 0 collision_mask = 0 @@ -52,9 +56,6 @@ linear_damp = 0.5 [node name="CollisionShape" type="CollisionShape" parent="Chunks"] shape = SubResource( 23 ) -[node name="Chunk" parent="Chunks" instance=ExtResource( 3 )] -visible = false -collision_layer = 0 [connection signal="area_entered" from="ChunkRenderDistance" to="." method="_on_ChunkRenderDistance_area_entered"] [connection signal="area_exited" from="ChunkRenderDistance" to="." method="_on_ChunkRenderDistance_area_exited"] diff --git a/world/chunk/ChunkGen.gd b/world/chunk/ChunkGen.gd index e71cc57..994d624 100644 --- a/world/chunk/ChunkGen.gd +++ b/world/chunk/ChunkGen.gd @@ -1,16 +1,11 @@ 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() onready var rng = RandomNumberGenerator.new() var _seed +var monuments = [] + func _ready(): #randomize() #self._seed = randi() @@ -21,13 +16,36 @@ func _ready(): self.noise.persistence = 0 self.rng.seed = self._seed +func setup_monuments(): + monuments.push_back(DockMonument.new(Transform(Basis().rotated(Vector3.UP,0.0),Vector3(0.0,0.0,-600.0)))) + monuments.push_back(DockMonument.new(Transform(Basis().rotated(Vector3.UP,PI),Vector3(0.0,0.0,600.0)))) + func rng_2dv(coords:Vector2): self.rng.seed = hash(coords) -func gen_chunk(chunk): - gen_distance(chunk,chunk.get_node("gen_tree/lod_distance")) - gen_mid(chunk,chunk.get_node("gen_tree/lod_mid")) - gen_close(chunk,chunk.get_node("gen_tree/lod_close")) +func gen_chunk(chunk,dummy=false): + if dummy: + return + var monument = get_monument_at_chunk(ChunkLoader.v2_coords(chunk.transform.origin)) + if monument != null: + gen_monument(chunk, monument) + else: + gen_distance(chunk,chunk.get_node("gen_tree/lod_distance")) + gen_mid(chunk,chunk.get_node("gen_tree/lod_mid")) + gen_close(chunk,chunk.get_node("gen_tree/lod_close")) + +func get_monument_at_chunk(chunk_coords:Vector2): + for monument in monuments: + if monument.is_chunk_in_monument(chunk_coords): + return monument + return null + +func gen_monument(chunk, monument): + var offset_to_origin = monument.origin_chunk - ChunkLoader.v2_coords(chunk.transform.origin) + var inst = monument.scene.instance() + inst.transform.origin = ChunkLoader.v3_coords(offset_to_origin) + inst.transform.basis = monument.xform.basis + chunk.add_child(inst) func gen_distance(chunk,tree): gen_lowres_rocks(chunk,tree) @@ -38,13 +56,8 @@ func gen_mid(chunk,tree): func gen_close(chunk,tree): gen_rock_hitboxes(chunk,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,tree,step:Vector2,cb:FuncRef,data): + var chunk_half_size = ChunkLoader.world.chunk_half_size 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): @@ -81,9 +94,9 @@ func gen_rock_hitboxes(chunk,tree): iterate_chunk(chunk, tree, Vector2(20.0,20.0), funcref(self,"rock_rng"), [0.4,0.6,1.0,4.0,1.0,funcref(self,"make_rock_hitbox")]) func rock_rng(chunk,rocks,chunk_coords:Vector2,data): - var coords = v3_coords(chunk_coords) + var coords = ChunkLoader.v3_coords(chunk_coords) var basis = Basis() - var world_coords = chunk_coords + v2_coords(chunk.transform.origin) + var world_coords = chunk_coords + ChunkLoader.v2_coords(chunk.transform.origin) self.rng_2dv(world_coords) var rng_val = self.rng.randf_range(0.0,TAU) basis = Basis(Vector3.UP,rng_val) * basis diff --git a/world/chunk/ChunkLoader.gd b/world/chunk/ChunkLoader.gd index 42e40bb..0ea422a 100644 --- a/world/chunk/ChunkLoader.gd +++ b/world/chunk/ChunkLoader.gd @@ -4,12 +4,14 @@ var world = null var Chunk = preload("res://world/chunk/Chunk.tscn") var loaded_chunks = {} +var freed_chunks = {} var chunk_thread = Thread.new() var mtx = Mutex.new() var sgnl = Semaphore.new() var exit = false var chunk_to_load = null var chunk_to_len +var chunk_to_dummy func _ready(): chunk_thread.start(self, "chunk_loader") @@ -27,14 +29,29 @@ func v2_coords(coords:Vector3): func chunk_coords(coords:Vector2): return coords.snapped(Vector2(world.chunk_size,world.chunk_size)) +func v3_coords(coords:Vector2): + return Vector3(coords.x,0.0,coords.y) + func free_chunk(coords:Vector2): + var monument = ChunkGen.get_monument_at_chunk(coords) + if monument != null && monument.loaded_chunk != null && monument.loaded_chunk == coords: + return if !loaded_chunks.has(coords): return - var c = loaded_chunks[coords].get_ref() - if c != null: - c.queue_free() + freed_chunks[coords] = loaded_chunks[coords] loaded_chunks.erase(coords) +func clean_chunks(): + var cleaned = {} + for chunk in freed_chunks.keys(): + var c = freed_chunks[chunk].get_ref() + if c == null: + cleaned[chunk] = c + continue + c.queue_free() + for chunk in cleaned.keys(): + freed_chunks.erase(chunk) + func chunk_update(): var chunks = {} var gen_center = -v2_coords(world.get_node("Chunks").transform.origin) @@ -43,10 +60,11 @@ func chunk_update(): for x in range(-gen_radius_rounded, gen_radius_rounded+world.chunk_size, world.chunk_size): for y in range(-gen_radius_rounded, gen_radius_rounded+world.chunk_size, world.chunk_size): var gen_coords = Vector2(x,y) - if gen_coords.length() > gen_radius: + var coords_len = gen_coords.length() + if coords_len > gen_radius: continue var coords = chunk_coords(gen_coords + gen_center) - chunks[coords] = coords.length() + chunks[coords] = coords_len var closest_unloaded_chunk = null var closest_len = 0.0 for chunk in chunks.keys(): @@ -56,15 +74,30 @@ func chunk_update(): closest_unloaded_chunk = chunk closest_len = chunk_len if closest_unloaded_chunk != null: + var dummy = false + var monument = ChunkGen.get_monument_at_chunk(closest_unloaded_chunk) + if monument != null && monument.loaded_chunk != null: + dummy = true mtx.lock() if chunk_to_load == null: chunk_to_load = closest_unloaded_chunk chunk_to_len = closest_len + chunk_to_dummy = dummy sgnl.post() mtx.unlock() + for monument in ChunkGen.monuments: + if monument.loaded_chunk != null: + var loaded = false + for chunk in chunks.keys(): + if monument.chunks.has(chunk): + loaded = true + break + if !loaded: + monument.loaded_chunk = null for chunk in loaded_chunks.keys(): if !chunks.has(chunk): free_chunk(chunk) + clean_chunks() func chunk_loader(): while true: @@ -72,18 +105,27 @@ func chunk_loader(): mtx.lock() var x = exit var coords = chunk_to_load - var owo = chunk_to_len - chunk_to_load = null + var lod = chunk_to_len + var dummy = chunk_to_dummy mtx.unlock() if x: break var chunk = Chunk.instance() chunk.transform.origin = Vector3(coords.x,0.0,coords.y) - owo -= world.chunk_size - chunk.lod = 2 if owo <= world.lod_close else 1 if owo <= world.lod_mid else 0 - ChunkGen.gen_chunk(chunk) + lod -= world.chunk_size + var tmp = world.get_node("Chunk") + chunk.lod = tmp.LOD.CLOSE if lod <= world.lod_close else tmp.LOD.MID if lod <= world.lod_mid else tmp.LOD.DISTANCE + ChunkGen.gen_chunk(chunk,dummy) self.call_deferred("finish_chunk", chunk) func finish_chunk(chunk): + mtx.lock() + chunk_to_load = null + mtx.unlock() world.get_node("Chunks").add_child(chunk) - loaded_chunks[v2_coords(chunk.transform.origin)] = weakref(chunk) + var coords = v2_coords(chunk.transform.origin) + loaded_chunks[coords] = weakref(chunk) + var monument = ChunkGen.get_monument_at_chunk(coords) + if monument != null: + if monument.loaded_chunk == null: + monument.loaded_chunk = coords diff --git a/world/monuments/Dock.tscn b/world/monuments/Dock.tscn new file mode 100644 index 0000000..5a21576 --- /dev/null +++ b/world/monuments/Dock.tscn @@ -0,0 +1,163 @@ +[gd_scene load_steps=14 format=2] + +[sub_resource type="OpenSimplexNoise" id=1] +period = 128.0 +persistence = 1.0 +lacunarity = 4.0 + +[sub_resource type="NoiseTexture" id=2] +noise = SubResource( 1 ) + +[sub_resource type="NoiseTexture" id=3] +seamless = true +as_normalmap = true +noise = SubResource( 1 ) + +[sub_resource type="SpatialMaterial" id=4] +albedo_color = Color( 0.905882, 0.823529, 0.427451, 1 ) +albedo_texture = SubResource( 2 ) +emission_enabled = true +emission = Color( 0.905882, 0.823529, 0.427451, 1 ) +emission_energy = 0.2 +emission_operator = 0 +emission_on_uv2 = false +normal_enabled = true +normal_scale = 1.0 +normal_texture = SubResource( 3 ) +uv1_triplanar = true + +[sub_resource type="SphereMesh" id=5] +material = SubResource( 4 ) +radius = 50.0 +height = 50.0 + +[sub_resource type="SpatialMaterial" id=6] +emission_enabled = true +emission = Color( 1, 1, 1, 1 ) +emission_energy = 0.25 +emission_operator = 0 +emission_on_uv2 = false + +[sub_resource type="CubeMesh" id=7] +material = SubResource( 6 ) +size = Vector3( 150, 50, 100 ) + +[sub_resource type="Gradient" id=8] +interpolation_mode = 1 +offsets = PoolRealArray( 0.0724138, 0.52069 ) +colors = PoolColorArray( 1, 1, 1, 1, 0, 0, 0, 1 ) + +[sub_resource type="GradientTexture2D" id=9] +gradient = SubResource( 8 ) +width = 5 +height = 5 +fill = 1 +fill_from = Vector2( 0.5, 0.5 ) +repeat = 1 + +[sub_resource type="SpatialMaterial" id=10] +albedo_color = Color( 0.521569, 0.298039, 0.00392157, 1 ) +albedo_texture = SubResource( 9 ) +uv1_triplanar = true + +[sub_resource type="PrismMesh" id=11] +material = SubResource( 10 ) +size = Vector3( 150, 50, 100 ) + +[sub_resource type="CubeMesh" id=12] +material = SubResource( 10 ) +size = Vector3( 5, 50, 150 ) + +[sub_resource type="CubeMesh" id=13] +material = SubResource( 10 ) +size = Vector3( 100, 5, 30 ) + +[node name="Dock" type="Spatial"] + +[node name="Shore" type="Spatial" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -15, 0 ) + +[node name="MeshInstance" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -100, 0, 0 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance2" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 100, 0, 0 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance7" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -100, 0, 70 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance8" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 100, 0, 70 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance3" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -30, 0, -50 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance4" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 30, 0, -50 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance5" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -30, 0, -140 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance9" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -115, 0, -50 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance10" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -115, 0, -140 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance6" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 30, 0, -140 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance11" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 115, 0, -50 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="MeshInstance12" type="MeshInstance" parent="Shore"] +transform = Transform( -4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 115, 0, -140 ) +mesh = SubResource( 5 ) +skeleton = NodePath("../..") + +[node name="House" type="Spatial" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 25, -80 ) + +[node name="MeshInstance" type="MeshInstance" parent="House"] +mesh = SubResource( 7 ) + +[node name="MeshInstance2" type="MeshInstance" parent="House"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 50, 0 ) +mesh = SubResource( 11 ) + +[node name="Dock" type="Spatial" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -10, 50 ) + +[node name="MeshInstance" type="MeshInstance" parent="Dock"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 50, 0, 0 ) +mesh = SubResource( 12 ) + +[node name="MeshInstance2" type="MeshInstance" parent="Dock"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -50, 0, 0 ) +mesh = SubResource( 12 ) + +[node name="MeshInstance3" type="MeshInstance" parent="Dock"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5, -40 ) +mesh = SubResource( 13 ) diff --git a/world/monuments/DockMonument.gd b/world/monuments/DockMonument.gd new file mode 100644 index 0000000..2ac0c71 --- /dev/null +++ b/world/monuments/DockMonument.gd @@ -0,0 +1,19 @@ +extends Monument +class_name DockMonument + +var packed_scene = preload("res://world/monuments/Dock.tscn") + +func _init(xform:Transform).(xform,packed_scene,_chunks(),_origin()): + pass + +func _chunks(): + var chunk_size = ChunkLoader.world.chunk_size + var c = {} + var width = stepify(200.0,chunk_size) + for x in range(-width,width+chunk_size,chunk_size): + for y in range(-width,width+chunk_size,chunk_size): + c[Vector2(x,y)] = true + return c + +func _origin(): + return Vector2(0.0,0.0) diff --git a/world/monuments/Monument.gd b/world/monuments/Monument.gd new file mode 100644 index 0000000..86074f1 --- /dev/null +++ b/world/monuments/Monument.gd @@ -0,0 +1,21 @@ +class_name Monument + +var xform:Transform = Transform(Basis(),Vector3.ZERO) +var scene:PackedScene = null +var chunks = {} +var origin_chunk = Vector2.ZERO +var loaded_chunk = null + +func is_chunk_in_monument(chunk_coords:Vector2): + return self.chunks.has(chunk_coords) + +func _init(transform,scn,member_chunks, origin): + self.xform = transform + self.xform.origin = ChunkLoader.v3_coords(ChunkLoader.chunk_coords(ChunkLoader.v2_coords(self.xform.origin))) + self.scene = scn + var org = ChunkLoader.chunk_coords(ChunkLoader.v2_coords(self.xform.origin)) + for c in member_chunks.keys(): + var c2 = ChunkLoader.v2_coords(self.xform.basis * ChunkLoader.v3_coords(c)) + self.chunks[ChunkLoader.chunk_coords(c2)+org] = member_chunks[c] + origin = ChunkLoader.v2_coords(self.xform.basis * ChunkLoader.v3_coords(origin)) + self.origin_chunk = ChunkLoader.chunk_coords(origin)+org |