Much stuff wow
This commit is contained in:
parent
7255cbdf64
commit
734730beee
45 changed files with 697 additions and 119 deletions
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue