import 'package:flame/components.dart'; import 'package:flame/effects.dart'; import 'package:flame/game.dart'; import 'package:flutter/material.dart'; import '../utils/colors.dart'; import 'components/bubble.dart'; import 'components/bubble_spawner.dart'; import 'audio/audio_manager.dart'; class ZenTapGame extends FlameGame { static const String routeName = '/game'; TextComponent? scoreText; TextComponent? timerText; int score = 0; bool isZenMode = false; double gameTime = 0.0; bool gameActive = true; BubbleSpawner? bubbleSpawner; final AudioManager audioManager = AudioManager(); @override Color backgroundColor() => ZenColors.appBackground; @override Future onLoad() async { await super.onLoad(); // Initialize audio await audioManager.initialize(); // Initialize score display scoreText = TextComponent( text: isZenMode ? 'Zen Mode' : 'Relaxation Points: $score', textRenderer: TextPaint( style: const TextStyle( color: ZenColors.scoreText, fontSize: 24, fontWeight: FontWeight.w500, ), ), position: Vector2(20, 50), ); add(scoreText!); // Initialize timer display (only in regular mode) if (!isZenMode) { timerText = TextComponent( text: 'Time: ${gameTime.toInt()}s', textRenderer: TextPaint( style: const TextStyle( color: ZenColors.timerText, fontSize: 18, ), ), position: Vector2(20, 80), ); add(timerText!); } // Add initial game elements await _initializeGame(); } Future _initializeGame() async { // Initialize bubble spawner bubbleSpawner = BubbleSpawner( onBubblePopped: _onBubblePopped, ); add(bubbleSpawner!); // Add instruction text final instructionText = TextComponent( text: isZenMode ? 'Tap bubbles to relax' : 'Pop bubbles for points!', textRenderer: TextPaint( style: TextStyle( color: ZenColors.secondaryText, fontSize: 18, ), ), position: Vector2(size.x / 2, size.y / 2 + 100), anchor: Anchor.center, ); add(instructionText); // Start background music await audioManager.playBackgroundMusic(); } @override void update(double dt) { super.update(dt); if (gameActive && !isZenMode) { gameTime += dt; _updateTimer(); } } void handleTap(Vector2 position) { if (!gameActive) return; // Create a bubble at tap position if in zen mode or no bubble was hit if (isZenMode) { bubbleSpawner?.spawnBubbleAt(position); } // Add visual feedback at tap position _addTapEffect(position); } void _onBubblePopped(Bubble bubble) { // Play pop sound and haptic feedback audioManager.playBubblePop(); if (!isZenMode) { // Increment score in regular mode score += 10; // 10 points per bubble _updateScore(); } } void _updateScore() { scoreText?.text = 'Relaxation Points: $score'; } void _updateTimer() { timerText?.text = 'Time: ${gameTime.toInt()}s'; } void _addTapEffect(Vector2 position) { // Create a simple tap effect circle with animation final tapEffect = CircleComponent( radius: 15, paint: Paint() ..color = ZenColors.bubblePopEffect.withValues(alpha: 0.6) ..style = PaintingStyle.stroke ..strokeWidth = 2, position: position, anchor: Anchor.center, ); add(tapEffect); // Add scaling animation tapEffect.add( ScaleEffect.to( Vector2.all(2.0), EffectController(duration: 0.3), ), ); // Add fade animation tapEffect.add( OpacityEffect.to( 0.0, EffectController(duration: 0.3), ), ); // Remove the effect after animation Future.delayed(const Duration(milliseconds: 300), () { if (tapEffect.isMounted) { remove(tapEffect); } }); } void setZenMode(bool zenMode) { isZenMode = zenMode; if (scoreText != null) { if (zenMode) { scoreText!.text = 'Zen Mode'; score = 0; // Hide timer in zen mode timerText?.removeFromParent(); timerText = null; } else { scoreText!.text = 'Relaxation Points: $score'; // Show timer in regular mode if (timerText == null) { timerText = TextComponent( text: 'Time: ${gameTime.toInt()}s', textRenderer: TextPaint( style: const TextStyle( color: ZenColors.timerText, fontSize: 18, ), ), position: Vector2(20, 80), ); add(timerText!); } } } // Update bubble spawner behavior bubbleSpawner?.setActive(!zenMode); } void resetGame() { score = 0; gameTime = 0.0; gameActive = true; _updateScore(); _updateTimer(); // Clear all bubbles bubbleSpawner?.clearAllBubbles(); } void pauseGame() { paused = true; gameActive = false; audioManager.pauseBackgroundMusic(); } void resumeGame() { paused = false; gameActive = true; audioManager.resumeBackgroundMusic(); } @override void onRemove() { audioManager.stopBackgroundMusic(); super.onRemove(); } }