From 66b8120eb760d47b735db65d55d05545827a6afc Mon Sep 17 00:00:00 2001 From: Nikolai Fedorov Date: Wed, 22 Apr 2026 18:49:13 +0300 Subject: [PATCH] rock respawn flow, fix flying spawn --- scripts/Main.gd | 55 ++++++++++++++++++++++++++++++++++++++++++++----- scripts/Rock.gd | 3 +++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/scripts/Main.gd b/scripts/Main.gd index 9305c01..6d3990a 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -93,13 +93,57 @@ func _process(delta: float) -> void: # ─── Rocks ──────────────────────────────────────────────────────────────────── +var rocks_on_field: int = 0 +var rocks_pending: int = 0 + +func _get_rock_limit() -> int: + return mini(2 + (wave + 1) / 2, 7) + func _spawn_rocks() -> void: - for i in range(10): - var rock := ROCK_SCENE.instantiate() - add_child(rock) + var limit := _get_rock_limit() + for i in range(limit): + _spawn_single_rock() + +func _spawn_single_rock() -> void: + var rock := ROCK_SCENE.instantiate() + rock.position = _safe_rock_position() + add_child(rock) + rock.connect("destroyed", _on_rock_destroyed) + rocks_on_field += 1 + +func _safe_rock_position() -> Vector3: + var player_pos := player.global_position if is_instance_valid(player) else Vector3.ZERO + for _attempt in range(30): var angle := randf() * TAU - var dist := randf_range(3.5, arena_size - 2.0) - rock.position = Vector3(cos(angle) * dist, 0.0, sin(angle) * dist) + var dist := randf_range(4.0, arena_size - 2.0) + var pos := Vector3(cos(angle) * dist, 0.0, sin(angle) * dist) + if player_pos.distance_to(pos) < 4.5: + continue + var clear := true + for r in get_tree().get_nodes_in_group("rocks"): + if (r as Node3D).global_position.distance_to(pos) < 1.5: + clear = false + break + if clear: + return pos + var a := randf() * TAU + return Vector3(cos(a) * (arena_size - 2.5), 0.0, sin(a) * (arena_size - 2.5)) + +func _on_rock_destroyed() -> void: + rocks_on_field = maxi(0, rocks_on_field - 1) + if not game_active: + return + if rocks_on_field + rocks_pending < _get_rock_limit(): + rocks_pending += 1 + await get_tree().create_timer(20.0).timeout + rocks_pending -= 1 + if game_active: + _spawn_single_rock() + +func _check_rock_slots() -> void: + var gap := _get_rock_limit() - rocks_on_field - rocks_pending + for i in range(gap): + _spawn_single_rock() # ─── Player ─────────────────────────────────────────────────────────────────── @@ -166,6 +210,7 @@ func _on_enemy_died(points: int) -> void: kills = 0 kills_for_next = int(kills_for_next * 1.6) wave += 1 + _check_rock_slots() _show_upgrade() func _spawn_upgraded_enemy(pos: Vector3, type: String, level: int, w: int) -> CharacterBody3D: diff --git a/scripts/Rock.gd b/scripts/Rock.gd index aaea4f0..3cbe21b 100644 --- a/scripts/Rock.gd +++ b/scripts/Rock.gd @@ -1,5 +1,7 @@ extends CharacterBody3D +signal destroyed + enum State { IDLE, FLYING } const AIR_FRICTION := 0.84 @@ -100,6 +102,7 @@ func _die() -> void: dead = true state = State.IDLE set_physics_process(false) + emit_signal("destroyed") var tw := create_tween() tw.tween_property(self, "scale", Vector3(1.6, 0.1, 1.6), 0.12) tw.tween_property(self, "scale", Vector3(0.0, 0.0, 0.0), 0.1)