zentap_game.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import 'package:flame/components.dart';
  2. import 'package:flame/effects.dart';
  3. import 'package:flame/game.dart';
  4. import 'package:flutter/material.dart';
  5. import '../utils/colors.dart';
  6. import 'components/bubble.dart';
  7. import 'components/bubble_spawner.dart';
  8. import 'audio/audio_manager.dart';
  9. class ZenTapGame extends FlameGame {
  10. static const String routeName = '/game';
  11. TextComponent? scoreText;
  12. TextComponent? timerText;
  13. int score = 0;
  14. bool isZenMode = false;
  15. double gameTime = 0.0;
  16. bool gameActive = true;
  17. BubbleSpawner? bubbleSpawner;
  18. final AudioManager audioManager = AudioManager();
  19. @override
  20. Color backgroundColor() => ZenColors.appBackground;
  21. @override
  22. Future<void> onLoad() async {
  23. await super.onLoad();
  24. // Initialize audio
  25. await audioManager.initialize();
  26. // Initialize score display
  27. scoreText = TextComponent(
  28. text: isZenMode ? 'Zen Mode' : 'Relaxation Points: $score',
  29. textRenderer: TextPaint(
  30. style: const TextStyle(
  31. color: ZenColors.scoreText,
  32. fontSize: 24,
  33. fontWeight: FontWeight.w500,
  34. ),
  35. ),
  36. position: Vector2(20, 50),
  37. );
  38. add(scoreText!);
  39. // Initialize timer display (only in regular mode)
  40. if (!isZenMode) {
  41. timerText = TextComponent(
  42. text: 'Time: ${gameTime.toInt()}s',
  43. textRenderer: TextPaint(
  44. style: const TextStyle(
  45. color: ZenColors.timerText,
  46. fontSize: 18,
  47. ),
  48. ),
  49. position: Vector2(20, 80),
  50. );
  51. add(timerText!);
  52. }
  53. // Add initial game elements
  54. await _initializeGame();
  55. }
  56. Future<void> _initializeGame() async {
  57. // Initialize bubble spawner
  58. bubbleSpawner = BubbleSpawner(
  59. onBubblePopped: _onBubblePopped,
  60. );
  61. add(bubbleSpawner!);
  62. // Add instruction text
  63. final instructionText = TextComponent(
  64. text: isZenMode ? 'Tap bubbles to relax' : 'Pop bubbles for points!',
  65. textRenderer: TextPaint(
  66. style: TextStyle(
  67. color: ZenColors.secondaryText,
  68. fontSize: 18,
  69. ),
  70. ),
  71. position: Vector2(size.x / 2, size.y / 2 + 100),
  72. anchor: Anchor.center,
  73. );
  74. add(instructionText);
  75. // Start background music
  76. await audioManager.playBackgroundMusic();
  77. }
  78. @override
  79. void update(double dt) {
  80. super.update(dt);
  81. if (gameActive && !isZenMode) {
  82. gameTime += dt;
  83. _updateTimer();
  84. }
  85. }
  86. void handleTap(Vector2 position) {
  87. if (!gameActive) return;
  88. // Create a bubble at tap position if in zen mode or no bubble was hit
  89. if (isZenMode) {
  90. bubbleSpawner?.spawnBubbleAt(position);
  91. }
  92. // Add visual feedback at tap position
  93. _addTapEffect(position);
  94. }
  95. void _onBubblePopped(Bubble bubble) {
  96. // Play pop sound and haptic feedback
  97. audioManager.playBubblePop();
  98. if (!isZenMode) {
  99. // Increment score in regular mode
  100. score += 10; // 10 points per bubble
  101. _updateScore();
  102. }
  103. }
  104. void _updateScore() {
  105. scoreText?.text = 'Relaxation Points: $score';
  106. }
  107. void _updateTimer() {
  108. timerText?.text = 'Time: ${gameTime.toInt()}s';
  109. }
  110. void _addTapEffect(Vector2 position) {
  111. // Create a simple tap effect circle with animation
  112. final tapEffect = CircleComponent(
  113. radius: 15,
  114. paint: Paint()
  115. ..color = ZenColors.bubblePopEffect.withValues(alpha: 0.6)
  116. ..style = PaintingStyle.stroke
  117. ..strokeWidth = 2,
  118. position: position,
  119. anchor: Anchor.center,
  120. );
  121. add(tapEffect);
  122. // Add scaling animation
  123. tapEffect.add(
  124. ScaleEffect.to(
  125. Vector2.all(2.0),
  126. EffectController(duration: 0.3),
  127. ),
  128. );
  129. // Add fade animation
  130. tapEffect.add(
  131. OpacityEffect.to(
  132. 0.0,
  133. EffectController(duration: 0.3),
  134. ),
  135. );
  136. // Remove the effect after animation
  137. Future.delayed(const Duration(milliseconds: 300), () {
  138. if (tapEffect.isMounted) {
  139. remove(tapEffect);
  140. }
  141. });
  142. }
  143. void setZenMode(bool zenMode) {
  144. isZenMode = zenMode;
  145. if (scoreText != null) {
  146. if (zenMode) {
  147. scoreText!.text = 'Zen Mode';
  148. score = 0;
  149. // Hide timer in zen mode
  150. timerText?.removeFromParent();
  151. timerText = null;
  152. } else {
  153. scoreText!.text = 'Relaxation Points: $score';
  154. // Show timer in regular mode
  155. if (timerText == null) {
  156. timerText = TextComponent(
  157. text: 'Time: ${gameTime.toInt()}s',
  158. textRenderer: TextPaint(
  159. style: const TextStyle(
  160. color: ZenColors.timerText,
  161. fontSize: 18,
  162. ),
  163. ),
  164. position: Vector2(20, 80),
  165. );
  166. add(timerText!);
  167. }
  168. }
  169. }
  170. // Update bubble spawner behavior
  171. bubbleSpawner?.setActive(!zenMode);
  172. }
  173. void resetGame() {
  174. score = 0;
  175. gameTime = 0.0;
  176. gameActive = true;
  177. _updateScore();
  178. _updateTimer();
  179. // Clear all bubbles
  180. bubbleSpawner?.clearAllBubbles();
  181. }
  182. void pauseGame() {
  183. paused = true;
  184. gameActive = false;
  185. audioManager.pauseBackgroundMusic();
  186. }
  187. void resumeGame() {
  188. paused = false;
  189. gameActive = true;
  190. audioManager.resumeBackgroundMusic();
  191. }
  192. @override
  193. void onRemove() {
  194. audioManager.stopBackgroundMusic();
  195. super.onRemove();
  196. }
  197. }