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 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) 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