Much stuff wow
This commit is contained in:
parent
7255cbdf64
commit
734730beee
45 changed files with 697 additions and 119 deletions
BIN
Assets/temp_models/Textures/colormap.png
(Stored with Git LFS)
Normal file
BIN
Assets/temp_models/Textures/colormap.png
(Stored with Git LFS)
Normal file
Binary file not shown.
35
Assets/temp_models/Textures/colormap.png.import
Normal file
35
Assets/temp_models/Textures/colormap.png.import
Normal file
|
|
@ -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
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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")])
|
||||
|
|
|
|||
|
|
@ -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()])
|
||||
|
|
|
|||
|
|
@ -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="."]
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
class_name TreeDataResource
|
||||
extends Resource
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
|
|
@ -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]
|
||||
|
||||
81
Entities/Tree/resources/TreeData.tres
Normal file
81
Entities/Tree/resources/TreeData.tres
Normal file
|
|
@ -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"
|
||||
20
Entities/Tree/resources/TreeDataCollection.gd
Normal file
20
Entities/Tree/resources/TreeDataCollection.gd
Normal file
|
|
@ -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
|
||||
1
Entities/Tree/resources/TreeDataCollection.gd.uid
Normal file
1
Entities/Tree/resources/TreeDataCollection.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dj4dhsd0m0bvd
|
||||
23
Entities/Tree/resources/TreeDataResource.gd
Normal file
23
Entities/Tree/resources/TreeDataResource.gd
Normal file
|
|
@ -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] = []
|
||||
|
|
@ -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
|
||||
|
|
|
|||
47
Utilities/BiomeGeneration/BiomeData.gd
Normal file
47
Utilities/BiomeGeneration/BiomeData.gd
Normal file
|
|
@ -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))
|
||||
1
Utilities/BiomeGeneration/BiomeData.gd.uid
Normal file
1
Utilities/BiomeGeneration/BiomeData.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://by8rwvoabdrgn
|
||||
35
Utilities/BiomeGeneration/BiomeGeneration.gd
Normal file
35
Utilities/BiomeGeneration/BiomeGeneration.gd
Normal file
|
|
@ -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
|
||||
1
Utilities/BiomeGeneration/BiomeGeneration.gd.uid
Normal file
1
Utilities/BiomeGeneration/BiomeGeneration.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ddle3veoss0ny
|
||||
1
Utilities/EntityDataGenerators/TreeDataGenerator.gd
Normal file
1
Utilities/EntityDataGenerators/TreeDataGenerator.gd
Normal file
|
|
@ -0,0 +1 @@
|
|||
extends Node
|
||||
1
Utilities/EntityDataGenerators/TreeDataGenerator.gd.uid
Normal file
1
Utilities/EntityDataGenerators/TreeDataGenerator.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c4ucwkf5w0ru
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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={
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue