google_play_games_manager.dart 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import 'package:games_services/games_services.dart';
  2. import 'dart:async';
  3. import 'dart:io';
  4. /// Manages Google Play Games Services integration
  5. class GooglePlayGamesManager {
  6. static GooglePlayGamesManager? _instance;
  7. static GooglePlayGamesManager get instance {
  8. _instance ??= GooglePlayGamesManager._internal();
  9. return _instance!;
  10. }
  11. GooglePlayGamesManager._internal();
  12. bool _isInitialized = false;
  13. bool _isSignedIn = false;
  14. String? _playerId;
  15. String? _playerName;
  16. // Achievement IDs - These need to be configured in Google Play Console
  17. static const String achievementFirstBubble = 'achievement_first_bubble';
  18. static const String achievement100Bubbles = 'achievement_100_bubbles';
  19. static const String achievement1000Bubbles = 'achievement_1000_bubbles';
  20. static const String achievement5000Bubbles = 'achievement_5000_bubbles';
  21. static const String achievementZenMaster = 'achievement_zen_master';
  22. static const String achievementSpeedDemon = 'achievement_speed_demon';
  23. static const String achievementPerfectSession = 'achievement_perfect_session';
  24. // Leaderboard IDs - These need to be configured in Google Play Console
  25. static const String leaderboardHighScore = 'leaderboard_high_score';
  26. static const String leaderboardZenMode = 'leaderboard_zen_mode';
  27. static const String leaderboardTotalBubbles = 'leaderboard_total_bubbles';
  28. static const String leaderboardLongestSession = 'leaderboard_longest_session';
  29. /// Initialize Google Play Games Services
  30. Future<bool> initialize() async {
  31. if (_isInitialized) return true;
  32. try {
  33. // Only available on Android
  34. if (!Platform.isAndroid) {
  35. print('Google Play Games Services only available on Android');
  36. return false;
  37. }
  38. _isInitialized = true;
  39. return true;
  40. } catch (e) {
  41. print('Error initializing Google Play Games: $e');
  42. return false;
  43. }
  44. }
  45. /// Sign in to Google Play Games
  46. Future<bool> signIn() async {
  47. if (!_isInitialized) {
  48. await initialize();
  49. }
  50. try {
  51. final result = await GamesServices.signIn();
  52. _isSignedIn = result != null && result.isNotEmpty;
  53. if (_isSignedIn) {
  54. _playerId = result;
  55. print('Successfully signed in to Google Play Games: $_playerId');
  56. // Get player name
  57. try {
  58. final playerName = await GamesServices.getPlayerName();
  59. _playerName = playerName;
  60. print('Player name: $_playerName');
  61. } catch (e) {
  62. print('Could not get player name: $e');
  63. }
  64. }
  65. return _isSignedIn;
  66. } catch (e) {
  67. print('Error signing in to Google Play Games: $e');
  68. _isSignedIn = false;
  69. return false;
  70. }
  71. }
  72. /// Sign out from Google Play Games
  73. Future<void> signOut() async {
  74. try {
  75. // Note: games_services package doesn't have a signOut method
  76. // We'll just reset our local state
  77. _isSignedIn = false;
  78. _playerId = null;
  79. _playerName = null;
  80. print('Successfully signed out from Google Play Games');
  81. } catch (e) {
  82. print('Error signing out from Google Play Games: $e');
  83. }
  84. }
  85. /// Check if signed in
  86. bool get isSignedIn => _isSignedIn;
  87. /// Get player ID
  88. String? get playerId => _playerId;
  89. /// Get player name
  90. String? get playerName => _playerName;
  91. /// Submit score to leaderboard
  92. Future<bool> submitScore(String leaderboardId, int score) async {
  93. if (!_isSignedIn) {
  94. print('Not signed in to Google Play Games');
  95. return false;
  96. }
  97. try {
  98. await GamesServices.submitScore(
  99. score: Score(
  100. androidLeaderboardID: leaderboardId,
  101. value: score,
  102. ),
  103. );
  104. print('Score $score submitted to leaderboard $leaderboardId');
  105. return true;
  106. } catch (e) {
  107. print('Error submitting score: $e');
  108. return false;
  109. }
  110. }
  111. /// Show leaderboards
  112. Future<void> showLeaderboards() async {
  113. if (!_isSignedIn) {
  114. print('Not signed in to Google Play Games');
  115. return;
  116. }
  117. try {
  118. await GamesServices.showLeaderboards();
  119. } catch (e) {
  120. print('Error showing leaderboards: $e');
  121. }
  122. }
  123. /// Show specific leaderboard
  124. Future<void> showLeaderboard(String leaderboardId) async {
  125. if (!_isSignedIn) {
  126. print('Not signed in to Google Play Games');
  127. return;
  128. }
  129. try {
  130. await GamesServices.showLeaderboards(
  131. androidLeaderboardID: leaderboardId,
  132. );
  133. } catch (e) {
  134. print('Error showing leaderboard: $e');
  135. }
  136. }
  137. /// Unlock achievement
  138. Future<bool> unlockAchievement(String achievementId) async {
  139. if (!_isSignedIn) {
  140. print('Not signed in to Google Play Games');
  141. return false;
  142. }
  143. try {
  144. await GamesServices.unlock(
  145. achievement: Achievement(
  146. androidID: achievementId,
  147. ),
  148. );
  149. print('Achievement $achievementId unlocked');
  150. return true;
  151. } catch (e) {
  152. print('Error unlocking achievement: $e');
  153. return false;
  154. }
  155. }
  156. /// Increment achievement (for incremental achievements)
  157. Future<bool> incrementAchievement(String achievementId, int steps) async {
  158. if (!_isSignedIn) {
  159. print('Not signed in to Google Play Games');
  160. return false;
  161. }
  162. try {
  163. await GamesServices.increment(
  164. achievement: Achievement(
  165. androidID: achievementId,
  166. steps: steps,
  167. ),
  168. );
  169. print('Achievement $achievementId incremented by $steps steps');
  170. return true;
  171. } catch (e) {
  172. print('Error incrementing achievement: $e');
  173. return false;
  174. }
  175. }
  176. /// Show achievements
  177. Future<void> showAchievements() async {
  178. if (!_isSignedIn) {
  179. print('Not signed in to Google Play Games');
  180. return;
  181. }
  182. try {
  183. await GamesServices.showAchievements();
  184. } catch (e) {
  185. print('Error showing achievements: $e');
  186. }
  187. }
  188. /// Check achievement-related milestones for bubble popping
  189. Future<void> checkBubbleAchievements(int totalBubbles) async {
  190. if (!_isSignedIn) return;
  191. // First bubble achievement
  192. if (totalBubbles >= 1) {
  193. await unlockAchievement(achievementFirstBubble);
  194. }
  195. // 100 bubbles achievement
  196. if (totalBubbles >= 100) {
  197. await unlockAchievement(achievement100Bubbles);
  198. }
  199. // 1000 bubbles achievement
  200. if (totalBubbles >= 1000) {
  201. await unlockAchievement(achievement1000Bubbles);
  202. }
  203. // 5000 bubbles achievement
  204. if (totalBubbles >= 5000) {
  205. await unlockAchievement(achievement5000Bubbles);
  206. }
  207. }
  208. /// Check zen mode achievements
  209. Future<void> checkZenModeAchievements(double sessionTime) async {
  210. if (!_isSignedIn) return;
  211. // Zen master achievement (10 minutes in zen mode)
  212. if (sessionTime >= 600) {
  213. await unlockAchievement(achievementZenMaster);
  214. }
  215. }
  216. /// Check score-based achievements
  217. Future<void> checkScoreAchievements(int score, double timeToReachScore) async {
  218. if (!_isSignedIn) return;
  219. // Speed demon achievement (reach 1000 points in under 2 minutes)
  220. if (score >= 1000 && timeToReachScore <= 120) {
  221. await unlockAchievement(achievementSpeedDemon);
  222. }
  223. }
  224. /// Submit various scores to leaderboards
  225. Future<void> submitGameResults({
  226. required int finalScore,
  227. required bool isZenMode,
  228. required int totalBubblesPopped,
  229. required double sessionLength,
  230. }) async {
  231. if (!_isSignedIn) return;
  232. // Submit to appropriate leaderboards
  233. if (isZenMode) {
  234. await submitScore(leaderboardZenMode, sessionLength.round());
  235. } else {
  236. await submitScore(leaderboardHighScore, finalScore);
  237. }
  238. await submitScore(leaderboardTotalBubbles, totalBubblesPopped);
  239. await submitScore(leaderboardLongestSession, sessionLength.round());
  240. // Check achievements
  241. await checkBubbleAchievements(totalBubblesPopped);
  242. if (isZenMode) {
  243. await checkZenModeAchievements(sessionLength);
  244. } else {
  245. await checkScoreAchievements(finalScore, sessionLength);
  246. }
  247. }
  248. }