feat: add spreading mushroom to playground level

This commit is contained in:
2026-05-12 17:06:23 -05:00
parent 3f3136c453
commit 2907fabe85
4 changed files with 135 additions and 47 deletions
+75
View File
@@ -0,0 +1,75 @@
extends Node3D
@export var spread_radius := 2.0
@export var spread_interval_min := 5.0
@export var spread_interval_max := 15.0
@export var max_mushrooms_in_radius := 3
@export var check_radius := 1.5
@export var max_total_mushrooms := 50
static var total_mushrooms := 0
@onready var spread_timer: Timer = $SpreadTimer
@onready var ground_ray: RayCast3D = $GroundRay
func _ready() -> void:
total_mushrooms += 1
_setup_timer()
# Randomize initial scale for variety
scale = Vector3.ONE * randf_range(0.8, 1.2)
rotation.y = randf_range(0, TAU)
func _setup_timer() -> void:
spread_timer.wait_time = randf_range(spread_interval_min, spread_interval_max)
spread_timer.start()
func _on_spread_timer_timeout() -> void:
if total_mushrooms >= max_total_mushrooms:
return
if _count_nearby_mushrooms() >= max_mushrooms_in_radius:
# Too crowded, try again later
_setup_timer()
return
_attempt_spread()
_setup_timer()
func _attempt_spread() -> void:
var random_angle := randf_range(0, TAU)
var random_dist := randf_range(spread_radius * 0.5, spread_radius)
var offset := Vector3(cos(random_angle) * random_dist, 5.0, sin(random_angle) * random_dist)
ground_ray.position = offset
ground_ray.force_raycast_update()
if ground_ray.is_colliding():
var collision_point := ground_ray.get_collision_point()
var collision_normal := ground_ray.get_collision_normal()
# Only spread on relatively flat surfaces
if collision_normal.dot(Vector3.UP) > 0.7:
_spawn_mushroom(collision_point)
func _spawn_mushroom(pos: Vector3) -> void:
var mushroom_scene = load(scene_file_path)
var new_mushroom = mushroom_scene.instantiate()
get_parent().add_child(new_mushroom)
new_mushroom.global_position = pos
# Visual feedback/animation
new_mushroom.scale = Vector3.ZERO
var tween = create_tween()
tween.tween_property(new_mushroom, "scale", Vector3.ONE * randf_range(0.8, 1.2), 1.0).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
func _count_nearby_mushrooms() -> int:
var count := 0
for mushroom in get_tree().get_nodes_in_group("mushrooms"):
if mushroom == self: continue
if global_position.distance_to(mushroom.global_position) < check_radius:
count += 1
return count
func _exit_tree() -> void:
total_mushrooms -= 1
+1
View File
@@ -0,0 +1 @@
uid://brtwt4rp650ao
+40
View File
@@ -0,0 +1,40 @@
[gd_scene load_steps=6 format=3]
[ext_resource type="Script" path="res://scenes/Interaction/mushroom.gd" id="1_m1s2h"]
[sub_resource type="CylinderMesh" id="CylinderMesh_stem"]
top_radius = 0.05
bottom_radius = 0.05
height = 0.15
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_stem"]
albedo_color = Color(0.9, 0.85, 0.7, 1)
[sub_resource type="SphereMesh" id="SphereMesh_cap"]
radius = 0.15
height = 0.1
is_hemisphere = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cap"]
albedo_color = Color(0.8, 0.2, 0.2, 1)
[node name="Mushroom" type="Node3D" groups=["mushrooms"]]
script = ExtResource("1_m1s2h")
[node name="Stem" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0)
mesh = SubResource("CylinderMesh_stem")
surface_material_override/0 = SubResource("StandardMaterial3D_stem")
[node name="Cap" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.15, 0)
mesh = SubResource("SphereMesh_cap")
surface_material_override/0 = SubResource("StandardMaterial3D_cap")
[node name="SpreadTimer" type="Timer" parent="."]
one_shot = true
[node name="GroundRay" type="RayCast3D" parent="."]
target_position = Vector3(0, -10, 0)
[connection signal="timeout" from="SpreadTimer" to="." method="_on_spread_timer_timeout"]