Tree collisions and highlights

This commit is contained in:
Dan Baker 2025-06-26 18:28:33 +01:00
parent 57602adddb
commit 7255cbdf64
17 changed files with 231 additions and 2251 deletions

View file

@ -1,14 +1,12 @@
[gd_scene load_steps=16 format=3 uid="uid://bwcevwwphdvq"] [gd_scene load_steps=14 format=3 uid="uid://bwcevwwphdvq"]
[ext_resource type="Script" uid="uid://bq7hia2dit80y" path="res://Entities/GroundTile/ground_tile.gd" id="1_uwxqs"] [ext_resource type="Script" uid="uid://bq7hia2dit80y" path="res://Entities/GroundTile/ground_tile.gd" id="1_uwxqs"]
[ext_resource type="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"] [ext_resource type="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"]
[ext_resource type="Script" uid="uid://cacp8ncwuofuj" path="res://Entities/GroundTile/scripts/grass.gd" id="3_224hx"] [ext_resource type="Script" uid="uid://cacp8ncwuofuj" path="res://Entities/GroundTile/scripts/grass.gd" id="3_224hx"]
[ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="3_f37ob"] [ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="3_f37ob"]
[ext_resource type="Script" uid="uid://btju6b83mvgvk" path="res://Entities/GroundTile/scripts/grass_multimesh.gd" id="4_3wpcb"] [ext_resource type="Script" uid="uid://btju6b83mvgvk" path="res://Entities/GroundTile/scripts/grass_multimesh.gd" id="4_3wpcb"]
[ext_resource type="PackedScene" uid="uid://dgvycnw8hpebx" path="res://Entities/Tree/assets/tree-tall.glb" id="6_7lc7k"]
[ext_resource type="Script" uid="uid://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"] [ext_resource type="Script" uid="uid://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"]
[ext_resource type="PackedScene" uid="uid://bwhpbjdyl577e" path="res://Entities/Tree/assets/tree.glb" id="8_ot4p5"] [ext_resource type="PackedScene" uid="uid://c27fogucecn0r" path="res://Entities/Tree/Tree.tscn" id="7_224hx"]
[ext_resource type="PackedScene" uid="uid://bwdibgbi3ycqn" path="res://Entities/Tree/assets/tree-autumn-tall.glb" id="12_4hjaq"]
[sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"] [sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"]
viewport_path = NodePath("DebugText/DebugTextViewport") viewport_path = NodePath("DebugText/DebugTextViewport")
@ -33,6 +31,7 @@ flip_faces = true
script = ExtResource("1_uwxqs") script = ExtResource("1_uwxqs")
[node name="DebugText" type="Node3D" parent="."] [node name="DebugText" type="Node3D" parent="."]
visible = false
[node name="DebugTextViewport" type="SubViewport" parent="DebugText"] [node name="DebugTextViewport" type="SubViewport" parent="DebugText"]
size = Vector2i(50, 50) size = Vector2i(50, 50)
@ -72,4 +71,4 @@ mesh = SubResource("PlaneMesh_f37ob")
[node name="Trees" type="Node3D" parent="."] [node name="Trees" type="Node3D" parent="."]
script = ExtResource("7_7lc7k") script = ExtResource("7_7lc7k")
tree_scenes = Array[PackedScene]([ExtResource("8_ot4p5"), ExtResource("6_7lc7k"), ExtResource("12_4hjaq"), ExtResource("8_ot4p5"), ExtResource("8_ot4p5"), ExtResource("8_ot4p5"), ExtResource("8_ot4p5")]) tree_scenes = Array[PackedScene]([ExtResource("7_224hx")])

View file

@ -1,7 +1,5 @@
# GroundTile.gd
class_name GroundTile class_name GroundTile
extends Node3D extends Node3D
@onready var debug_text: Label = $DebugText/DebugTextViewport/DebugTextLabel @onready var debug_text: Label = $DebugText/DebugTextViewport/DebugTextLabel
@onready var tree_spawner = $Trees @onready var tree_spawner = $Trees
@onready var grass_spawner = $Grass @onready var grass_spawner = $Grass
@ -9,17 +7,22 @@ var grid_x: int
var grid_z: int var grid_z: int
var cell_info: CellDataResource = null var cell_info: CellDataResource = null
var spawners_ready: bool = false var spawners_ready: bool = false
var cached_rng: RandomClass = null
var rng: RandomClass = RandomClass.new()
func _ready() -> void: func _ready() -> void:
spawners_ready = true spawners_ready = true
# Now that spawners are ready, trigger spawning if we have cell_info
if cell_info != null: if cell_info != null:
spawn_content() spawn_content()
update_text_label() update_text_label()
rng.set_seed(cell_info.cell_seed)
func get_rng() -> RandomClass:
if cached_rng == null and cell_info:
cached_rng = RandomClass.get_seeded_instance(cell_info.cell_seed)
elif cached_rng == null:
cached_rng = RandomClass.get_shared_instance()
return cached_rng
func set_grid_location(x, z) -> void: func set_grid_location(x, z) -> void:
grid_x = x grid_x = x

View file

@ -21,14 +21,16 @@ func spawn_grass_for_cell(value):
grass_multimesh.setup_multimesh() grass_multimesh.setup_multimesh()
func update_grass_density() -> void: func update_grass_density() -> void:
if parent_node == null or parent_node.rng == null: if parent_node == null:
return return
var rng = parent_node.get_rng()
if grass_density > 0.8: if grass_density > 0.8:
grass_instance_range = parent_node.rng.randi_range(100, 500) grass_instance_range = rng.randi_range(100, 500)
elif grass_density > 0.6: elif grass_density > 0.6:
grass_instance_range = parent_node.rng.randi_range(30, 50) grass_instance_range = rng.randi_range(30, 50)
elif grass_density > 0.3: elif grass_density > 0.3:
grass_instance_range = parent_node.rng.randi_range(5, 20) grass_instance_range = rng.randi_range(5, 20)
else: else:
grass_instance_range = parent_node.rng.randi_range(0, 1) grass_instance_range = rng.randi_range(0, 1)

View file

@ -1,7 +1,6 @@
extends MultiMeshInstance3D extends MultiMeshInstance3D
var mm: MultiMesh var mm: MultiMesh
var parent_node: GrassController var parent_node: GrassController
static var grass_mesh: Mesh = null static var grass_mesh: Mesh = null
func _ready() -> void: func _ready() -> void:
@ -30,18 +29,21 @@ func setup_multimesh() -> void:
# Configure instance count # Configure instance count
mm.instance_count = parent_node.grass_instance_range mm.instance_count = parent_node.grass_instance_range
# Get shared RNG from GroundTile
var rng = parent_node.parent_node.get_rng()
# Generate positions using shared RNG # Generate positions using shared RNG
for i in range(mm.instance_count): for i in range(mm.instance_count):
var random_pos = Vector3( var random_pos = Vector3(
parent_node.parent_node.rng.randf_range(-1.0, 1.0), rng.randf_range(-1.0, 1.0),
0.0, 0.0,
parent_node.parent_node.rng.randf_range(-1.0, 1.0) rng.randf_range(-1.0, 1.0)
) )
var random_rotation = parent_node.parent_node.rng.randf_range(0.0, TAU) var random_rotation = rng.randf_range(0.0, TAU)
var basis = Basis(Vector3.UP, random_rotation) var basis = Basis(Vector3.UP, random_rotation)
var random_scale = parent_node.parent_node.rng.randf_range(0.05, 0.3) var random_scale = rng.randf_range(0.05, 0.3)
basis = basis.scaled(Vector3(random_scale, random_scale, random_scale)) basis = basis.scaled(Vector3(random_scale, random_scale, random_scale))
var tx = Transform3D(basis, random_pos) var tx = Transform3D(basis, random_pos)

View file

@ -13,27 +13,12 @@ func spawn_trees_for_cell(cell_info: CellDataResource):
if not cell_info: if not cell_info:
return return
# Use parent's RNG instead of creating new one if not parent_ground_tile:
if not parent_ground_tile or not parent_ground_tile.rng:
return return
var tree_count = max(0, cell_info.trees.size()) var tree_count = max(0, cell_info.trees.size())
spawn_trees(tree_count) spawn_trees(tree_count)
# Update all rng calls to use parent_ground_tile.rng:
func get_random_position() -> Vector3:
var x = parent_ground_tile.rng.randf_range(-spawn_area_size.x / 2, spawn_area_size.x / 2)
var z = parent_ground_tile.rng.randf_range(-spawn_area_size.y / 2, spawn_area_size.y / 2)
return Vector3(x, 0, z)
func spawn_tree_at_position(pos: Vector3):
var random_index = parent_ground_tile.rng.randi() % tree_scenes.size()
var random_tree_scene = tree_scenes[random_index]
var tree_instance = random_tree_scene.instantiate()
add_child(tree_instance)
tree_instance.position = pos
tree_instance.rotation.y = parent_ground_tile.rng.randf() * TAU
func spawn_trees(tree_count: int): func spawn_trees(tree_count: int):
if tree_scenes.is_empty() or tree_count == 0: if tree_scenes.is_empty() or tree_count == 0:
return return
@ -56,6 +41,21 @@ func spawn_trees(tree_count: int):
attempts += 1 attempts += 1
func get_random_position() -> Vector3:
var rng = parent_ground_tile.get_rng()
var x = rng.randf_range(-spawn_area_size.x / 2, spawn_area_size.x / 2)
var z = rng.randf_range(-spawn_area_size.y / 2, spawn_area_size.y / 2)
return Vector3(x, 0, z)
func spawn_tree_at_position(pos: Vector3):
var rng = parent_ground_tile.get_rng()
var random_index = rng.randi() % tree_scenes.size()
var random_tree_scene = tree_scenes[random_index]
var tree_instance = random_tree_scene.instantiate()
add_child(tree_instance)
tree_instance.position = pos
tree_instance.rotation.y = rng.randf() * TAU
func is_position_valid(pos: Vector3) -> bool: func is_position_valid(pos: Vector3) -> bool:
for existing_pos in spawned_positions: for existing_pos in spawned_positions:
if pos.distance_to(existing_pos) < min_distance: if pos.distance_to(existing_pos) < min_distance:

25
Entities/Tree/Tree.tscn Normal file
View file

@ -0,0 +1,25 @@
[gd_scene load_steps=5 format=3 uid="uid://c27fogucecn0r"]
[ext_resource type="Script" uid="uid://lcedx3lau6v5" path="res://Entities/Tree/scripts/tree.gd" id="1_702jv"]
[ext_resource type="PackedScene" uid="uid://bwhpbjdyl577e" path="res://Entities/Tree/assets/tree.glb" id="1_s6kdm"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_s6kdm"]
radius = 0.2
height = 0.5
[sub_resource type="SphereShape3D" id="SphereShape3D_702jv"]
[node name="Tree" type="Node3D"]
script = ExtResource("1_702jv")
[node name="TreeModel" parent="." instance=ExtResource("1_s6kdm")]
[node name="TreeCollision" type="StaticBody3D" parent="TreeModel" groups=["tree"]]
[node name="CollisionShape3D" type="CollisionShape3D" parent="TreeModel/TreeCollision"]
shape = SubResource("CapsuleShape3D_s6kdm")
[node name="InteractRange" type="Area3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractRange"]
shape = SubResource("SphereShape3D_702jv")

View file

@ -0,0 +1,89 @@
class_name TreeNode
extends Node3D
@onready var area: Area3D = $InteractRange
var mesh_instances: Array[MeshInstance3D] = []
var original_materials: Array[Material] = []
var outline_material: Material
var base_circle: MeshInstance3D
var circle_material: Material
func _ready():
create_base_circle()
# Find all MeshInstance3D nodes in the GLB
find_all_mesh_instances(self)
setup_outline_material()
area.body_entered.connect(_on_player_entered)
area.body_exited.connect(_on_player_exited)
func setup_outline_material():
if mesh_instances.is_empty():
print("Warning: No MeshInstance3D found in GLB!")
return
# Store original materials
for mesh in mesh_instances:
if mesh.get_surface_override_material(0):
original_materials.append(mesh.get_surface_override_material(0))
else:
original_materials.append(mesh.get_surface_override_material(0))
# Create outline material with your shader
outline_material = ShaderMaterial.new()
outline_material.shader = preload("res://outline.gdshader")
outline_material.set_shader_parameter("color", Vector3(0.702, 0.557, 0.259))
func find_all_mesh_instances(node: Node):
if node is MeshInstance3D:
mesh_instances.append(node)
for child in node.get_children():
find_all_mesh_instances(child)
func create_base_circle():
base_circle = MeshInstance3D.new()
add_child(base_circle)
# Create a flat cylinder for the circle
var cylinder = CylinderMesh.new()
cylinder.top_radius = 0.4 # Adjust size as needed
cylinder.bottom_radius = 0.4
cylinder.height = 0.02 # Very thin to make it look like a flat circle
cylinder.rings = 1
cylinder.radial_segments = 9 # More segments = smoother circle
base_circle.mesh = cylinder
# Create transparent material with outline
circle_material = StandardMaterial3D.new()
circle_material.flags_transparent = true
circle_material.albedo_color = Color(1.0, 0.843, 0.0, 0.0) # Fully transparent gold
# Add rim lighting effect for outline appearance
circle_material.rim_enabled = true
circle_material.rim = 1.0
circle_material.rim_tint = 1.0
circle_material.rim_color = Color(1.0, 0.843, 0.0) # Gold rim
base_circle.material_override = circle_material
# Position at ground level
base_circle.position.y = 0.01 # Slightly above ground to avoid z-fighting
# Start hidden
base_circle.visible = false
func _on_player_entered(body: Node3D):
if body.is_in_group("player"):
base_circle.visible = true
# Apply outline to all mesh instances
for mesh in mesh_instances:
mesh.material_overlay = outline_material
func _on_player_exited(body: Node3D):
if body.is_in_group("player"):
Log.pr('Out of range...')
base_circle.visible = false
# Remove outline from all mesh instances
for mesh in mesh_instances:
mesh.material_overlay = null

View file

@ -0,0 +1 @@
uid://lcedx3lau6v5

View file

@ -22,6 +22,6 @@ static func generate_cell(x: int, z: int, density: float, path: bool = false, wa
if not (path or water): if not (path or water):
if density >= 0.6: if density >= 0.6:
cell_data.add_trees(int(density * 10 / 3)) cell_data.add_trees(int(density * 10 / 2))
Global.map_data[x][z] = cell_data Global.map_data[x][z] = cell_data

View file

@ -1,14 +1,36 @@
extends Node extends Node
class_name RandomClass class_name RandomClass
var _rng: RandomNumberGenerator = RandomNumberGenerator.new() var _rng: RandomNumberGenerator = RandomNumberGenerator.new()
# Static shared instance for all tiles to use
static var shared_instance: RandomClass = null
func _ready(): func _ready():
randomize() randomize()
# Initialize shared instance if it doesn't exist
if shared_instance == null:
shared_instance = RandomClass.new()
# Static method to get the shared instance with a specific seed
static func get_seeded_instance(seed_value: int) -> RandomClass:
if shared_instance == null:
shared_instance = RandomClass.new()
shared_instance.set_seed(seed_value)
return shared_instance
# Static method to get the shared instance (without changing seed)
static func get_shared_instance() -> RandomClass:
if shared_instance == null:
shared_instance = RandomClass.new()
return shared_instance
# Set a specific seed for reproducible results # Set a specific seed for reproducible results
func set_seed(seed_value: int) -> void: func set_seed(seed_value: int) -> void:
#Log.pr('Seeded RNG with ', seed_value)
_rng.seed = seed_value _rng.seed = seed_value
# Randomize the seed (for non-reproducible results) # Randomize the seed (for non-reproducible results)

13
outline.gdshader Normal file
View file

@ -0,0 +1,13 @@
shader_type spatial;
render_mode cull_front, unshaded;
uniform vec3 color : source_color = vec3(0,0,0);
uniform float thickness : hint_range(0.0, 1.0, 0.01) = 0.03;
void vertex() {
VERTEX += thickness*NORMAL;
}
void fragment() {
ALBEDO = color;
}

1
outline.gdshader.uid Normal file
View file

@ -0,0 +1 @@
uid://os2r7dm88ofb

View file

@ -463,15 +463,14 @@ anchor_bottom = 1.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
stretch = true stretch = true
stretch_shrink = 2
[node name="SubViewport" type="SubViewport" parent="SubViewportContainer"] [node name="SubViewport" type="SubViewport" parent="SubViewportContainer"]
transparent_bg = true transparent_bg = true
handle_input_locally = false handle_input_locally = false
size = Vector2i(576, 324) size = Vector2i(1152, 648)
render_target_update_mode = 4 render_target_update_mode = 4
[node name="Player" type="CharacterBody3D" parent="SubViewportContainer/SubViewport"] [node name="Player" type="CharacterBody3D" parent="SubViewportContainer/SubViewport" groups=["player"]]
unique_name_in_owner = true unique_name_in_owner = true
script = ExtResource("1_d602n") script = ExtResource("1_d602n")
@ -741,7 +740,7 @@ transform = Transform3D(1, 0, 0, 0, 1, -1.49012e-07, 0, 1.19209e-07, 1, 0.041054
projection = 1 projection = 1
current = true current = true
size = 4.0 size = 4.0
near = 0.01 near = 0.005
far = 100.0 far = 100.0
[node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"] [node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"]
@ -772,7 +771,7 @@ draw_pass_1 = SubResource("QuadMesh_hvb1l")
[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/VFX/Fire"] [node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/VFX/Fire"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992)
light_color = Color(0.89, 0.461613, 0.2136, 1) light_color = Color(0.89, 0.461613, 0.2136, 1)
light_energy = 0.721247 light_energy = 0.849132
light_indirect_energy = 1.084 light_indirect_energy = 1.084
light_volumetric_fog_energy = 3.764 light_volumetric_fog_energy = 3.764
light_size = 0.105 light_size = 0.105
@ -801,7 +800,6 @@ ground_tile = ExtResource("25_caaui")
[node name="tent-canvas2" parent="." instance=ExtResource("23_5r2bu")] [node name="tent-canvas2" parent="." instance=ExtResource("23_5r2bu")]
transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, 1.49756, 1.86265e-09, -3.10828) transform = Transform3D(0.964438, 0, -0.264311, 0, 1, 0, 0.264311, 0, 0.964438, 1.49756, 1.86265e-09, -3.10828)
visible = false
[node name="UISubViewportContainer" type="SubViewportContainer" parent="."] [node name="UISubViewportContainer" type="SubViewportContainer" parent="."]
anchors_preset = 15 anchors_preset = 15

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4,21 +4,18 @@ extends Node3D
@export var map_width: int = Global.map_width @export var map_width: int = Global.map_width
@export var map_height: int = Global.map_height @export var map_height: int = Global.map_height
@export var tile_size: float = 2.0 @export var tile_size: float = 2.0
@export var chunk_size: int = 5 @export var chunk_size: int = 2
@export var view_distance: int = 2 @export var view_distance: int = 2
@export var tiles_per_frame: int = 5 # How many tiles to create per frame @export var tiles_per_frame: int = 3 # How many tiles to create per frame
var loaded_chunks: Dictionary = {} var loaded_chunks: Dictionary = {}
var player_position: Vector3 var player_position: Vector3
var last_chunk_pos: Vector2i = Vector2i(-999, -999) var last_chunk_pos: Vector2i = Vector2i(-999, -999)
var loading_chunks: Dictionary = {} # Track chunks currently being loaded var loading_chunks: Dictionary = {} # Track chunks currently being loaded
func _ready() -> void: func _ready() -> void:
Log.pr('Testing optimized tile map generation')
create_tiles_chunked() create_tiles_chunked()
func create_tiles_chunked() -> void: func create_tiles_chunked() -> void:
Log.pr('Setting up chunked tile system...')
var player = %Player var player = %Player
if player: if player:
player_position = player.global_position player_position = player.global_position
@ -48,10 +45,8 @@ func update_chunks(player_pos: Vector3) -> void:
chunks_to_load.append(current_chunk + Vector2i(x, z)) chunks_to_load.append(current_chunk + Vector2i(x, z))
# LOADING new chunks # LOADING new chunks
Log.pr("Chunks to load: ", chunks_to_load.size())
for chunk_pos in chunks_to_load: for chunk_pos in chunks_to_load:
if chunk_pos not in loaded_chunks and chunk_pos not in loading_chunks: if chunk_pos not in loaded_chunks and chunk_pos not in loading_chunks:
Log.pr("Loading new: ", chunk_pos)
loading_chunks[chunk_pos] = true loading_chunks[chunk_pos] = true
load_chunk_async(chunk_pos) load_chunk_async(chunk_pos)
@ -61,9 +56,7 @@ func update_chunks(player_pos: Vector3) -> void:
if chunk_pos not in chunks_to_load: if chunk_pos not in chunks_to_load:
chunks_to_unload.append(chunk_pos) chunks_to_unload.append(chunk_pos)
Log.pr("Chunks to unload: ", chunks_to_unload.size())
for chunk_pos in chunks_to_unload: for chunk_pos in chunks_to_unload:
Log.pr("Unloading: ", chunk_pos)
unload_chunk(chunk_pos) unload_chunk(chunk_pos)
func load_chunk_async(chunk_pos: Vector2i) -> void: func load_chunk_async(chunk_pos: Vector2i) -> void:
@ -72,8 +65,6 @@ func load_chunk_async(chunk_pos: Vector2i) -> void:
loading_chunks.erase(chunk_pos) loading_chunks.erase(chunk_pos)
return return
var orphans_before = Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)
var chunk_node = Node3D.new() var chunk_node = Node3D.new()
chunk_node.name = "Chunk_%d_%d" % [chunk_pos.x, chunk_pos.y] chunk_node.name = "Chunk_%d_%d" % [chunk_pos.x, chunk_pos.y]
add_child(chunk_node) add_child(chunk_node)
@ -81,7 +72,7 @@ func load_chunk_async(chunk_pos: Vector2i) -> void:
var start_x = chunk_pos.x * chunk_size * tile_size - (chunk_size * tile_size) / 2.0 var start_x = chunk_pos.x * chunk_size * tile_size - (chunk_size * tile_size) / 2.0
var start_z = chunk_pos.y * chunk_size * tile_size - (chunk_size * tile_size) / 2.0 var start_z = chunk_pos.y * chunk_size * tile_size - (chunk_size * tile_size) / 2.0
var tiles_created = 0 #var tiles_created = 0
var tiles_this_frame = 0 var tiles_this_frame = 0
for x in range(chunk_size): for x in range(chunk_size):
@ -95,7 +86,7 @@ func load_chunk_async(chunk_pos: Vector2i) -> void:
) )
chunk_node.add_child(tile_instance) chunk_node.add_child(tile_instance)
tiles_created += 1 #tiles_created += 1
tiles_this_frame += 1 tiles_this_frame += 1
# Yield after creating a certain number of tiles # Yield after creating a certain number of tiles
@ -103,34 +94,12 @@ func load_chunk_async(chunk_pos: Vector2i) -> void:
tiles_this_frame = 0 tiles_this_frame = 0
await get_tree().process_frame await get_tree().process_frame
Log.pr("Created ", tiles_created, " tiles in chunk ", chunk_pos)
loaded_chunks[chunk_pos] = chunk_node loaded_chunks[chunk_pos] = chunk_node
loading_chunks.erase(chunk_pos) loading_chunks.erase(chunk_pos)
var orphans_after = Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)
Log.pr("Orphans during chunk load: ", orphans_after - orphans_before)
# In your TileGround script, add this debugging to unload_chunk():
func unload_chunk(chunk_pos: Vector2i) -> void: func unload_chunk(chunk_pos: Vector2i) -> void:
if chunk_pos in loaded_chunks: if chunk_pos in loaded_chunks:
Log.pr("Unloading chunk: ", chunk_pos)
var chunk_node = loaded_chunks[chunk_pos] var chunk_node = loaded_chunks[chunk_pos]
var orphans_before = Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)
var nodes_before = Performance.get_monitor(Performance.OBJECT_NODE_COUNT)
# Count children before cleanup
var child_count = chunk_node.get_child_count()
Log.pr("Chunk has ", child_count, " children")
chunk_node.queue_free() chunk_node.queue_free()
loaded_chunks.erase(chunk_pos) loaded_chunks.erase(chunk_pos)
# Check immediately after
await get_tree().process_frame
var orphans_after = Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT)
var nodes_after = Performance.get_monitor(Performance.OBJECT_NODE_COUNT)
Log.pr("Orphans created: ", orphans_after - orphans_before)
Log.pr("Nodes remaining: ", nodes_after - nodes_before)

View file

@ -62,7 +62,9 @@ func get_object_debug_text() -> String:
var static_max = Performance.get_monitor(Performance.MEMORY_STATIC_MAX) var static_max = Performance.get_monitor(Performance.MEMORY_STATIC_MAX)
text += "Static Mem: " + format_bytes(static_mem) + "\n" text += "Static Mem: " + format_bytes(static_mem) + "\n"
text += "Peak Mem: " + format_bytes(static_max) text += "Peak Mem: " + format_bytes(static_max) + "\n"
text += "Trees: " + str(get_tree().get_nodes_in_group("tree").size())
return text return text