nature-sim/Entities/Tree/scripts/tree.gd
Dan Baker ea5006e8a2 Improves tree and ground tile appearance
Refactors tree spawning and rendering:
- Adds seasonal color variations for trees via scripts.
- Introduces `ColorStorage` to manage tree and grass colors
- Removes unused code from tree spawning logic.
- Adjusts ground tile color for better visual appeal.
- Hides debug text on ground tiles.
2025-06-28 17:21:50 +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, "spring")
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