import 'dart:math'; import 'package:flame/components.dart'; import 'bubble.dart'; class BubbleSpawner extends Component with HasGameReference { static const double spawnInterval = 2.0; // seconds static const int maxBubbles = 8; double _timeSinceLastSpawn = 0; final List _activeBubbles = []; final Random _random = Random(); Function(Bubble)? onBubblePopped; bool isActive = true; BubbleSpawner({this.onBubblePopped}); @override void update(double dt) { super.update(dt); if (!isActive) return; _timeSinceLastSpawn += dt; // Spawn new bubble if conditions are met if (_timeSinceLastSpawn >= spawnInterval && _activeBubbles.length < maxBubbles) { _spawnBubble(); _timeSinceLastSpawn = 0; } // Clean up popped bubbles _activeBubbles.removeWhere((bubble) => !bubble.isMounted); } void _spawnBubble() { if (game.size.x == 0 || game.size.y == 0) return; // Calculate safe spawn area (avoiding edges and UI elements) const margin = 80.0; final minX = margin; final maxX = game.size.x - margin; final minY = margin + 100; // Extra margin for score display final maxY = game.size.y - margin; if (maxX <= minX || maxY <= minY) return; final spawnPosition = Vector2( minX + _random.nextDouble() * (maxX - minX), minY + _random.nextDouble() * (maxY - minY), ); final bubble = Bubble( position: spawnPosition, onPop: _onBubblePopped, ); _activeBubbles.add(bubble); game.add(bubble); } void _onBubblePopped(Bubble bubble) { _activeBubbles.remove(bubble); onBubblePopped?.call(bubble); } void spawnBubbleAt(Vector2 position) { final bubble = Bubble( position: position, onPop: _onBubblePopped, ); _activeBubbles.add(bubble); game.add(bubble); } void clearAllBubbles() { for (final bubble in _activeBubbles) { if (bubble.isMounted) { bubble.removeFromParent(); } } _activeBubbles.clear(); } void setActive(bool active) { isActive = active; } int get activeBubbleCount => _activeBubbles.length; }