react-native-games 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/README.md +80 -368
  2. package/lib/module/games/balloon-blaster/BalloonBlaster.js +1 -167
  3. package/lib/module/games/balloon-blaster/BalloonBlaster.js.map +1 -1
  4. package/lib/module/games/balloon-blaster/BalloonBlasterConstants.js +1 -182
  5. package/lib/module/games/balloon-blaster/BalloonBlasterConstants.js.map +1 -1
  6. package/lib/module/games/balloon-blaster/BalloonBlasterService.js +1 -318
  7. package/lib/module/games/balloon-blaster/BalloonBlasterStore.js +1 -183
  8. package/lib/module/games/balloon-blaster/components/BalloonComponent.js +1 -237
  9. package/lib/module/games/balloon-blaster/components/GameArea.js +1 -156
  10. package/lib/module/games/balloon-blaster/components/GameBackground.js +1 -476
  11. package/lib/module/games/balloon-blaster/components/ScoreBoard.js +1 -112
  12. package/lib/module/games/balloon-blaster/components/ScoreBoard.js.map +1 -1
  13. package/lib/module/games/balloon-blaster/components/index.js +1 -7
  14. package/lib/module/games/candy-crush/CandyCrush.js +1 -131
  15. package/lib/module/games/candy-crush/CandyCrush.js.map +1 -1
  16. package/lib/module/games/candy-crush/CandyCrushConstants.js +1 -125
  17. package/lib/module/games/candy-crush/CandyCrushConstants.js.map +1 -1
  18. package/lib/module/games/candy-crush/CandyCrushService.js +1 -370
  19. package/lib/module/games/candy-crush/CandyCrushStore.js +1 -303
  20. package/lib/module/games/candy-crush/components/CandyItem.js +1 -191
  21. package/lib/module/games/candy-crush/components/GameBackground.js +1 -85
  22. package/lib/module/games/candy-crush/components/GameGrid.js +1 -314
  23. package/lib/module/games/candy-crush/components/ScoreBoard.js +1 -79
  24. package/lib/module/games/candy-crush/components/index.js +1 -7
  25. package/lib/module/games/candy-crush/index.js +1 -6
  26. package/lib/module/games/colors-sort/ColorsSort.js +1 -143
  27. package/lib/module/games/colors-sort/ColorsSort.js.map +1 -1
  28. package/lib/module/games/colors-sort/ColorsSortConstants.js +1 -72
  29. package/lib/module/games/colors-sort/ColorsSortConstants.js.map +1 -1
  30. package/lib/module/games/colors-sort/ColorsSortService.js +1 -255
  31. package/lib/module/games/colors-sort/ColorsSortStore.js +1 -257
  32. package/lib/module/games/colors-sort/ColorsSortStore.js.map +1 -1
  33. package/lib/module/games/colors-sort/components/ColorContainer.js +1 -140
  34. package/lib/module/games/colors-sort/components/GameBackground.js +1 -135
  35. package/lib/module/games/colors-sort/components/ScoreBoard.js +1 -70
  36. package/lib/module/games/colors-sort/components/index.js +1 -6
  37. package/lib/module/games/dino-jump/DinoJump.js +1 -209
  38. package/lib/module/games/dino-jump/DinoJump.js.map +1 -1
  39. package/lib/module/games/dino-jump/DinoJumpConstants.js +1 -189
  40. package/lib/module/games/dino-jump/DinoJumpConstants.js.map +1 -1
  41. package/lib/module/games/dino-jump/DinoJumpService.js +1 -270
  42. package/lib/module/games/dino-jump/DinoJumpStore.js +1 -381
  43. package/lib/module/games/dino-jump/components/DinoSprite.js +1 -418
  44. package/lib/module/games/dino-jump/components/DinoSprite.js.map +1 -1
  45. package/lib/module/games/dino-jump/components/GameArea.js +1 -68
  46. package/lib/module/games/dino-jump/components/GameBackground.js +1 -444
  47. package/lib/module/games/dino-jump/components/ObstacleSprite.js +1 -306
  48. package/lib/module/games/dino-jump/components/ScoreBoard.js +1 -105
  49. package/lib/module/games/dino-jump/components/ScoreBoard.js.map +1 -1
  50. package/lib/module/games/dino-jump/components/StarSprite.js +1 -45
  51. package/lib/module/games/dino-jump/components/index.js +1 -9
  52. package/lib/module/games/flappy-bird/FlappyBird.js +1 -126
  53. package/lib/module/games/flappy-bird/FlappyBird.js.map +1 -1
  54. package/lib/module/games/flappy-bird/FlappyBirdConstants.js +1 -90
  55. package/lib/module/games/flappy-bird/FlappyBirdConstants.js.map +1 -1
  56. package/lib/module/games/flappy-bird/FlappyBirdStore.js +1 -300
  57. package/lib/module/games/flappy-bird/components/Bird.js +1 -87
  58. package/lib/module/games/flappy-bird/components/GameArea.js +1 -87
  59. package/lib/module/games/flappy-bird/components/GameBackground.js +1 -79
  60. package/lib/module/games/flappy-bird/components/Pipes.js +1 -172
  61. package/lib/module/games/flappy-bird/components/ScoreBoard.js +1 -73
  62. package/lib/module/games/flappy-bird/components/index.js +1 -8
  63. package/lib/module/games/fruit-merger/FruitMerger.js +1 -120
  64. package/lib/module/games/fruit-merger/FruitMerger.js.map +1 -1
  65. package/lib/module/games/fruit-merger/FruitMergerConstants.js +1 -119
  66. package/lib/module/games/fruit-merger/FruitMergerConstants.js.map +1 -1
  67. package/lib/module/games/fruit-merger/FruitMergerService.js +1 -13
  68. package/lib/module/games/fruit-merger/FruitMergerStore.js +1 -315
  69. package/lib/module/games/fruit-merger/components/FruitItem.js +1 -102
  70. package/lib/module/games/fruit-merger/components/GameArea.js +1 -103
  71. package/lib/module/games/fruit-merger/components/GameBackground.js +1 -498
  72. package/lib/module/games/fruit-merger/components/ScoreBoard.js +1 -58
  73. package/lib/module/games/fruit-merger/components/index.js +1 -7
  74. package/lib/module/games/fruit-ninja/FruitNinja.js +1 -134
  75. package/lib/module/games/fruit-ninja/FruitNinja.js.map +1 -1
  76. package/lib/module/games/fruit-ninja/FruitNinjaConstants.js +1 -148
  77. package/lib/module/games/fruit-ninja/FruitNinjaConstants.js.map +1 -1
  78. package/lib/module/games/fruit-ninja/FruitNinjaService.js +1 -311
  79. package/lib/module/games/fruit-ninja/FruitNinjaStore.js +1 -191
  80. package/lib/module/games/fruit-ninja/FruitNinjaStore.js.map +1 -1
  81. package/lib/module/games/fruit-ninja/components/FruitComponent.js +1 -99
  82. package/lib/module/games/fruit-ninja/components/GameArea.js +1 -215
  83. package/lib/module/games/fruit-ninja/components/GameBackground.js +1 -1267
  84. package/lib/module/games/fruit-ninja/components/ScoreBoard.js +1 -92
  85. package/lib/module/games/fruit-ninja/components/ScoreBoard.js.map +1 -1
  86. package/lib/module/games/fruit-ninja/components/index.js +1 -7
  87. package/lib/module/games/game-2048/Game2048.js +1 -149
  88. package/lib/module/games/game-2048/Game2048.js.map +1 -1
  89. package/lib/module/games/game-2048/Game2048Constants.js +1 -263
  90. package/lib/module/games/game-2048/Game2048Constants.js.map +1 -1
  91. package/lib/module/games/game-2048/Game2048Service.js +1 -457
  92. package/lib/module/games/game-2048/Game2048Store.js +1 -236
  93. package/lib/module/games/game-2048/components/GameBackground.js +1 -247
  94. package/lib/module/games/game-2048/components/GameGrid.js +1 -139
  95. package/lib/module/games/game-2048/components/GameTile.js +1 -72
  96. package/lib/module/games/game-2048/components/ScoreBoard.js +1 -52
  97. package/lib/module/games/game-2048/components/index.js +1 -7
  98. package/lib/module/games/maze-runner/MazeRunner.js +1 -267
  99. package/lib/module/games/maze-runner/MazeRunner.js.map +1 -1
  100. package/lib/module/games/maze-runner/MazeRunnerConstants.js +1 -100
  101. package/lib/module/games/maze-runner/MazeRunnerConstants.js.map +1 -1
  102. package/lib/module/games/maze-runner/MazeRunnerService.js +1 -586
  103. package/lib/module/games/maze-runner/components/EnhancedBallComponent.js +1 -150
  104. package/lib/module/games/maze-runner/components/EnhancedGameArea.js +1 -370
  105. package/lib/module/games/maze-runner/components/GameBackground.js +1 -175
  106. package/lib/module/games/maze-runner/components/ScoreBoard.js +1 -61
  107. package/lib/module/games/maze-runner/components/SkiaPipeComponent.js +1 -209
  108. package/lib/module/games/maze-runner/components/StaticGameBackground.js +1 -169
  109. package/lib/module/games/maze-runner/components/WallComponent.js +1 -91
  110. package/lib/module/games/maze-runner/components/index.js +1 -8
  111. package/lib/module/games/popit-fidget/PopitFidget.js +1 -285
  112. package/lib/module/games/popit-fidget/PopitFidget.js.map +1 -1
  113. package/lib/module/games/popit-fidget/PopitFidgetConstants.js +1 -113
  114. package/lib/module/games/popit-fidget/PopitFidgetConstants.js.map +1 -1
  115. package/lib/module/games/popit-fidget/PopitFidgetService.js +1 -132
  116. package/lib/module/games/popit-fidget/PopitFidgetStore.js +1 -125
  117. package/lib/module/games/popit-fidget/components/BubbleComponent.js +1 -198
  118. package/lib/module/games/popit-fidget/components/FidgetGrid.js +1 -165
  119. package/lib/module/games/popit-fidget/components/GameBackground.js +1 -177
  120. package/lib/module/games/popit-fidget/components/ScoreBoard.js +1 -61
  121. package/lib/module/games/popit-fidget/components/index.js +1 -7
  122. package/lib/module/games/sliding-numbers/SlidingNumbers.js +1 -159
  123. package/lib/module/games/sliding-numbers/SlidingNumbers.js.map +1 -1
  124. package/lib/module/games/sliding-numbers/SlidingNumbersConstants.js +1 -207
  125. package/lib/module/games/sliding-numbers/SlidingNumbersConstants.js.map +1 -1
  126. package/lib/module/games/sliding-numbers/SlidingNumbersService.js +1 -248
  127. package/lib/module/games/sliding-numbers/SlidingNumbersStore.js +1 -274
  128. package/lib/module/games/sliding-numbers/components/GameBackground.js +1 -259
  129. package/lib/module/games/sliding-numbers/components/NumbersGrid.js +1 -174
  130. package/lib/module/games/sliding-numbers/components/NumbersTile.js +1 -116
  131. package/lib/module/games/sliding-numbers/components/ScoreBoard.js +1 -64
  132. package/lib/module/games/sliding-numbers/components/index.js +1 -7
  133. package/lib/module/games/snake/Snake.js +1 -189
  134. package/lib/module/games/snake/Snake.js.map +1 -1
  135. package/lib/module/games/snake/SnakeConstants.js +1 -138
  136. package/lib/module/games/snake/SnakeConstants.js.map +1 -1
  137. package/lib/module/games/snake/SnakeService.js +1 -148
  138. package/lib/module/games/snake/SnakeStore.js +1 -182
  139. package/lib/module/games/snake/components/GameBackground.js +1 -221
  140. package/lib/module/games/snake/components/GameGrid.js +1 -153
  141. package/lib/module/games/snake/components/ScoreBoard.js +1 -51
  142. package/lib/module/games/snake/components/index.js +1 -6
  143. package/lib/module/games/snake/index.js +1 -6
  144. package/lib/module/games/space-fighter/SpaceFighter.js +1 -165
  145. package/lib/module/games/space-fighter/SpaceFighter.js.map +1 -1
  146. package/lib/module/games/space-fighter/SpaceFighterConstants.js +1 -108
  147. package/lib/module/games/space-fighter/SpaceFighterConstants.js.map +1 -1
  148. package/lib/module/games/space-fighter/SpaceFighterService.js +1 -326
  149. package/lib/module/games/space-fighter/SpaceFighterStore.js +1 -209
  150. package/lib/module/games/space-fighter/components/AsteroidComponent.js +1 -113
  151. package/lib/module/games/space-fighter/components/GameArea.js +1 -289
  152. package/lib/module/games/space-fighter/components/GameBackground.js +1 -239
  153. package/lib/module/games/space-fighter/components/ScoreBoard.js +1 -136
  154. package/lib/module/games/space-fighter/components/Spacecraft3D.js +1 -202
  155. package/lib/module/games/space-fighter/components/SpacecraftPath.js +1 -52
  156. package/lib/module/games/space-fighter/components/index.js +1 -9
  157. package/lib/module/games/whack-a-mole/WhackAMole.js +1 -270
  158. package/lib/module/games/whack-a-mole/WhackAMole.js.map +1 -1
  159. package/lib/module/games/whack-a-mole/WhackAMoleConstants.js +1 -115
  160. package/lib/module/games/whack-a-mole/WhackAMoleConstants.js.map +1 -1
  161. package/lib/module/games/whack-a-mole/WhackAMoleService.js +1 -120
  162. package/lib/module/games/whack-a-mole/WhackAMoleStore.js +1 -172
  163. package/lib/module/games/whack-a-mole/components/GameBackground.js +1 -477
  164. package/lib/module/games/whack-a-mole/components/GameGrid.js +1 -97
  165. package/lib/module/games/whack-a-mole/components/GameHole.js +1 -196
  166. package/lib/module/games/whack-a-mole/components/MoleCharacter.js +1 -241
  167. package/lib/module/games/whack-a-mole/components/ScoreBoard.js +1 -67
  168. package/lib/module/games/whack-a-mole/components/ScoreBoard.js.map +1 -1
  169. package/lib/module/games/whack-a-mole/components/index.js +1 -8
  170. package/lib/module/helpers/AnimationFrame.js +1 -120
  171. package/lib/module/helpers/AnimationTracker.js +1 -89
  172. package/lib/module/helpers/ErrorHandler.js +1 -269
  173. package/lib/module/helpers/GameControlButton.js +1 -219
  174. package/lib/module/helpers/GameOverModal.js +1 -144
  175. package/lib/module/helpers/GameOverModal.js.map +1 -1
  176. package/lib/module/helpers/GameSettingsModal.js +1 -287
  177. package/lib/module/helpers/ParticleBlast.js +1 -134
  178. package/lib/module/helpers/ScoreBoardContainer.js +1 -34
  179. package/lib/module/helpers/index.js +1 -12
  180. package/lib/module/index.js +1 -22
  181. package/lib/module/services/GamesConstants.js +1 -178
  182. package/lib/module/services/GamesService.js +1 -112
  183. package/lib/module/services/GamesService.js.map +1 -1
  184. package/lib/module/services/HapticsService.js +1 -77
  185. package/lib/module/services/SoundsService.js +1 -302
  186. package/lib/module/services/UtilsService.js +1 -32
  187. package/lib/typescript/src/games/balloon-blaster/BalloonBlaster.d.ts.map +1 -1
  188. package/lib/typescript/src/games/balloon-blaster/BalloonBlasterConstants.d.ts +1 -1
  189. package/lib/typescript/src/games/balloon-blaster/components/ScoreBoard.d.ts.map +1 -1
  190. package/lib/typescript/src/games/candy-crush/CandyCrushConstants.d.ts +7 -7
  191. package/lib/typescript/src/games/colors-sort/ColorsSort.d.ts.map +1 -1
  192. package/lib/typescript/src/games/colors-sort/ColorsSortStore.d.ts.map +1 -1
  193. package/lib/typescript/src/games/dino-jump/DinoJump.d.ts.map +1 -1
  194. package/lib/typescript/src/games/dino-jump/components/DinoSprite.d.ts.map +1 -1
  195. package/lib/typescript/src/games/flappy-bird/FlappyBird.d.ts.map +1 -1
  196. package/lib/typescript/src/games/flappy-bird/FlappyBirdConstants.d.ts.map +1 -1
  197. package/lib/typescript/src/games/fruit-merger/FruitMerger.d.ts.map +1 -1
  198. package/lib/typescript/src/games/fruit-merger/FruitMergerConstants.d.ts.map +1 -1
  199. package/lib/typescript/src/games/fruit-ninja/FruitNinja.d.ts.map +1 -1
  200. package/lib/typescript/src/games/fruit-ninja/components/ScoreBoard.d.ts.map +1 -1
  201. package/lib/typescript/src/games/game-2048/Game2048.d.ts.map +1 -1
  202. package/lib/typescript/src/games/maze-runner/MazeRunner.d.ts.map +1 -1
  203. package/lib/typescript/src/games/popit-fidget/PopitFidget.d.ts.map +1 -1
  204. package/lib/typescript/src/games/sliding-numbers/SlidingNumbers.d.ts.map +1 -1
  205. package/lib/typescript/src/games/space-fighter/SpaceFighter.d.ts.map +1 -1
  206. package/lib/typescript/src/games/whack-a-mole/WhackAMole.d.ts.map +1 -1
  207. package/lib/typescript/src/games/whack-a-mole/WhackAMoleConstants.d.ts +1 -1
  208. package/lib/typescript/src/games/whack-a-mole/components/ScoreBoard.d.ts.map +1 -1
  209. package/lib/typescript/src/helpers/GameOverModal.d.ts +3 -0
  210. package/lib/typescript/src/helpers/GameOverModal.d.ts.map +1 -1
  211. package/lib/typescript/src/services/GamesConstants.d.ts +7 -7
  212. package/package.json +2 -2
@@ -1,318 +1 @@
1
- "use strict";
2
-
3
- import { Dimensions } from 'react-native';
4
- import { BALLOON_BLASTER_GAME_CONFIG as GAME_CONFIG, BALLOON_BLASTER_ANIMATION_CONFIG as ANIMATION_CONFIG, BALLOON_BLASTER_COLORS as COLORS, BALLOON_TYPES, BALLOON_SPECIAL_ITEMS as SPECIAL_ITEMS } from "./BalloonBlasterConstants.js";
5
- const {
6
- width,
7
- height
8
- } = Dimensions.get('window');
9
-
10
- // Constants now imported from BalloonBlasterConstants.ts
11
- // Re-export for backward compatibility
12
- export { GAME_CONFIG, ANIMATION_CONFIG, COLORS, BALLOON_TYPES, SPECIAL_ITEMS };
13
-
14
- // Types
15
-
16
- export class BalloonBlasterService {
17
- gameTimerRef = null;
18
- balloonSpawnRef = null;
19
- animationRef = null;
20
- comboTimeoutRef = null;
21
- particles = [];
22
- constructor(balloonAnimations, particleAnimations) {
23
- this.balloonAnimations = balloonAnimations;
24
- this.particleAnimations = particleAnimations;
25
- }
26
- startGameTimer(onTick) {
27
- this.clearGameTimer();
28
- this.gameTimerRef = setInterval(onTick, 1000);
29
- }
30
- startBalloonSpawning(spawnBalloon, customSpawnInterval) {
31
- this.clearBalloonSpawn();
32
- const spawnInterval = customSpawnInterval || GAME_CONFIG.BALLOON_SPAWN_INTERVAL;
33
- const spawnLoop = () => {
34
- const balloon = this.createRandomBalloon();
35
- spawnBalloon(balloon);
36
-
37
- // Reduced random variation for more consistent spawning
38
- const randomVariation = (Math.random() - 0.5) * 150; // Further reduced for more consistent spawning
39
- const nextSpawnTime = spawnInterval + randomVariation;
40
- this.balloonSpawnRef = setTimeout(spawnLoop, Math.max(200, nextSpawnTime)); // Reduced minimum to 200ms for faster spawning
41
- };
42
-
43
- // Spawn initial balloons immediately for instant action
44
- for (let i = 0; i < 3; i++) {
45
- // 3 balloons for immediate start
46
- setTimeout(() => {
47
- const initialBalloon = this.createRandomBalloon();
48
- spawnBalloon(initialBalloon);
49
- }, i * 50); // Very fast stagger for immediate appearance
50
- }
51
-
52
- // Start continuous spawning loop immediately
53
- this.balloonSpawnRef = setTimeout(spawnLoop, 100); // Almost immediate continuous spawning
54
- }
55
- startPhysicsLoop(updateBalloon, removeBalloon, getBalloons) {
56
- let lastTime = performance.now();
57
- const targetFPS = 60;
58
- const targetFrameTime = 1000 / targetFPS;
59
- const updateLoop = currentTime => {
60
- const deltaTime = currentTime - lastTime;
61
-
62
- // Frame rate limiting - only update if enough time has passed
63
- if (deltaTime < targetFrameTime) {
64
- this.animationRef = requestAnimationFrame(updateLoop);
65
- return;
66
- }
67
- lastTime = currentTime;
68
- const deltaMultiplier = deltaTime / 16.67; // Normalize to 60fps baseline
69
-
70
- // Always update particles for smooth animation with delta time
71
- this.updateParticles(deltaMultiplier);
72
- const balloons = getBalloons();
73
-
74
- // Use for loop instead of forEach for better performance
75
- for (let i = 0; i < balloons.length; i++) {
76
- const balloon = balloons[i];
77
- if (!balloon || balloon.isPopped) continue;
78
-
79
- // Physics calculations with delta time
80
- const newVelocityY = balloon.velocity.y + GAME_CONFIG.GRAVITY * deltaMultiplier;
81
- let newX = balloon.position.x + balloon.velocity.x * deltaMultiplier;
82
- const newY = balloon.position.y + newVelocityY * deltaMultiplier;
83
- const newRotation = balloon.rotation + balloon.rotationSpeed * deltaMultiplier;
84
-
85
- // Remove balloons that float off screen (top only)
86
- if (newY < -100) {
87
- removeBalloon(balloon.id);
88
- continue;
89
- }
90
-
91
- // Remove balloons that go too far below screen (they should only move upward)
92
- if (newY > height + 100) {
93
- // Remove balloons that somehow drift too far down
94
- removeBalloon(balloon.id);
95
- continue;
96
- }
97
-
98
- // Simplified wall bounce logic
99
- let newVelocityX = balloon.velocity.x;
100
- if (newX <= 0) {
101
- newX = 0;
102
- newVelocityX = Math.abs(newVelocityX) * 0.8; // Bounce right with damping
103
- } else if (newX >= width - GAME_CONFIG.BALLOON_SIZE) {
104
- newX = width - GAME_CONFIG.BALLOON_SIZE;
105
- newVelocityX = -Math.abs(newVelocityX) * 0.8; // Bounce left with damping
106
- }
107
-
108
- // Batch update for better performance
109
- updateBalloon(balloon.id, {
110
- position: {
111
- x: newX,
112
- y: newY
113
- },
114
- velocity: {
115
- x: newVelocityX,
116
- y: newVelocityY
117
- },
118
- rotation: newRotation
119
- });
120
- }
121
- this.animationRef = requestAnimationFrame(updateLoop);
122
- };
123
- this.animationRef = requestAnimationFrame(updateLoop);
124
- }
125
- createRandomBalloon() {
126
- // 10% chance for special items
127
- const isSpecial = Math.random() < 0.1;
128
- const type = isSpecial ? SPECIAL_ITEMS[Math.floor(Math.random() * SPECIAL_ITEMS.length)] : BALLOON_TYPES[Math.floor(Math.random() * BALLOON_TYPES.length)];
129
-
130
- // Use fallback if type is undefined
131
- const balloonType = type || BALLOON_TYPES[0];
132
-
133
- // FORCE all balloons to spawn from bottom with better random X distribution
134
- const balloonSize = GAME_CONFIG.BALLOON_SIZE;
135
- const margin = balloonSize / 2; // Add margin from edges
136
- const availableWidth = width - margin * 2 - balloonSize;
137
- const spawnX = margin + Math.random() * availableWidth;
138
- const spawnY = height - 30; // Spawn slightly below screen for gradual appearance
139
-
140
- // Simple upward velocity
141
- const velocityX = (Math.random() - 0.5) * GAME_CONFIG.INITIAL_VELOCITY_X_RANGE;
142
- const velocityY = GAME_CONFIG.INITIAL_VELOCITY_Y;
143
- return {
144
- id: `balloon_${Date.now()}_${Math.random()}`,
145
- type: balloonType,
146
- position: {
147
- x: spawnX,
148
- y: spawnY
149
- },
150
- velocity: {
151
- x: velocityX,
152
- y: velocityY
153
- },
154
- rotation: 0,
155
- rotationSpeed: (Math.random() - 0.5) * GAME_CONFIG.ROTATION_SPEED_RANGE,
156
- isPopped: false,
157
- spawnTime: Date.now(),
158
- isBomb: 'isBomb' in balloonType && balloonType.isBomb,
159
- isBonus: 'isBonus' in balloonType && balloonType.isBonus
160
- };
161
- }
162
- createPopParticles(balloon) {
163
- // Aggressive particle limiting to prevent performance issues during rapid popping
164
- const maxTotalParticles = 15; // Reduced maximum particles on screen at once
165
- if (this.particles.length >= maxTotalParticles) {
166
- // Remove half of existing particles to make room for new ones
167
- this.particles.splice(0, Math.floor(this.particles.length / 2));
168
- }
169
- const particles = [];
170
- const particleCount = Math.min(GAME_CONFIG.PARTICLE_COUNT, 6); // Limit particles per balloon to 6
171
-
172
- // Calculate balloon center for particle spawn
173
- const balloonCenterX = balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2;
174
- const balloonCenterY = balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2;
175
- for (let i = 0; i < particleCount; i++) {
176
- const angle = i / particleCount * Math.PI * 2;
177
- const speed = 5 + Math.random() * 4; // Increased speed for better visibility
178
-
179
- particles.push({
180
- id: `particle_${balloon.id}_${i}_${Date.now()}_${Math.random()}`,
181
- // More unique ID
182
- position: {
183
- x: balloonCenterX,
184
- // Center particles exactly on balloon center
185
- y: balloonCenterY
186
- },
187
- velocity: {
188
- x: Math.cos(angle) * speed,
189
- y: Math.sin(angle) * speed - 3 // Stronger upward bias for visibility
190
- },
191
- color: COLORS.PARTICLE_COLORS[i % COLORS.PARTICLE_COLORS.length] || '#FF6B6B',
192
- size: 4 + Math.random() * 3,
193
- // Slightly smaller particles (4-7px) for better performance
194
- lifetime: 0,
195
- maxLifetime: Math.min(GAME_CONFIG.PARTICLE_LIFETIME, 800) // Reduced lifetime for better performance
196
- });
197
- }
198
-
199
- // Create new particles array instead of mutating existing one
200
- this.particles = [...this.particles, ...particles];
201
- return particles;
202
- }
203
- updateParticles(deltaMultiplier = 1) {
204
- // Optimized particle update with delta time
205
- const deltaTime = 16 * deltaMultiplier; // Scale with actual frame time
206
- const gravity = 0.08 * deltaMultiplier; // Scale gravity with delta time
207
-
208
- // Use filter to create new array instead of mutating existing one
209
- const updatedParticles = [];
210
- for (let i = 0; i < this.particles.length; i++) {
211
- const particle = this.particles[i];
212
- if (!particle) continue;
213
-
214
- // Create a new particle object to avoid mutation
215
- const updatedParticle = {
216
- ...particle
217
- };
218
- updatedParticle.lifetime += deltaTime;
219
- if (updatedParticle.lifetime >= updatedParticle.maxLifetime) {
220
- // Skip expired particle (don't add to updatedParticles)
221
- continue;
222
- }
223
-
224
- // Update particle physics with delta time scaling
225
- updatedParticle.position = {
226
- x: updatedParticle.position.x + updatedParticle.velocity.x * deltaMultiplier,
227
- y: updatedParticle.position.y + updatedParticle.velocity.y * deltaMultiplier
228
- };
229
- updatedParticle.velocity = {
230
- x: updatedParticle.velocity.x * Math.pow(0.99, deltaMultiplier),
231
- y: (updatedParticle.velocity.y + gravity) * Math.pow(0.99, deltaMultiplier)
232
- };
233
- updatedParticles.push(updatedParticle);
234
- }
235
-
236
- // Replace particles array with updated one
237
- this.particles = updatedParticles;
238
- }
239
- getParticles() {
240
- return this.particles;
241
- }
242
- checkBalloonPop(balloon, slicePath) {
243
- if (balloon.isPopped || slicePath.length < 2) return false;
244
- const balloonCenter = {
245
- x: balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2,
246
- y: balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2
247
- };
248
- const balloonRadius = GAME_CONFIG.BALLOON_SIZE / 2;
249
-
250
- // Check if slice path intersects with balloon
251
- for (let i = 0; i < slicePath.length - 1; i++) {
252
- const p1 = slicePath[i];
253
- const p2 = slicePath[i + 1];
254
- if (!p1 || !p2) continue;
255
- const distance = this.distanceFromPointToLine(balloonCenter, p1, p2);
256
- if (distance <= balloonRadius) {
257
- return true;
258
- }
259
- }
260
- return false;
261
- }
262
- distanceFromPointToLine(point, lineStart, lineEnd) {
263
- const A = point.x - lineStart.x;
264
- const B = point.y - lineStart.y;
265
- const C = lineEnd.x - lineStart.x;
266
- const D = lineEnd.y - lineStart.y;
267
- const dot = A * C + B * D;
268
- const lenSq = C * C + D * D;
269
- if (lenSq === 0) return Math.sqrt(A * A + B * B);
270
- let param = dot / lenSq;
271
- param = Math.max(0, Math.min(1, param));
272
- const xx = lineStart.x + param * C;
273
- const yy = lineStart.y + param * D;
274
- const dx = point.x - xx;
275
- const dy = point.y - yy;
276
- return Math.sqrt(dx * dx + dy * dy);
277
- }
278
- resetAnimations() {
279
- this.balloonAnimations.clear();
280
- this.particleAnimations.clear();
281
- this.particles = [];
282
- }
283
- cleanup() {
284
- this.clearGameTimer();
285
- this.clearBalloonSpawn();
286
- this.clearAnimationLoop();
287
- this.clearComboTimeout();
288
- this.particles = [];
289
- }
290
- clearGameTimer() {
291
- if (this.gameTimerRef) {
292
- clearInterval(this.gameTimerRef);
293
- this.gameTimerRef = null;
294
- }
295
- }
296
- clearBalloonSpawn() {
297
- if (this.balloonSpawnRef) {
298
- clearTimeout(this.balloonSpawnRef);
299
- this.balloonSpawnRef = null;
300
- }
301
- }
302
- clearAnimationLoop() {
303
- if (this.animationRef) {
304
- cancelAnimationFrame(this.animationRef);
305
- this.animationRef = null;
306
- }
307
- }
308
- clearComboTimeout() {
309
- if (this.comboTimeoutRef) {
310
- clearTimeout(this.comboTimeoutRef);
311
- this.comboTimeoutRef = null;
312
- }
313
- }
314
- }
315
- export const createBalloonBlasterService = (balloonAnimations, particleAnimations) => {
316
- return new BalloonBlasterService(balloonAnimations, particleAnimations);
317
- };
318
- //# sourceMappingURL=BalloonBlasterService.js.map
1
+ "use strict";import{Dimensions}from 'react-native';import{BALLOON_BLASTER_GAME_CONFIG as GAME_CONFIG,BALLOON_BLASTER_ANIMATION_CONFIG as ANIMATION_CONFIG,BALLOON_BLASTER_COLORS as COLORS,BALLOON_TYPES,BALLOON_SPECIAL_ITEMS as SPECIAL_ITEMS}from "./BalloonBlasterConstants.js";const{width,height}= Dimensions.get('window');export{GAME_CONFIG,ANIMATION_CONFIG,COLORS,BALLOON_TYPES,SPECIAL_ITEMS};export class BalloonBlasterService{gameTimerRef = null;balloonSpawnRef = null;animationRef = null;comboTimeoutRef = null;particles = [];constructor(balloonAnimations,particleAnimations){this.balloonAnimations = balloonAnimations;this.particleAnimations = particleAnimations;}startGameTimer(onTick){this.clearGameTimer();this.gameTimerRef = setInterval(onTick,1000);}startBalloonSpawning(spawnBalloon,customSpawnInterval){this.clearBalloonSpawn();const spawnInterval = customSpawnInterval || GAME_CONFIG.BALLOON_SPAWN_INTERVAL;const spawnLoop =()=>{const balloon = this.createRandomBalloon();spawnBalloon(balloon);const randomVariation =(Math.random()- 0.5)* 150;const nextSpawnTime = spawnInterval + randomVariation;this.balloonSpawnRef = setTimeout(spawnLoop,Math.max(200,nextSpawnTime));};for(let i = 0;i < 3;i++){setTimeout(()=>{const initialBalloon = this.createRandomBalloon();spawnBalloon(initialBalloon);},i * 50);}this.balloonSpawnRef = setTimeout(spawnLoop,100);}startPhysicsLoop(updateBalloon,removeBalloon,getBalloons){let lastTime = performance.now();const targetFPS = 60;const targetFrameTime = 1000 / targetFPS;const updateLoop = currentTime =>{const deltaTime = currentTime - lastTime;if(deltaTime < targetFrameTime){this.animationRef = requestAnimationFrame(updateLoop);return;}lastTime = currentTime;const deltaMultiplier = deltaTime / 16.67;this.updateParticles(deltaMultiplier);const balloons = getBalloons();for(let i = 0;i < balloons.length;i++){const balloon = balloons[i];if(!balloon || balloon.isPopped)continue;const newVelocityY = balloon.velocity.y + GAME_CONFIG.GRAVITY * deltaMultiplier;let newX = balloon.position.x + balloon.velocity.x * deltaMultiplier;const newY = balloon.position.y + newVelocityY * deltaMultiplier;const newRotation = balloon.rotation + balloon.rotationSpeed * deltaMultiplier;if(newY < -100){removeBalloon(balloon.id);continue;}if(newY > height + 100){removeBalloon(balloon.id);continue;}let newVelocityX = balloon.velocity.x;if(newX <= 0){newX = 0;newVelocityX = Math.abs(newVelocityX)* 0.8;}else if(newX >= width - GAME_CONFIG.BALLOON_SIZE){newX = width - GAME_CONFIG.BALLOON_SIZE;newVelocityX = -Math.abs(newVelocityX)* 0.8;}updateBalloon(balloon.id,{position:{x:newX,y:newY},velocity:{x:newVelocityX,y:newVelocityY},rotation:newRotation});}this.animationRef = requestAnimationFrame(updateLoop);};this.animationRef = requestAnimationFrame(updateLoop);}createRandomBalloon(){const isSpecial = Math.random()< 0.1;const type = isSpecial ? SPECIAL_ITEMS[Math.floor(Math.random()* SPECIAL_ITEMS.length)]:BALLOON_TYPES[Math.floor(Math.random()* BALLOON_TYPES.length)];const balloonType = type || BALLOON_TYPES[0];const balloonSize = GAME_CONFIG.BALLOON_SIZE;const margin = balloonSize / 2;const availableWidth = width - margin * 2 - balloonSize;const spawnX = margin + Math.random()* availableWidth;const spawnY = height - 30;const velocityX =(Math.random()- 0.5)* GAME_CONFIG.INITIAL_VELOCITY_X_RANGE;const velocityY = GAME_CONFIG.INITIAL_VELOCITY_Y;return{id:`balloon_${Date.now()}_${Math.random()}`,type:balloonType,position:{x:spawnX,y:spawnY},velocity:{x:velocityX,y:velocityY},rotation:0,rotationSpeed:(Math.random()- 0.5)* GAME_CONFIG.ROTATION_SPEED_RANGE,isPopped:false,spawnTime:Date.now(),isBomb:'isBomb' in balloonType && balloonType.isBomb,isBonus:'isBonus' in balloonType && balloonType.isBonus};}createPopParticles(balloon){const maxTotalParticles = 15;if(this.particles.length >= maxTotalParticles){this.particles.splice(0,Math.floor(this.particles.length / 2));}const particles = [];const particleCount = Math.min(GAME_CONFIG.PARTICLE_COUNT,6);const balloonCenterX = balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2;const balloonCenterY = balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2;for(let i = 0;i < particleCount;i++){const angle = i / particleCount * Math.PI * 2;const speed = 5 + Math.random()* 4;particles.push({id:`particle_${balloon.id}_${i}_${Date.now()}_${Math.random()}`,position:{x:balloonCenterX,y:balloonCenterY},velocity:{x:Math.cos(angle)* speed,y:Math.sin(angle)* speed - 3},color:COLORS.PARTICLE_COLORS[i % COLORS.PARTICLE_COLORS.length] || '#FF6B6B',size:4 + Math.random()* 3,lifetime:0,maxLifetime:Math.min(GAME_CONFIG.PARTICLE_LIFETIME,800)});}this.particles = [...this.particles,...particles];return particles;}updateParticles(deltaMultiplier = 1){const deltaTime = 16 * deltaMultiplier;const gravity = 0.08 * deltaMultiplier;const updatedParticles = [];for(let i = 0;i < this.particles.length;i++){const particle = this.particles[i];if(!particle)continue;const updatedParticle ={...particle};updatedParticle.lifetime += deltaTime;if(updatedParticle.lifetime >= updatedParticle.maxLifetime){continue;}updatedParticle.position ={x:updatedParticle.position.x + updatedParticle.velocity.x * deltaMultiplier,y:updatedParticle.position.y + updatedParticle.velocity.y * deltaMultiplier};updatedParticle.velocity ={x:updatedParticle.velocity.x * Math.pow(0.99,deltaMultiplier),y:(updatedParticle.velocity.y + gravity)* Math.pow(0.99,deltaMultiplier)};updatedParticles.push(updatedParticle);}this.particles = updatedParticles;}getParticles(){return this.particles;}checkBalloonPop(balloon,slicePath){if(balloon.isPopped || slicePath.length < 2)return false;const balloonCenter ={x:balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2,y:balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2};const balloonRadius = GAME_CONFIG.BALLOON_SIZE / 2;for(let i = 0;i < slicePath.length - 1;i++){const p1 = slicePath[i];const p2 = slicePath[i + 1];if(!p1 || !p2)continue;const distance = this.distanceFromPointToLine(balloonCenter,p1,p2);if(distance <= balloonRadius){return true;}}return false;}distanceFromPointToLine(point,lineStart,lineEnd){const A = point.x - lineStart.x;const B = point.y - lineStart.y;const C = lineEnd.x - lineStart.x;const D = lineEnd.y - lineStart.y;const dot = A * C + B * D;const lenSq = C * C + D * D;if(lenSq === 0)return Math.sqrt(A * A + B * B);let param = dot / lenSq;param = Math.max(0,Math.min(1,param));const xx = lineStart.x + param * C;const yy = lineStart.y + param * D;const dx = point.x - xx;const dy = point.y - yy;return Math.sqrt(dx * dx + dy * dy);}resetAnimations(){this.balloonAnimations.clear();this.particleAnimations.clear();this.particles = [];}cleanup(){this.clearGameTimer();this.clearBalloonSpawn();this.clearAnimationLoop();this.clearComboTimeout();this.particles = [];}clearGameTimer(){if(this.gameTimerRef){clearInterval(this.gameTimerRef);this.gameTimerRef = null;}}clearBalloonSpawn(){if(this.balloonSpawnRef){clearTimeout(this.balloonSpawnRef);this.balloonSpawnRef = null;}}clearAnimationLoop(){if(this.animationRef){cancelAnimationFrame(this.animationRef);this.animationRef = null;}}clearComboTimeout(){if(this.comboTimeoutRef){clearTimeout(this.comboTimeoutRef);this.comboTimeoutRef = null;}}}export const createBalloonBlasterService =(balloonAnimations,particleAnimations)=>{return new BalloonBlasterService(balloonAnimations,particleAnimations);};
@@ -1,183 +1 @@
1
- "use strict";
2
-
3
- import { create } from 'zustand';
4
- import { subscribeWithSelector } from 'zustand/middleware';
5
- import { GAME_CONFIG } from "./BalloonBlasterService.js";
6
- import { immerMiddleware } from "../../services/UtilsService.js";
7
- // Optimized store with selective subscriptions for low-end devices
8
- export const useBalloonBlasterStore = create()(subscribeWithSelector(immerMiddleware((set, get) => ({
9
- // Initial state
10
- score: 0,
11
- timeLeft: 60,
12
- // Fixed 60 seconds regardless of difficulty
13
- isPlaying: false,
14
- gameOver: false,
15
- combo: 0,
16
- lives: GAME_CONFIG.MAX_LIVES,
17
- balloons: [],
18
- particles: [],
19
- slicePath: [],
20
- isSlicing: false,
21
- // Actions
22
- startGame: _gameDuration => {
23
- // Always use fixed duration regardless of difficulty or passed duration
24
- const duration = 60;
25
- set(draft => {
26
- draft.score = 0;
27
- draft.timeLeft = duration;
28
- draft.isPlaying = true;
29
- draft.gameOver = false;
30
- draft.combo = 0;
31
- draft.lives = GAME_CONFIG.MAX_LIVES;
32
- draft.balloons = [];
33
- draft.slicePath = [];
34
- draft.isSlicing = false;
35
- });
36
- },
37
- stopGame: () => {
38
- set(draft => {
39
- draft.score = 0;
40
- draft.timeLeft = 60; // Fixed 60 seconds
41
- draft.isPlaying = false;
42
- draft.gameOver = false;
43
- draft.combo = 0;
44
- draft.lives = GAME_CONFIG.MAX_LIVES;
45
- draft.balloons = [];
46
- draft.slicePath = [];
47
- draft.isSlicing = false;
48
- });
49
- },
50
- resetGame: () => {
51
- set(draft => {
52
- draft.score = 0;
53
- draft.timeLeft = 60; // Fixed 60 seconds
54
- draft.isPlaying = false;
55
- draft.gameOver = false;
56
- draft.combo = 0;
57
- draft.lives = GAME_CONFIG.MAX_LIVES;
58
- draft.balloons = [];
59
- draft.slicePath = [];
60
- draft.isSlicing = false;
61
- });
62
- },
63
- popBalloon: balloonId => {
64
- const {
65
- balloons,
66
- isPlaying
67
- } = get();
68
- if (!isPlaying) return;
69
-
70
- // Optimized: Use for-loop instead of find for better performance
71
- let balloonIndex = -1;
72
- for (let i = 0; i < balloons.length; i++) {
73
- if (balloons[i].id === balloonId) {
74
- balloonIndex = i;
75
- break;
76
- }
77
- }
78
- if (balloonIndex === -1 || balloons[balloonIndex].isPopped) return;
79
-
80
- // Simplified scoring: each balloon = 10 points (no combo multipliers)
81
- const points = 10;
82
- set(draft => {
83
- draft.score = draft.score + points;
84
- // Optimized: Direct array access instead of find
85
- if (draft.balloons[balloonIndex]) {
86
- draft.balloons[balloonIndex].isPopped = true;
87
- draft.balloons[balloonIndex].popTime = Date.now();
88
- }
89
- });
90
- },
91
- updateScore: points => {
92
- set(draft => {
93
- draft.score = draft.score + points;
94
- });
95
- },
96
- decrementTime: () => {
97
- set(draft => {
98
- const newTimeLeft = draft.timeLeft - 1;
99
- if (newTimeLeft <= 0) {
100
- draft.timeLeft = 0;
101
- draft.isPlaying = false;
102
- draft.gameOver = true;
103
- } else {
104
- draft.timeLeft = newTimeLeft;
105
- }
106
- });
107
- },
108
- addBalloon: balloon => {
109
- set(draft => {
110
- // FORCE all balloons to spawn from bottom - override any wrong positions
111
- const {
112
- height
113
- } = require('react-native').Dimensions.get('window');
114
- const correctedBalloon = {
115
- ...balloon,
116
- position: {
117
- x: balloon.position.x,
118
- y: height + 20 // Force bottom spawn regardless of input
119
- }
120
- };
121
- draft.balloons.push(correctedBalloon);
122
- });
123
- },
124
- removeBalloon: balloonId => {
125
- set(draft => {
126
- draft.balloons = draft.balloons.filter(b => b.id !== balloonId);
127
- });
128
- },
129
- updateBalloon: (balloonId, updates) => {
130
- set(draft => {
131
- // Optimized: Use for-loop instead of find for better performance
132
- for (let i = 0; i < draft.balloons.length; i++) {
133
- if (draft.balloons[i].id === balloonId) {
134
- Object.assign(draft.balloons[i], updates);
135
- break;
136
- }
137
- }
138
- });
139
- },
140
- setParticles: particles => {
141
- set(draft => {
142
- draft.particles = particles;
143
- });
144
- },
145
- setSlicePath: path => {
146
- set(draft => {
147
- draft.slicePath = path;
148
- });
149
- },
150
- setIsSlicing: isSlicing => {
151
- set(draft => {
152
- draft.isSlicing = isSlicing;
153
- });
154
- },
155
- incrementCombo: () => {
156
- set(draft => {
157
- draft.combo = draft.combo + 1;
158
- });
159
- },
160
- resetCombo: () => {
161
- set(draft => {
162
- draft.combo = 0;
163
- });
164
- },
165
- loseLife: () => {
166
- set(draft => {
167
- const newLives = draft.lives - 1;
168
- if (newLives <= 0) {
169
- draft.lives = 0;
170
- draft.isPlaying = false;
171
- draft.gameOver = true;
172
- } else {
173
- draft.lives = newLives;
174
- }
175
- });
176
- },
177
- addLife: () => {
178
- set(draft => {
179
- draft.lives = Math.min(draft.lives + 1, GAME_CONFIG.MAX_LIVES); // Cap at max lives
180
- });
181
- }
182
- }))));
183
- //# sourceMappingURL=BalloonBlasterStore.js.map
1
+ "use strict";import{create}from 'zustand';import{subscribeWithSelector}from 'zustand/middleware';import{GAME_CONFIG}from "./BalloonBlasterService.js";import{immerMiddleware}from "../../services/UtilsService.js";export const useBalloonBlasterStore = create()(subscribeWithSelector(immerMiddleware((set,get)=>({score:0,timeLeft:60,isPlaying:false,gameOver:false,combo:0,lives:GAME_CONFIG.MAX_LIVES,balloons:[],particles:[],slicePath:[],isSlicing:false,startGame:_gameDuration =>{const duration = 60;set(draft =>{draft.score = 0;draft.timeLeft = duration;draft.isPlaying = true;draft.gameOver = false;draft.combo = 0;draft.lives = GAME_CONFIG.MAX_LIVES;draft.balloons = [];draft.slicePath = [];draft.isSlicing = false;});},stopGame:()=>{set(draft =>{draft.score = 0;draft.timeLeft = 60;draft.isPlaying = false;draft.gameOver = false;draft.combo = 0;draft.lives = GAME_CONFIG.MAX_LIVES;draft.balloons = [];draft.slicePath = [];draft.isSlicing = false;});},resetGame:()=>{set(draft =>{draft.score = 0;draft.timeLeft = 60;draft.isPlaying = false;draft.gameOver = false;draft.combo = 0;draft.lives = GAME_CONFIG.MAX_LIVES;draft.balloons = [];draft.slicePath = [];draft.isSlicing = false;});},popBalloon:balloonId =>{const{balloons,isPlaying}= get();if(!isPlaying)return;let balloonIndex = -1;for(let i = 0;i < balloons.length;i++){if(balloons[i].id === balloonId){balloonIndex = i;break;}}if(balloonIndex === -1 || balloons[balloonIndex].isPopped)return;const points = 10;set(draft =>{draft.score = draft.score + points;if(draft.balloons[balloonIndex]){draft.balloons[balloonIndex].isPopped = true;draft.balloons[balloonIndex].popTime = Date.now();}});},updateScore:points =>{set(draft =>{draft.score = draft.score + points;});},decrementTime:()=>{set(draft =>{const newTimeLeft = draft.timeLeft - 1;if(newTimeLeft <= 0){draft.timeLeft = 0;draft.isPlaying = false;draft.gameOver = true;}else{draft.timeLeft = newTimeLeft;}});},addBalloon:balloon =>{set(draft =>{const{height}= require('react-native').Dimensions.get('window');const correctedBalloon ={...balloon,position:{x:balloon.position.x,y:height + 20}};draft.balloons.push(correctedBalloon);});},removeBalloon:balloonId =>{set(draft =>{draft.balloons = draft.balloons.filter(b => b.id !== balloonId);});},updateBalloon:(balloonId,updates)=>{set(draft =>{for(let i = 0;i < draft.balloons.length;i++){if(draft.balloons[i].id === balloonId){Object.assign(draft.balloons[i],updates);break;}}});},setParticles:particles =>{set(draft =>{draft.particles = particles;});},setSlicePath:path =>{set(draft =>{draft.slicePath = path;});},setIsSlicing:isSlicing =>{set(draft =>{draft.isSlicing = isSlicing;});},incrementCombo:()=>{set(draft =>{draft.combo = draft.combo + 1;});},resetCombo:()=>{set(draft =>{draft.combo = 0;});},loseLife:()=>{set(draft =>{const newLives = draft.lives - 1;if(newLives <= 0){draft.lives = 0;draft.isPlaying = false;draft.gameOver = true;}else{draft.lives = newLives;}});},addLife:()=>{set(draft =>{draft.lives = Math.min(draft.lives + 1,GAME_CONFIG.MAX_LIVES);});}}))));