nature-sim/Entities/Tree/scripts/tree.gd
Dan Baker 3959333534 Adds bushes and flowers to ground tiles
Implements bush and flower spawning on ground tiles based on vegetation density.
Adds new assets for bushes and flowers, and introduces multi-mesh rendering for optimized performance.
Introduces seasonal color variations for vegetation using a shader for bushes and materials for flowers and grass.
Refactors material application into a MaterialManager to handle material assignments over multiple frames.
Moves ground tile scripts into a subfolder.
Adds floating particles to test scene.
2025-06-29 10:58:18 +01:00

134 lines
3.9 KiB
GDScript

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
var base_circle: MeshInstance3D
var circle_material: Material
func _ready():
setup_outline_material()
area.body_entered.connect(_on_player_entered)
area.body_exited.connect(_on_player_exited)
func set_tree_data(data: TreeDataResource):
tree_data = data
spawn_model()
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()
tree_data.apply_seasonal_colors(model_instance, Season.current)
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() -> void:
# 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)
for child in node.get_children():
find_all_mesh_instances(child)
func create_base_circle():
base_circle = MeshInstance3D.new()
add_child(base_circle)
# Create a flat cylinder for the circle
var cylinder = CylinderMesh.new()
cylinder.top_radius = 0.4 # Adjust size as needed
cylinder.bottom_radius = 0.4
cylinder.height = 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
base_circle.position.y = 1 # Slightly above ground to avoid z-fighting
# Start hidden
base_circle.visible = true
func _on_player_entered(body: Node3D):
if body.is_in_group("player"):
base_circle.visible = true
# Apply outline to all mesh instances
for mesh in mesh_instances:
mesh.material_overlay = outline_material
func _on_player_exited(body: Node3D):
if body.is_in_group("player"):
Log.pr('Out of range...')
base_circle.visible = false
# Remove outline from all mesh instances
for mesh in mesh_instances:
mesh.material_overlay = null