using UnityEngine; namespace FlappyBird.Gameplay.Pipes { /// /// Pure C# service — all pipe-spawning and timing logic. /// No MonoBehaviour, no Unity lifecycle. Ticked externally by PipeSpawnerTicker. /// public sealed class PipeSpawner : IPipeSpawner { private readonly IPipePool _pool; private readonly PipeSettings _settings; private float _timer; /// Constructor injection. public PipeSpawner(IPipePool pool, PipeSettings settings) { _pool = pool; _settings = settings; } // ── IPipeSpawner ─────────────────────────────────────────────────── /// public void Tick(float deltaTime) { _timer += deltaTime; if (_timer >= _settings.SpawnInterval) { _timer -= _settings.SpawnInterval; SpawnPair(); } } /// public void ResetTimer() => _timer = 0f; // ── Private helpers ──────────────────────────────────────────────── /// /// Fetches a pipe pair from the pool, positions it with a random gap centre, /// then places the top and bottom pipe transforms around that gap. /// private void SpawnPair() { float gapCentreY = Random.Range(_settings.MinGapCentreY, _settings.MaxGapCentreY); float halfGap = _settings.GapSize * 0.5f; float pipeOffset = _settings.PipeHalfHeight; // shifts pivot to tip when centred PipeView pipe = _pool.Get(); pipe.transform.position = new Vector3(_settings.SpawnX, 0f, 0f); // Bottom pipe: pivot centre pushed downward so the tip meets the gap edge. pipe.BottomPipe.position = new Vector3( _settings.SpawnX, gapCentreY - halfGap - pipeOffset, 0f); // Top pipe: pivot centre pushed upward so the tip meets the gap edge. pipe.TopPipe.position = new Vector3( _settings.SpawnX, gapCentreY + halfGap + pipeOffset, 0f); } } }