diff --git a/Assets/temp_models/Textures/colormap.png b/Assets/temp_models/Textures/colormap.png new file mode 100644 index 0000000..32bba44 --- /dev/null +++ b/Assets/temp_models/Textures/colormap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ca023be9f12e8c2358fcf94320c8a894b4c05a3dd0bad1f5c268312053caca1 +size 7440 diff --git a/Assets/temp_models/Textures/colormap.png.import b/Assets/temp_models/Textures/colormap.png.import new file mode 100644 index 0000000..6f91484 --- /dev/null +++ b/Assets/temp_models/Textures/colormap.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://m3jsjukytaqy" +path.s3tc="res://.godot/imported/colormap.png-ba57e54e3743a282f3d81dcd3a2fa8c2.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://Assets/temp_models/Textures/colormap.png" +dest_files=["res://.godot/imported/colormap.png-ba57e54e3743a282f3d81dcd3a2fa8c2.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/Entities/Tree/assets/flowers-tall.glb b/Assets/temp_models/flowers-tall.glb similarity index 100% rename from Entities/Tree/assets/flowers-tall.glb rename to Assets/temp_models/flowers-tall.glb diff --git a/Entities/Tree/assets/flowers-tall.glb.import b/Assets/temp_models/flowers-tall.glb.import similarity index 75% rename from Entities/Tree/assets/flowers-tall.glb.import rename to Assets/temp_models/flowers-tall.glb.import index 98ecdfc..2a8d096 100644 --- a/Entities/Tree/assets/flowers-tall.glb.import +++ b/Assets/temp_models/flowers-tall.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://c5squxlbapts8" -path="res://.godot/imported/flowers-tall.glb-95d03d8d03dfdd00c1156b3c9d948d51.scn" +path="res://.godot/imported/flowers-tall.glb-f244b44beee32be4bca978c256b9b6a3.scn" [deps] -source_file="res://Entities/Tree/assets/flowers-tall.glb" -dest_files=["res://.godot/imported/flowers-tall.glb-95d03d8d03dfdd00c1156b3c9d948d51.scn"] +source_file="res://Assets/temp_models/flowers-tall.glb" +dest_files=["res://.godot/imported/flowers-tall.glb-f244b44beee32be4bca978c256b9b6a3.scn"] [params] diff --git a/Entities/Tree/assets/flowers.glb b/Assets/temp_models/flowers.glb similarity index 100% rename from Entities/Tree/assets/flowers.glb rename to Assets/temp_models/flowers.glb diff --git a/Entities/Tree/assets/flowers.glb.import b/Assets/temp_models/flowers.glb.import similarity index 76% rename from Entities/Tree/assets/flowers.glb.import rename to Assets/temp_models/flowers.glb.import index 71ae1ad..579422d 100644 --- a/Entities/Tree/assets/flowers.glb.import +++ b/Assets/temp_models/flowers.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://10c6aovvh80f" -path="res://.godot/imported/flowers.glb-e088e23c831479646c36442d07fa990a.scn" +path="res://.godot/imported/flowers.glb-643d814f11eac4de9f7fc76085d3adac.scn" [deps] -source_file="res://Entities/Tree/assets/flowers.glb" -dest_files=["res://.godot/imported/flowers.glb-e088e23c831479646c36442d07fa990a.scn"] +source_file="res://Assets/temp_models/flowers.glb" +dest_files=["res://.godot/imported/flowers.glb-643d814f11eac4de9f7fc76085d3adac.scn"] [params] diff --git a/Entities/Tree/assets/grass.glb b/Assets/temp_models/grass.glb similarity index 100% rename from Entities/Tree/assets/grass.glb rename to Assets/temp_models/grass.glb diff --git a/Entities/Tree/assets/grass.glb.import b/Assets/temp_models/grass.glb.import similarity index 76% rename from Entities/Tree/assets/grass.glb.import rename to Assets/temp_models/grass.glb.import index 10d84a9..9758681 100644 --- a/Entities/Tree/assets/grass.glb.import +++ b/Assets/temp_models/grass.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://cltv073ea1df6" -path="res://.godot/imported/grass.glb-e355d999e18b247a452756b0c0298f3f.scn" +path="res://.godot/imported/grass.glb-7e581c773d5cf661e4fb13652143204c.scn" [deps] -source_file="res://Entities/Tree/assets/grass.glb" -dest_files=["res://.godot/imported/grass.glb-e355d999e18b247a452756b0c0298f3f.scn"] +source_file="res://Assets/temp_models/grass.glb" +dest_files=["res://.godot/imported/grass.glb-7e581c773d5cf661e4fb13652143204c.scn"] [params] diff --git a/Entities/Tree/assets/mushrooms.glb b/Assets/temp_models/mushrooms.glb similarity index 100% rename from Entities/Tree/assets/mushrooms.glb rename to Assets/temp_models/mushrooms.glb diff --git a/Entities/Tree/assets/mushrooms.glb.import b/Assets/temp_models/mushrooms.glb.import similarity index 75% rename from Entities/Tree/assets/mushrooms.glb.import rename to Assets/temp_models/mushrooms.glb.import index 8d1af4d..df29711 100644 --- a/Entities/Tree/assets/mushrooms.glb.import +++ b/Assets/temp_models/mushrooms.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://7pg0hhklawxb" -path="res://.godot/imported/mushrooms.glb-fbdb79cee23454ae0534ba9b11cd89be.scn" +path="res://.godot/imported/mushrooms.glb-3620553a4f83af03e1259fecf477bba9.scn" [deps] -source_file="res://Entities/Tree/assets/mushrooms.glb" -dest_files=["res://.godot/imported/mushrooms.glb-fbdb79cee23454ae0534ba9b11cd89be.scn"] +source_file="res://Assets/temp_models/mushrooms.glb" +dest_files=["res://.godot/imported/mushrooms.glb-3620553a4f83af03e1259fecf477bba9.scn"] [params] diff --git a/Entities/Tree/assets/plant.glb b/Assets/temp_models/plant.glb similarity index 100% rename from Entities/Tree/assets/plant.glb rename to Assets/temp_models/plant.glb diff --git a/Entities/Tree/assets/plant.glb.import b/Assets/temp_models/plant.glb.import similarity index 76% rename from Entities/Tree/assets/plant.glb.import rename to Assets/temp_models/plant.glb.import index 6fbecc4..2982814 100644 --- a/Entities/Tree/assets/plant.glb.import +++ b/Assets/temp_models/plant.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://dpsdijnn33q12" -path="res://.godot/imported/plant.glb-7178531d987506ebea1d66a300992d57.scn" +path="res://.godot/imported/plant.glb-339d9b8108b82f10d7e228e28ae0b50b.scn" [deps] -source_file="res://Entities/Tree/assets/plant.glb" -dest_files=["res://.godot/imported/plant.glb-7178531d987506ebea1d66a300992d57.scn"] +source_file="res://Assets/temp_models/plant.glb" +dest_files=["res://.godot/imported/plant.glb-339d9b8108b82f10d7e228e28ae0b50b.scn"] [params] diff --git a/Config/Globals.gd b/Config/Globals.gd index c00c87c..501de9a 100644 --- a/Config/Globals.gd +++ b/Config/Globals.gd @@ -3,11 +3,152 @@ extends Node var map_height: int = 200 var map_width: int = 200 +var _map_data: Array +var _biome_data: Dictionary = {} -var map_data: Array +# Property for map_data with logging +var map_data: Array: + get: + return _map_data + set(value): + _map_data = value + Log.pr("Map data updated") + +# Property for biome_data with logging +var biome_data: Dictionary: + get: + return _biome_data + set(value): + _biome_data = value + _log_biome_update() func _init() -> void: - map_data.resize(map_height) + _map_data.resize(map_height) for y in range(map_height): - map_data[y] = [] - map_data[y].resize(map_width) + _map_data[y] = [] + _map_data[y].resize(map_width) + Log.pr("Globals initialized with map size: %d x %d" % [map_width, map_height]) + +# Helper methods for updating specific parts of the data +func set_map_cell(x: int, y: int, value) -> void: + if x >= 0 and x < map_width and y >= 0 and y < map_height: + _map_data[y][x] = value + Log.pr("Map cell updated at (%d, %d)" % [x, y]) + +func update_biome(key: String, value) -> void: + _biome_data[key] = value + Log.pr("Biome data updated for key: %s" % key) + +# Internal logging function for biome updates +func _log_biome_update() -> void: + var details = [] + for key in _biome_data.keys(): + var value = _biome_data[key] + if value is Image: + var img = value as Image + details.append("%s: Image[%dx%d]" % [key, img.get_width(), img.get_height()]) + else: + details.append("%s: %s" % [key, str(value)]) + Log.pr("Biome data updated: { %s }" % ", ".join(details)) + display_all_noise_maps() + +# Display visual representation of noise map +func display_noise_map(key: String, scale: int = 4) -> void: + if not _biome_data.has(key): + Log.pr("No biome data found for key: %s" % key) + return + + var img = _biome_data[key] + if not img is Image: + Log.pr("Data for key '%s' is not an image" % key) + return + + var image = img as Image + var width = image.get_width() + var height = image.get_height() + + # Sample the image at lower resolution for console display + var display_width = min(width / scale, 50) # Max 50 chars wide + var display_height = min(height / scale, 25) # Max 25 lines tall + + Log.pr("=== %s Noise Map (%dx%d) ===" % [key.capitalize(), width, height]) + + for y in range(display_height): + var line = "" + for x in range(display_width): + # Sample from the original image + var sample_x = int(x * scale) + var sample_y = int(y * scale) + + # Get pixel color (assuming grayscale or we'll use red channel) + var pixel = image.get_pixel(sample_x, sample_y) + var intensity = pixel.r # Use red channel as intensity + + # Convert intensity to colored circle + line += _get_colored_circle(intensity) + + Log.pr(line) + + Log.pr("Scale: 1 character = %dx%d pixels" % [scale, scale]) + +# Convert intensity value to colored circle character +func _get_colored_circle(intensity: float) -> String: + # ANSI color codes for red > yellow > green gradient + var color_code: String + var circle = "●" + + if intensity < 0.1: + color_code = "[color=maroon]" # Dark red + elif intensity < 0.2: + color_code = "[color=red]" # Red + elif intensity < 0.3: + color_code = "[color=#FF4500]" # Orange red + elif intensity < 0.4: + color_code = "[color=orange]" # Orange + elif intensity < 0.5: + color_code = "[color=#FFD700]" # Gold + elif intensity < 0.6: + color_code = "[color=yellow]" # Yellow + elif intensity < 0.7: + color_code = "[color=#ADFF2F]" # Green yellow + elif intensity < 0.8: + color_code = "[color=lime]" # Lime + elif intensity < 0.9: + color_code = "[color=green]" # Green + else: + color_code = "[color=darkgreen]" # Dark green + + return color_code + circle + "[/color]" + +# Display all biome maps +func display_all_noise_maps(scale: int = 4) -> void: + for key in _biome_data.keys(): + if _biome_data[key] is Image: + display_noise_map(key, scale) + Log.pr("") # Empty line between maps + +# Helper function to get detailed biome info +func log_biome_details() -> void: + Log.pr("=== Biome Data Details ===") + for key in _biome_data.keys(): + var value = _biome_data[key] + if value is Image: + var img = value as Image + Log.pr("%s: Image [%dx%d, Format: %s]" % [key, img.get_width(), img.get_height(), _get_format_name(img.get_format())]) + else: + Log.pr("%s: %s" % [key, str(value)]) + +# Helper to convert image format enum to readable string +func _get_format_name(format: Image.Format) -> String: + match format: + Image.FORMAT_L8: return "L8" + Image.FORMAT_LA8: return "LA8" + Image.FORMAT_R8: return "R8" + Image.FORMAT_RG8: return "RG8" + Image.FORMAT_RGB8: return "RGB8" + Image.FORMAT_RGBA8: return "RGBA8" + Image.FORMAT_RF: return "RF" + Image.FORMAT_RGF: return "RGF" + Image.FORMAT_RGBF: return "RGBF" + Image.FORMAT_RGBAF: return "RGBAF" + _: return "Unknown (%d)" % format \ No newline at end of file diff --git a/Entities/GroundTile/GroundTile.tscn b/Entities/GroundTile/GroundTile.tscn index 9f1d153..37e6239 100644 --- a/Entities/GroundTile/GroundTile.tscn +++ b/Entities/GroundTile/GroundTile.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=14 format=3 uid="uid://bwcevwwphdvq"] +[gd_scene load_steps=13 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="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"] @@ -6,7 +6,6 @@ [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://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"] -[ext_resource type="PackedScene" uid="uid://c27fogucecn0r" path="res://Entities/Tree/Tree.tscn" id="7_224hx"] [sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"] viewport_path = NodePath("DebugText/DebugTextViewport") @@ -31,7 +30,6 @@ flip_faces = true script = ExtResource("1_uwxqs") [node name="DebugText" type="Node3D" parent="."] -visible = false [node name="DebugTextViewport" type="SubViewport" parent="DebugText"] size = Vector2i(50, 50) @@ -71,4 +69,3 @@ mesh = SubResource("PlaneMesh_f37ob") [node name="Trees" type="Node3D" parent="."] script = ExtResource("7_7lc7k") -tree_scenes = Array[PackedScene]([ExtResource("7_224hx")]) diff --git a/Entities/GroundTile/scripts/trees.gd b/Entities/GroundTile/scripts/trees.gd index 85bd8b8..929b62b 100644 --- a/Entities/GroundTile/scripts/trees.gd +++ b/Entities/GroundTile/scripts/trees.gd @@ -1,8 +1,8 @@ extends Node3D -@export var tree_scenes: Array[PackedScene] = [] + @export var spawn_area_size: Vector2 = Vector2(2.0, 2.0) -@export var max_trees: int = 3 @export var min_distance: float = 0.5 + var spawned_positions: Array[Vector3] = [] var parent_ground_tile: GroundTile @@ -16,30 +16,31 @@ func spawn_trees_for_cell(cell_info: CellDataResource): if not parent_ground_tile: return - var tree_count = max(0, cell_info.trees.size()) - spawn_trees(tree_count) - -func spawn_trees(tree_count: int): - if tree_scenes.is_empty() or tree_count == 0: - return - # Clear existing trees WITHOUT queue_free() for child in get_children(): child.free() # Immediate cleanup instead of queue_free() spawned_positions.clear() - # Spawn new trees + # Spawn each tree in the array + var spawned_count = 0 var attempts = 0 - var max_attempts = tree_count * 10 + var max_attempts = cell_info.trees.size() * 10 - while spawned_positions.size() < tree_count and attempts < max_attempts: + for tree_resource in cell_info.trees: + if attempts >= max_attempts: + Log.pr("Reached max attempts, could only spawn %d of %d trees" % [spawned_count, cell_info.trees.size()]) + break + var pos = get_random_position() if is_position_valid(pos): - spawn_tree_at_position(pos) + spawn_tree_at_position(pos, tree_resource as TreeDataResource) spawned_positions.append(pos) + spawned_count += 1 attempts += 1 + + Log.pr("Spawned %d of %d trees in cell" % [spawned_count, cell_info.trees.size()]) func get_random_position() -> Vector3: var rng = parent_ground_tile.get_rng() @@ -47,17 +48,67 @@ func get_random_position() -> Vector3: 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() +func spawn_tree_at_position(pos: Vector3, tree_resource: TreeDataResource): + if not tree_resource: + Log.pr("No tree resource provided") + return + + + var tree_scene = preload("res://Entities/Tree/Tree.tscn") + var tree_instance = tree_scene.instantiate() add_child(tree_instance) tree_instance.position = pos + + var rng = parent_ground_tile.get_rng() tree_instance.rotation.y = rng.randf() * TAU + + # Pass the TreeDataResource to the Tree instance + if tree_instance.has_method("set_tree_data"): + tree_instance.set_tree_data(tree_resource) + elif tree_instance.has_method("setup_tree"): + tree_instance.setup_tree(tree_resource) + else: + Log.pr("Tree instance doesn't have set_tree_data() or setup_tree() method") func is_position_valid(pos: Vector3) -> bool: for existing_pos in spawned_positions: if pos.distance_to(existing_pos) < min_distance: return false return true + +# Alternative method that shuffles trees for more random placement +func spawn_trees_shuffled(cell_info: CellDataResource): + if not cell_info: + return + + if not parent_ground_tile: + return + + # Clear existing trees + for child in get_children(): + child.free() + spawned_positions.clear() + + # Create a copy and shuffle for random placement order + var trees_to_spawn = cell_info.trees.duplicate() + trees_to_spawn.shuffle() + + var spawned_count = 0 + var attempts = 0 + var max_attempts = trees_to_spawn.size() * 10 + + for tree_resource in trees_to_spawn: + if attempts >= max_attempts: + Log.pr("Reached max attempts, could only spawn %d of %d trees" % [spawned_count, trees_to_spawn.size()]) + break + + var pos = get_random_position() + + if is_position_valid(pos): + spawn_tree_at_position(pos, tree_resource as TreeDataResource) + spawned_positions.append(pos) + spawned_count += 1 + + attempts += 1 + + Log.pr("Spawned %d of %d trees in cell (shuffled)" % [spawned_count, trees_to_spawn.size()]) diff --git a/Entities/Tree/Tree.tscn b/Entities/Tree/Tree.tscn index 96e687a..a45cf43 100644 --- a/Entities/Tree/Tree.tscn +++ b/Entities/Tree/Tree.tscn @@ -1,7 +1,6 @@ -[gd_scene load_steps=5 format=3 uid="uid://c27fogucecn0r"] +[gd_scene load_steps=4 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 @@ -12,11 +11,9 @@ height = 0.5 [node name="Tree" type="Node3D"] script = ExtResource("1_702jv") -[node name="TreeModel" parent="." instance=ExtResource("1_s6kdm")] +[node name="TreeCollision" type="StaticBody3D" parent="." groups=["tree"]] -[node name="TreeCollision" type="StaticBody3D" parent="TreeModel" groups=["tree"]] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="TreeModel/TreeCollision"] +[node name="CollisionShape3D" type="CollisionShape3D" parent="TreeCollision"] shape = SubResource("CapsuleShape3D_s6kdm") [node name="InteractRange" type="Area3D" parent="."] diff --git a/Entities/Tree/TreeDataResource.gd b/Entities/Tree/TreeDataResource.gd deleted file mode 100644 index 75f657e..0000000 --- a/Entities/Tree/TreeDataResource.gd +++ /dev/null @@ -1,2 +0,0 @@ -class_name TreeDataResource -extends Resource \ No newline at end of file diff --git a/Entities/Tree/assets/temp/stump_squareDetailedWide.glb b/Entities/Tree/assets/stump_squareDetailedWide.glb similarity index 100% rename from Entities/Tree/assets/temp/stump_squareDetailedWide.glb rename to Entities/Tree/assets/stump_squareDetailedWide.glb diff --git a/Entities/Tree/assets/temp/stump_squareDetailedWide.glb.import b/Entities/Tree/assets/stump_squareDetailedWide.glb.import similarity index 78% rename from Entities/Tree/assets/temp/stump_squareDetailedWide.glb.import rename to Entities/Tree/assets/stump_squareDetailedWide.glb.import index e200ff5..652f628 100644 --- a/Entities/Tree/assets/temp/stump_squareDetailedWide.glb.import +++ b/Entities/Tree/assets/stump_squareDetailedWide.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://cbpdkprq4oygx" -path="res://.godot/imported/stump_squareDetailedWide.glb-d878f01571d1b63564fad6b6c5034e4e.scn" +path="res://.godot/imported/stump_squareDetailedWide.glb-cf6ab5acdf21d0d1c819e12a33760a23.scn" [deps] -source_file="res://Entities/Tree/assets/temp/stump_squareDetailedWide.glb" -dest_files=["res://.godot/imported/stump_squareDetailedWide.glb-d878f01571d1b63564fad6b6c5034e4e.scn"] +source_file="res://Entities/Tree/assets/stump_squareDetailedWide.glb" +dest_files=["res://.godot/imported/stump_squareDetailedWide.glb-cf6ab5acdf21d0d1c819e12a33760a23.scn"] [params] diff --git a/Entities/Tree/assets/temp/tree_simple.glb b/Entities/Tree/assets/tree_birch.glb similarity index 100% rename from Entities/Tree/assets/temp/tree_simple.glb rename to Entities/Tree/assets/tree_birch.glb diff --git a/Entities/Tree/assets/temp/tree_simple.glb.import b/Entities/Tree/assets/tree_birch.glb.import similarity index 75% rename from Entities/Tree/assets/temp/tree_simple.glb.import rename to Entities/Tree/assets/tree_birch.glb.import index d7f0c4e..3941bf1 100644 --- a/Entities/Tree/assets/temp/tree_simple.glb.import +++ b/Entities/Tree/assets/tree_birch.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://besaean4w1n83" -path="res://.godot/imported/tree_simple.glb-b9d4e3d58a0247bb4b0a272930d98816.scn" +path="res://.godot/imported/tree_birch.glb-5b5f3dd54832f8b215e47c1a3d185b41.scn" [deps] -source_file="res://Entities/Tree/assets/temp/tree_simple.glb" -dest_files=["res://.godot/imported/tree_simple.glb-b9d4e3d58a0247bb4b0a272930d98816.scn"] +source_file="res://Entities/Tree/assets/tree_birch.glb" +dest_files=["res://.godot/imported/tree_birch.glb-5b5f3dd54832f8b215e47c1a3d185b41.scn"] [params] diff --git a/Entities/Tree/assets/temp/tree_detailed.glb b/Entities/Tree/assets/tree_detailed.glb similarity index 100% rename from Entities/Tree/assets/temp/tree_detailed.glb rename to Entities/Tree/assets/tree_detailed.glb diff --git a/Entities/Tree/assets/temp/tree_detailed.glb.import b/Entities/Tree/assets/tree_detailed.glb.import similarity index 74% rename from Entities/Tree/assets/temp/tree_detailed.glb.import rename to Entities/Tree/assets/tree_detailed.glb.import index 27094e9..230c57a 100644 --- a/Entities/Tree/assets/temp/tree_detailed.glb.import +++ b/Entities/Tree/assets/tree_detailed.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://b3lc1nbuv5ol8" -path="res://.godot/imported/tree_detailed.glb-b5202c3bc7a30f70608fb9f2e022f85a.scn" +path="res://.godot/imported/tree_detailed.glb-9c5d658b3d25a47972c567f3d1f098f9.scn" [deps] -source_file="res://Entities/Tree/assets/temp/tree_detailed.glb" -dest_files=["res://.godot/imported/tree_detailed.glb-b5202c3bc7a30f70608fb9f2e022f85a.scn"] +source_file="res://Entities/Tree/assets/tree_detailed.glb" +dest_files=["res://.godot/imported/tree_detailed.glb-9c5d658b3d25a47972c567f3d1f098f9.scn"] [params] diff --git a/Entities/Tree/assets/temp/tree_oak.glb b/Entities/Tree/assets/tree_oak.glb similarity index 100% rename from Entities/Tree/assets/temp/tree_oak.glb rename to Entities/Tree/assets/tree_oak.glb diff --git a/Entities/Tree/assets/temp/tree_oak.glb.import b/Entities/Tree/assets/tree_oak.glb.import similarity index 75% rename from Entities/Tree/assets/temp/tree_oak.glb.import rename to Entities/Tree/assets/tree_oak.glb.import index 69f72fd..3d1078f 100644 --- a/Entities/Tree/assets/temp/tree_oak.glb.import +++ b/Entities/Tree/assets/tree_oak.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://g74ar24o4s1" -path="res://.godot/imported/tree_oak.glb-3aa4e2d0d7eaeebf59babfa38b1c94d8.scn" +path="res://.godot/imported/tree_oak.glb-44054ae42038fcc129cfdc3e72791764.scn" [deps] -source_file="res://Entities/Tree/assets/temp/tree_oak.glb" -dest_files=["res://.godot/imported/tree_oak.glb-3aa4e2d0d7eaeebf59babfa38b1c94d8.scn"] +source_file="res://Entities/Tree/assets/tree_oak.glb" +dest_files=["res://.godot/imported/tree_oak.glb-44054ae42038fcc129cfdc3e72791764.scn"] [params] diff --git a/Entities/Tree/assets/temp/tree_oak_fall.glb b/Entities/Tree/assets/tree_oak_fall.glb similarity index 100% rename from Entities/Tree/assets/temp/tree_oak_fall.glb rename to Entities/Tree/assets/tree_oak_fall.glb diff --git a/Entities/Tree/assets/temp/tree_oak_fall.glb.import b/Entities/Tree/assets/tree_oak_fall.glb.import similarity index 74% rename from Entities/Tree/assets/temp/tree_oak_fall.glb.import rename to Entities/Tree/assets/tree_oak_fall.glb.import index dc3c273..b139237 100644 --- a/Entities/Tree/assets/temp/tree_oak_fall.glb.import +++ b/Entities/Tree/assets/tree_oak_fall.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://vnpet4sa23cm" -path="res://.godot/imported/tree_oak_fall.glb-5e5d4e93272aaf8df4999be726ef1d25.scn" +path="res://.godot/imported/tree_oak_fall.glb-5423c3799178cc793415b030f003201c.scn" [deps] -source_file="res://Entities/Tree/assets/temp/tree_oak_fall.glb" -dest_files=["res://.godot/imported/tree_oak_fall.glb-5e5d4e93272aaf8df4999be726ef1d25.scn"] +source_file="res://Entities/Tree/assets/tree_oak_fall.glb" +dest_files=["res://.godot/imported/tree_oak_fall.glb-5423c3799178cc793415b030f003201c.scn"] [params] diff --git a/Entities/Tree/resources/TreeData.tres b/Entities/Tree/resources/TreeData.tres new file mode 100644 index 0000000..52dc4ae --- /dev/null +++ b/Entities/Tree/resources/TreeData.tres @@ -0,0 +1,81 @@ +[gd_resource type="Resource" script_class="TreeDataCollection" load_steps=11 format=3 uid="uid://buf5mtxc5f7o"] + +[ext_resource type="Script" uid="uid://dj4dhsd0m0bvd" path="res://Entities/Tree/resources/TreeDataCollection.gd" id="1_7y4l8"] +[ext_resource type="Script" uid="uid://cdudelqysppwl" path="res://Entities/Tree/resources/TreeDataResource.gd" id="2_4yk3p"] +[ext_resource type="PackedScene" uid="uid://g74ar24o4s1" path="res://Entities/Tree/assets/tree_oak.glb" id="3_4yk3p"] +[ext_resource type="PackedScene" uid="uid://bwhpbjdyl577e" path="res://Entities/Tree/assets/tree.glb" id="4_4wxxs"] +[ext_resource type="PackedScene" uid="uid://besaean4w1n83" path="res://Entities/Tree/assets/tree_birch.glb" id="5_35hba"] +[ext_resource type="PackedScene" uid="uid://b3lc1nbuv5ol8" path="res://Entities/Tree/assets/tree_detailed.glb" id="6_ibfiw"] + +[sub_resource type="Resource" id="Resource_7y4l8"] +script = ExtResource("2_4yk3p") +tree_name = "Oak" +model = ExtResource("3_4yk3p") +growth_stages = Array[PackedScene]([]) +temperature_range = Vector2(0.4, 0.9) +moisture_range = Vector2(0.3, 0.8) +elevation_range = Vector2(0.1, 0.5) +max_height = 15.0 +growth_time = 120.0 +spawn_probability = 0.1 +spread_radius = 5.0 +seasonal_models = Array[PackedScene]([]) +drops_leaves = true +leaf_color_variations = Array[Color]([]) +metadata/_custom_type_script = "uid://cdudelqysppwl" + +[sub_resource type="Resource" id="Resource_35hba"] +script = ExtResource("2_4yk3p") +tree_name = "Pine" +model = ExtResource("4_4wxxs") +growth_stages = Array[PackedScene]([]) +temperature_range = Vector2(0.1, 0.6) +moisture_range = Vector2(0.2, 0.6) +elevation_range = Vector2(0.7, 1) +max_height = 15.0 +growth_time = 120.0 +spawn_probability = 0.1 +spread_radius = 5.0 +seasonal_models = Array[PackedScene]([]) +drops_leaves = true +leaf_color_variations = Array[Color]([]) +metadata/_custom_type_script = "uid://cdudelqysppwl" + +[sub_resource type="Resource" id="Resource_4wxxs"] +script = ExtResource("2_4yk3p") +tree_name = "Birch" +model = ExtResource("5_35hba") +growth_stages = Array[PackedScene]([]) +temperature_range = Vector2(0.2, 0.7) +moisture_range = Vector2(0.5, 0.6) +elevation_range = Vector2(0.1, 0.5) +max_height = 15.0 +growth_time = 120.0 +spawn_probability = 0.1 +spread_radius = 5.0 +seasonal_models = Array[PackedScene]([]) +drops_leaves = true +leaf_color_variations = Array[Color]([]) +metadata/_custom_type_script = "uid://cdudelqysppwl" + +[sub_resource type="Resource" id="Resource_54eyh"] +script = ExtResource("2_4yk3p") +tree_name = "Elder" +model = ExtResource("6_ibfiw") +growth_stages = Array[PackedScene]([]) +temperature_range = Vector2(0.3, 0.8) +moisture_range = Vector2(0.7, 1) +elevation_range = Vector2(0, 0.2) +max_height = 15.0 +growth_time = 120.0 +spawn_probability = 0.1 +spread_radius = 5.0 +seasonal_models = Array[PackedScene]([]) +drops_leaves = true +leaf_color_variations = Array[Color]([]) +metadata/_custom_type_script = "uid://cdudelqysppwl" + +[resource] +script = ExtResource("1_7y4l8") +trees = Array[ExtResource("2_4yk3p")]([SubResource("Resource_7y4l8"), SubResource("Resource_35hba"), SubResource("Resource_4wxxs"), SubResource("Resource_54eyh")]) +metadata/_custom_type_script = "uid://dj4dhsd0m0bvd" diff --git a/Entities/Tree/resources/TreeDataCollection.gd b/Entities/Tree/resources/TreeDataCollection.gd new file mode 100644 index 0000000..adb63d6 --- /dev/null +++ b/Entities/Tree/resources/TreeDataCollection.gd @@ -0,0 +1,20 @@ +class_name TreeDataCollection +extends Resource + +@export var trees: Array[TreeDataResource] = [] + +# Helper functions +func get_tree_by_name(name: String) -> TreeDataResource: + for tree in trees: + if tree.tree_name == name: + return tree + return null + +func get_suitable_trees(temperature: float, moisture: float, elevation: float) -> Array[TreeDataResource]: + var suitable_trees: Array[TreeDataResource] = [] + for tree in trees: + if (temperature >= tree.temperature_range.x and temperature <= tree.temperature_range.y and + moisture >= tree.moisture_range.x and moisture <= tree.moisture_range.y and + elevation >= tree.elevation_range.x and elevation <= tree.elevation_range.y): + suitable_trees.append(tree) + return suitable_trees \ No newline at end of file diff --git a/Entities/Tree/resources/TreeDataCollection.gd.uid b/Entities/Tree/resources/TreeDataCollection.gd.uid new file mode 100644 index 0000000..1622b30 --- /dev/null +++ b/Entities/Tree/resources/TreeDataCollection.gd.uid @@ -0,0 +1 @@ +uid://dj4dhsd0m0bvd diff --git a/Entities/Tree/resources/TreeDataResource.gd b/Entities/Tree/resources/TreeDataResource.gd new file mode 100644 index 0000000..abd2411 --- /dev/null +++ b/Entities/Tree/resources/TreeDataResource.gd @@ -0,0 +1,23 @@ +class_name TreeDataResource +extends Resource + +@export var tree_name: String = "Oak Tree" +@export var model: PackedScene +@export var icon: Texture2D +@export var growth_stages: Array[PackedScene] = [] + +@export_group("Biome Preferences") +@export var temperature_range: Vector2 = Vector2(0.3, 0.7) # Min/Max temperature +@export var moisture_range: Vector2 = Vector2(0.4, 0.8) # Min/Max moisture +@export var elevation_range: Vector2 = Vector2(0.0, 0.6) # Min/Max elevation + +@export_group("Growth Properties") +@export var max_height: float = 15.0 +@export var growth_time: float = 120.0 # Seconds to full growth +@export var spawn_probability: float = 0.1 +@export var spread_radius: float = 5.0 + +@export_group("Seasonal Behavior") +@export var seasonal_models: Array[PackedScene] = [] # Spring, Summer, Fall, Winter +@export var drops_leaves: bool = true +@export var leaf_color_variations: Array[Color] = [] diff --git a/Entities/Tree/TreeDataResource.gd.uid b/Entities/Tree/resources/TreeDataResource.gd.uid similarity index 100% rename from Entities/Tree/TreeDataResource.gd.uid rename to Entities/Tree/resources/TreeDataResource.gd.uid diff --git a/Entities/Tree/scripts/tree.gd b/Entities/Tree/scripts/tree.gd index 0d64724..586f44f 100644 --- a/Entities/Tree/scripts/tree.gd +++ b/Entities/Tree/scripts/tree.gd @@ -2,6 +2,9 @@ class_name TreeNode extends Node3D @onready var area: Area3D = $InteractRange + +var tree_data: TreeDataResource +var model_instance: Node3D var mesh_instances: Array[MeshInstance3D] = [] var original_materials: Array[Material] = [] var outline_material: Material @@ -9,69 +12,112 @@ 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 +func set_tree_data(data: TreeDataResource): + tree_data = data + spawn_model() - # 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)) +func setup_tree(data: TreeDataResource): + # Alternative method name if you prefer + set_tree_data(data) + +func spawn_model(): + if not tree_data or not tree_data.model: + Log.pr("No tree data or model provided") + return + + # Clear any existing model + if model_instance: + model_instance.queue_free() + mesh_instances.clear() + original_materials.clear() + + # Instantiate the model from the TreeDataResource + model_instance = tree_data.model.instantiate() + add_child(model_instance) + + # Create base circle after model is loaded + if not base_circle: + create_base_circle() + + # Re-scan for mesh instances in the new model + find_all_mesh_instances(model_instance) + update_outline_materials() + + # Apply any additional properties from tree_data + apply_tree_properties() + +func apply_tree_properties(): + if not model_instance or not tree_data: + return + + # Apply scale variations if defined in tree_data + if tree_data.has_method("get_random_scale"): + model_instance.scale *= tree_data.get_random_scale() + + # Apply random scale based on tree properties + if tree_data.max_height > 0: + var scale_variation = randf_range(0.8, 1.2) + model_instance.scale *= scale_variation + +func setup_outline_material(): # 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 update_outline_materials(): + if mesh_instances.is_empty(): + print("Warning: No MeshInstance3D found in model!") + return + + # Store original materials for the new model + original_materials.clear() + 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)) + func find_all_mesh_instances(node: Node): if node is MeshInstance3D: - mesh_instances.append(node) - + mesh_instances.append(node) for child in node.get_children(): - find_all_mesh_instances(child) + 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.height = 1 # 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 - + base_circle.position.y = 1 # Slightly above ground to avoid z-fighting + # Start hidden - base_circle.visible = false + base_circle.visible = true + func _on_player_entered(body: Node3D): if body.is_in_group("player"): @@ -84,6 +130,6 @@ 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 + # Remove outline from all mesh instances for mesh in mesh_instances: mesh.material_overlay = null diff --git a/Utilities/BiomeGeneration/BiomeData.gd b/Utilities/BiomeGeneration/BiomeData.gd new file mode 100644 index 0000000..1fce675 --- /dev/null +++ b/Utilities/BiomeGeneration/BiomeData.gd @@ -0,0 +1,47 @@ +class_name BiomeDataClass +extends Node + +var tree_collection = preload("res://Entities/Tree/Resources/TreeData.tres") as TreeDataCollection + +# Calculate spawn probability for each tree type +func calculate_tree_probabilities(x: int, z: int) -> Dictionary: + if Global.biome_data == null: + Log.pr("Biome data not initialized. Call generate_environment_maps first.") + return {} + + if x > Global.map_data.size() and x <= 0: + if z > Global.map_data[x].size() and z <= 0: + Log.pr("Coordinates out of bounds: (%d, %d)" % [x, z]) + return {} + + var moisture = Global.biome_data.moisture.get_pixel(x, z).r + var temperature = Global.biome_data.temperature.get_pixel(x, z).r + var elevation = Global.biome_data.elevation.get_pixel(x, z).r + + var probabilities = {} + + for tree in tree_collection.trees: + # Calculate suitability for each environmental factor + var moisture_suit = calculate_suitability(moisture, tree.moisture_range[0], tree.moisture_range[1]) + var temp_suit = calculate_suitability(temperature, tree.temperature_range[0], tree.temperature_range[1]) + var elev_suit = calculate_suitability(elevation, tree.elevation_range[0], tree.elevation_range[1]) + + # Combined probability + probabilities[tree.tree_name] = {} + probabilities[tree.tree_name]['chance'] = moisture_suit * temp_suit * elev_suit + probabilities[tree.tree_name]['resource'] = tree + + return probabilities + +func calculate_suitability(value: float, min_pref: float, max_pref: float) -> float: + if value >= min_pref and value <= max_pref: + return 1.0 + else: + var distance_outside = 0.0 + if value < min_pref: + distance_outside = min_pref - value + else: + distance_outside = value - max_pref + + # Exponential decay - drops very quickly + return max(0.01, exp(-distance_outside * 10.0)) diff --git a/Utilities/BiomeGeneration/BiomeData.gd.uid b/Utilities/BiomeGeneration/BiomeData.gd.uid new file mode 100644 index 0000000..a73a772 --- /dev/null +++ b/Utilities/BiomeGeneration/BiomeData.gd.uid @@ -0,0 +1 @@ +uid://by8rwvoabdrgn diff --git a/Utilities/BiomeGeneration/BiomeGeneration.gd b/Utilities/BiomeGeneration/BiomeGeneration.gd new file mode 100644 index 0000000..e98c981 --- /dev/null +++ b/Utilities/BiomeGeneration/BiomeGeneration.gd @@ -0,0 +1,35 @@ +class_name BiomeGenerationClass +extends Node + +# Generate environmental maps +static func generate_environment_maps(width: int, height: int) -> Dictionary: + var moisture_noise = FastNoiseLite.new() + moisture_noise.seed = 12345 + moisture_noise.frequency = 0.02 + + var temperature_noise = FastNoiseLite.new() + temperature_noise.seed = 54321 + temperature_noise.frequency = 0.015 + + var elevation_noise = FastNoiseLite.new() + elevation_noise.seed = 98765 + elevation_noise.frequency = 0.01 + + var maps = {} + maps.moisture = Image.create(width, height, false, Image.FORMAT_RF) + maps.temperature = Image.create(width, height, false, Image.FORMAT_RF) + maps.elevation = Image.create(width, height, false, Image.FORMAT_RF) + + for x in range(width): + for y in range(height): + var moisture = (moisture_noise.get_noise_2d(x, y) + 1.0) * 0.5 + var temperature = (temperature_noise.get_noise_2d(x, y) + 1.0) * 0.5 + var elevation = (elevation_noise.get_noise_2d(x, y) + 1.0) * 0.5 + + maps.moisture.set_pixel(x, y, Color(moisture, 0, 0, 1)) + maps.temperature.set_pixel(x, y, Color(temperature, 0, 0, 1)) + maps.elevation.set_pixel(x, y, Color(elevation, 0, 0, 1)) + + Global.biome_data = maps + + return maps diff --git a/Utilities/BiomeGeneration/BiomeGeneration.gd.uid b/Utilities/BiomeGeneration/BiomeGeneration.gd.uid new file mode 100644 index 0000000..433d0fd --- /dev/null +++ b/Utilities/BiomeGeneration/BiomeGeneration.gd.uid @@ -0,0 +1 @@ +uid://ddle3veoss0ny diff --git a/Utilities/EntityDataGenerators/TreeDataGenerator.gd b/Utilities/EntityDataGenerators/TreeDataGenerator.gd new file mode 100644 index 0000000..61510e1 --- /dev/null +++ b/Utilities/EntityDataGenerators/TreeDataGenerator.gd @@ -0,0 +1 @@ +extends Node diff --git a/Utilities/EntityDataGenerators/TreeDataGenerator.gd.uid b/Utilities/EntityDataGenerators/TreeDataGenerator.gd.uid new file mode 100644 index 0000000..671d085 --- /dev/null +++ b/Utilities/EntityDataGenerators/TreeDataGenerator.gd.uid @@ -0,0 +1 @@ +uid://c4ucwkf5w0ru diff --git a/Utilities/MapData/CellDataResource.gd b/Utilities/MapData/CellDataResource.gd index b3e8526..9f661e6 100644 --- a/Utilities/MapData/CellDataResource.gd +++ b/Utilities/MapData/CellDataResource.gd @@ -12,7 +12,6 @@ extends Resource @export var trees: Array = [] -func add_trees(qty: int) -> void: +func add_trees(tree: TreeDataResource, qty: int) -> void: for i in qty: - var tree = TreeDataResource.new() trees.append(tree) diff --git a/Utilities/MapData/MapPopulation.gd b/Utilities/MapData/MapPopulation.gd index 2582284..68fe2b9 100644 --- a/Utilities/MapData/MapPopulation.gd +++ b/Utilities/MapData/MapPopulation.gd @@ -7,14 +7,42 @@ var map_data: Array = Global.map_data ## Setup the X and Z ## If it's a path or water we do nothing else for now ## If it's anything else then we need to: - ## Set grass density directly from the vegetation density - ## Then do the following: - ## Density < 0.5 - chance of spawning special stuff and nothing else - ## Density > 0.6 - add trees, varying quantity from 0.6 to 1 - ## Density 0.1 to 0.6 - add bushes, varying quantity TBD - ## Density 0.1 to 0.4 - add flowers, varying quantity TBD + ## Set grass density directly from the vegetation density + ## Then do the following: + ## Density < 0.5 - chance of spawning special stuff and nothing else + ## Density > 0.6 - add trees, varying quantity from 0.6 to 1 + ## Density 0.1 to 0.6 - add bushes, varying quantity TBD + ## Density 0.1 to 0.4 - add flowers, varying quantity TBD -static func generate_cell(x: int, z: int, density: float, path: bool = false, water: bool = false): +# Weighted random selection based on tree chances +static func select_weighted_tree(tree_preferences: Dictionary): + if tree_preferences.is_empty(): + return null + + # Calculate total weight + var total_weight = 0.0 + for tree_name in tree_preferences.keys(): + total_weight += tree_preferences[tree_name]["chance"] + + if total_weight <= 0.0: + return null + + # Generate random number between 0 and total_weight + var random_value = randf() * total_weight + + # Find which tree this random value corresponds to + var cumulative_weight = 0.0 + for tree_name in tree_preferences.keys(): + cumulative_weight += tree_preferences[tree_name]["chance"] + if random_value <= cumulative_weight: + return tree_preferences[tree_name]["resource"] + + # Fallback (shouldn't happen, but just in case) + var first_key = tree_preferences.keys()[0] + return tree_preferences[first_key]["resource"] + +# Pre-calculate tree distribution for the cell +static func generate_cell_with_distribution(x: int, z: int, density: float, path: bool = false, water: bool = false): var cell_data = CellDataResource.new() cell_data.x = x cell_data.z = z @@ -22,6 +50,51 @@ static func generate_cell(x: int, z: int, density: float, path: bool = false, wa if not (path or water): if density >= 0.6: - cell_data.add_trees(int(density * 10 / 2)) + var tree_preferences = BiomeData.calculate_tree_probabilities(x, z) + var tree_distribution = calculate_tree_distribution(tree_preferences, density) + + # Add trees based on calculated distribution + for tree_type in tree_distribution.keys(): + var quantity = tree_distribution[tree_type]["quantity"] + var resource = tree_distribution[tree_type]["resource"].duplicate() + if quantity > 0: + cell_data.add_trees(resource, quantity) Global.map_data[x][z] = cell_data + +# Calculate how many of each tree type to spawn +static func calculate_tree_distribution(tree_preferences: Dictionary, density: float) -> Dictionary: + var distribution = {} + + if tree_preferences.is_empty(): + return distribution + + # Calculate total number of trees for this cell + var total_trees = int((density / 2) * 10) + randi_range(1, 3) + #var total_trees = int((density - 0.6) * 25) + randi_range(3, 8) + + # Normalize the chances to get proportions + var total_weight = 0.0 + for tree_name in tree_preferences.keys(): + total_weight += tree_preferences[tree_name]["chance"] + + if total_weight <= 0.0: + return distribution + + # Distribute trees based on weighted probabilities + for tree_name in tree_preferences.keys(): + var proportion = tree_preferences[tree_name]["chance"] / total_weight + var base_quantity = int(total_trees * proportion) + + # Add some randomness - chance to get +1 tree based on remainder + var remainder = (total_trees * proportion) - base_quantity + if randf() < remainder: + base_quantity += 1 + + if base_quantity > 0: + distribution[tree_name] = { + "quantity": base_quantity, + "resource": tree_preferences[tree_name]["resource"] + } + + return distribution diff --git a/Utilities/MapGeneration/MapGeneration.gd b/Utilities/MapGeneration/MapGeneration.gd index f61d65c..04301b3 100644 --- a/Utilities/MapGeneration/MapGeneration.gd +++ b/Utilities/MapGeneration/MapGeneration.gd @@ -41,9 +41,10 @@ func _ready(): generate_map() generate_paths() generate_water_bodies() + BiomeGenerationClass.generate_environment_maps(map_width, map_height) generate_final_map_data() - + #if export_image: # export_map_as_image() @@ -52,7 +53,7 @@ func generate_final_map_data(): for y in range(map_height): for x in range(map_width): - MapPopulationClass.generate_cell(x, y, map_data[y][x], is_path_at(x, y), is_water_at(x, y)) + MapPopulationClass.generate_cell_with_distribution(x, y, map_data[y][x], is_path_at(x, y), is_water_at(x, y)) # Check immediately after await get_tree().process_frame diff --git a/project.godot b/project.godot index 3ddb29a..3fd6561 100644 --- a/project.godot +++ b/project.godot @@ -21,6 +21,7 @@ Debug="*res://Utilities/Debug/DebugHelper.gd" Global="*res://Config/Globals.gd" DebugMenu="*res://addons/debug_menu/debug_menu.tscn" MapGeneration="*res://Utilities/MapGeneration/MapGeneration.gd" +BiomeData="*res://Utilities/BiomeGeneration/BiomeData.gd" MapData="*res://Utilities/MapData/MapData.gd" MapPopulation="*res://Utilities/MapData/MapPopulation.gd" @@ -60,6 +61,10 @@ jump={ ] } +[network] + +limits/debugger/max_chars_per_second=1000000 + [shader_globals] wind_direction={ diff --git a/stages/Test3D/Test3d.tscn b/stages/Test3D/Test3d.tscn index 706066b..662f6b0 100644 --- a/stages/Test3D/Test3d.tscn +++ b/stages/Test3D/Test3d.tscn @@ -463,11 +463,12 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 stretch = true +stretch_shrink = 2 [node name="SubViewport" type="SubViewport" parent="SubViewportContainer"] transparent_bg = true handle_input_locally = false -size = Vector2i(1152, 648) +size = Vector2i(576, 324) render_target_update_mode = 4 [node name="Player" type="CharacterBody3D" parent="SubViewportContainer/SubViewport" groups=["player"]] @@ -771,7 +772,7 @@ draw_pass_1 = SubResource("QuadMesh_hvb1l") [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) light_color = Color(0.89, 0.461613, 0.2136, 1) -light_energy = 0.849132 +light_energy = 0.668778 light_indirect_energy = 1.084 light_volumetric_fog_energy = 3.764 light_size = 0.105 diff --git a/stages/UI/debug_ui.gd b/stages/UI/debug_ui.gd index cc21d0c..33188e3 100644 --- a/stages/UI/debug_ui.gd +++ b/stages/UI/debug_ui.gd @@ -5,15 +5,45 @@ extends Control @onready var loaded_ojects_label = $PanelContainer/VBoxContainer/LoadedTreesLabel func _ready() -> void: - update_map_size() update_cell_count() -func _process(delta: float) -> void: +func _process(_delta: float) -> void: + update_map_size() update_loaded_cells_count() update_loaded_objects() func update_map_size() -> void: - map_size_label.text = 'Map Dimensions: ' + str(Global.map_height) + 'x' + str(Global.map_width) + var player_pos = %Player.position + var cell_x = int(player_pos.x / 2.0) + var cell_z = int(player_pos.z / 2.0) + + # Get biome data for current cell + var biome_info = "" + if Global.biome_data != null and not Global.biome_data.is_empty(): + # Check bounds to avoid errors + var moisture_img = Global.biome_data.get("moisture") + var temp_img = Global.biome_data.get("temperature") + var elev_img = Global.biome_data.get("elevation") + + if moisture_img != null and temp_img != null and elev_img != null: + # Make sure coordinates are within image bounds + var img_width = moisture_img.get_width() + var img_height = moisture_img.get_height() + + if cell_x >= 0 and cell_x < img_width and cell_z >= 0 and cell_z < img_height: + var moisture = moisture_img.get_pixel(cell_x, cell_z).r + var temperature = temp_img.get_pixel(cell_x, cell_z).r + var elevation = elev_img.get_pixel(cell_x, cell_z).r + + biome_info = "\nMoisture: %.2f | Temp: %.2f | Elevation: %.2f" % [moisture, temperature, elevation] + else: + biome_info = "\nBiome: Out of bounds" + else: + biome_info = "\nBiome: Data not available" + else: + biome_info = "\nBiome: Not initialized" + + map_size_label.text = 'X: %.1f, Z: %.1f | Cell: (%d, %d)%s' % [player_pos.x, player_pos.z, cell_x, cell_z, biome_info] func update_cell_count() -> void: cell_count_label.text = 'Cell Count: ' + str(Global.map_height * Global.map_width) @@ -81,13 +111,3 @@ func format_bytes(bytes: float) -> String: return str(int(bytes / 1024)) + "KB" else: return str(int(bytes / (1024 * 1024))) + "MB" - -# Add to your debug script -func track_orphan_creation(): - # Hook into the scene tree to catch orphan creation - get_tree().node_removed.connect(_on_node_orphaned) - -func _on_node_orphaned(node: Node): - print("Orphan created: ", node.name, " (", node.get_class(), ")") - if node.get_script(): - print(" Script: ", node.get_script().resource_path)