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,370 +1 @@
1
- "use strict";
2
-
3
- import { Animated } from 'react-native';
4
- import { CANDY_CRUSH_GAME_CONFIG, CANDY_COLORS, CANDY_TYPES } from "./CandyCrushConstants.js";
5
- export class CandyCrushService {
6
- nextCandyId = 1;
7
-
8
- // Create empty grid
9
- createGrid() {
10
- return Array(CANDY_CRUSH_GAME_CONFIG.GRID_SIZE).fill(null).map(() => Array(CANDY_CRUSH_GAME_CONFIG.GRID_SIZE).fill(null));
11
- }
12
-
13
- // Initialize grid with random candies (ensuring no initial matches)
14
- initializeGrid(candyTypes) {
15
- const grid = this.createGrid();
16
- const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;
17
- for (let row = 0; row < size; row++) {
18
- for (let col = 0; col < size; col++) {
19
- let candyType;
20
- let attempts = 0;
21
-
22
- // Generate candy type that doesn't create initial matches
23
- do {
24
- candyType = Math.floor(Math.random() * candyTypes);
25
- attempts++;
26
- } while (attempts < 10 && this.wouldCreateMatch(grid, row, col, candyType));
27
- const candy = {
28
- id: this.nextCandyId++,
29
- row,
30
- col,
31
- type: candyType,
32
- specialType: CANDY_TYPES.NORMAL,
33
- animatedValue: new Animated.Value(1),
34
- scaleValue: new Animated.Value(1),
35
- isMatched: false,
36
- isFalling: false
37
- };
38
- const gridRow = grid[row];
39
- if (gridRow) {
40
- gridRow[col] = candy;
41
- }
42
- }
43
- }
44
- return grid;
45
- }
46
-
47
- // Check if placing candy would create a match
48
- wouldCreateMatch(grid, row, col, type) {
49
- // Check horizontal
50
- let horizontalCount = 1;
51
-
52
- // Check left
53
- for (let c = col - 1; c >= 0; c--) {
54
- const gridRow = grid[row];
55
- const candy = gridRow ? gridRow[c] : null;
56
- if (candy && candy.type === type) {
57
- horizontalCount++;
58
- } else {
59
- break;
60
- }
61
- }
62
-
63
- // Check right
64
- for (let c = col + 1; c < CANDY_CRUSH_GAME_CONFIG.GRID_SIZE; c++) {
65
- const gridRow = grid[row];
66
- const candy = gridRow ? gridRow[c] : null;
67
- if (candy && candy.type === type) {
68
- horizontalCount++;
69
- } else {
70
- break;
71
- }
72
- }
73
- if (horizontalCount >= CANDY_CRUSH_GAME_CONFIG.MIN_MATCH) {
74
- return true;
75
- }
76
-
77
- // Check vertical
78
- let verticalCount = 1;
79
-
80
- // Check up
81
- for (let r = row - 1; r >= 0; r--) {
82
- const gridRow = grid[r];
83
- const candy = gridRow ? gridRow[col] : null;
84
- if (candy && candy.type === type) {
85
- verticalCount++;
86
- } else {
87
- break;
88
- }
89
- }
90
-
91
- // Check down
92
- for (let r = row + 1; r < CANDY_CRUSH_GAME_CONFIG.GRID_SIZE; r++) {
93
- const gridRow = grid[r];
94
- const candy = gridRow ? gridRow[col] : null;
95
- if (candy && candy.type === type) {
96
- verticalCount++;
97
- } else {
98
- break;
99
- }
100
- }
101
- return verticalCount >= CANDY_CRUSH_GAME_CONFIG.MIN_MATCH;
102
- }
103
-
104
- // Check if two candies can be swapped
105
- canSwap(candy1, candy2) {
106
- const rowDiff = Math.abs(candy1.row - candy2.row);
107
- const colDiff = Math.abs(candy1.col - candy2.col);
108
-
109
- // Must be adjacent (horizontally or vertically)
110
- return rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1;
111
- }
112
-
113
- // Swap two candies
114
- swapCandies(grid, candy1, candy2) {
115
- const row1 = candy1.row;
116
- const col1 = candy1.col;
117
- const row2 = candy2.row;
118
- const col2 = candy2.col;
119
-
120
- // Get references from grid
121
- const gridRow1 = grid[row1];
122
- const gridRow2 = grid[row2];
123
- if (gridRow1 && gridRow2) {
124
- const temp1 = gridRow1[col1];
125
- const temp2 = gridRow2[col2];
126
-
127
- // Swap in grid
128
- gridRow1[col1] = temp2 || null;
129
- gridRow2[col2] = temp1 || null;
130
-
131
- // Update positions (these are mutable in Immer draft)
132
- if (temp1) {
133
- temp1.row = row2;
134
- temp1.col = col2;
135
- }
136
- if (temp2) {
137
- temp2.row = row1;
138
- temp2.col = col1;
139
- }
140
- }
141
- }
142
-
143
- // Find all matches in the grid
144
- findMatches(grid) {
145
- const matches = [];
146
- const matchedSet = new Set();
147
- const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;
148
-
149
- // Check horizontal matches
150
- for (let row = 0; row < size; row++) {
151
- for (let col = 0; col < size - 2; col++) {
152
- const gridRow = grid[row];
153
- if (!gridRow) continue;
154
- const candy1 = gridRow[col];
155
- const candy2 = gridRow[col + 1];
156
- const candy3 = gridRow[col + 2];
157
- if (candy1 && candy2 && candy3 && candy1.type === candy2.type && candy2.type === candy3.type) {
158
- let matchLength = 3;
159
- const matchCandies = [candy1, candy2, candy3];
160
-
161
- // Check for longer matches
162
- for (let c = col + 3; c < size; c++) {
163
- const nextCandy = gridRow[c];
164
- if (nextCandy && nextCandy.type === candy1.type) {
165
- matchLength++;
166
- matchCandies.push(nextCandy);
167
- } else {
168
- break;
169
- }
170
- }
171
-
172
- // Add to matches
173
- matchCandies.forEach(candy => {
174
- if (!matchedSet.has(candy.id)) {
175
- matchedSet.add(candy.id);
176
- matches.push(candy);
177
- }
178
- });
179
- col += matchLength - 1;
180
- }
181
- }
182
- }
183
-
184
- // Check vertical matches
185
- for (let col = 0; col < size; col++) {
186
- for (let row = 0; row < size - 2; row++) {
187
- const gridRow1 = grid[row];
188
- const gridRow2 = grid[row + 1];
189
- const gridRow3 = grid[row + 2];
190
- if (!gridRow1 || !gridRow2 || !gridRow3) continue;
191
- const candy1 = gridRow1[col];
192
- const candy2 = gridRow2[col];
193
- const candy3 = gridRow3[col];
194
- if (candy1 && candy2 && candy3 && candy1.type === candy2.type && candy2.type === candy3.type) {
195
- let matchLength = 3;
196
- const matchCandies = [candy1, candy2, candy3];
197
-
198
- // Check for longer matches
199
- for (let r = row + 3; r < size; r++) {
200
- const nextRow = grid[r];
201
- const nextCandy = nextRow ? nextRow[col] : null;
202
- if (nextCandy && nextCandy.type === candy1.type) {
203
- matchLength++;
204
- matchCandies.push(nextCandy);
205
- } else {
206
- break;
207
- }
208
- }
209
-
210
- // Add to matches
211
- matchCandies.forEach(candy => {
212
- if (!matchedSet.has(candy.id)) {
213
- matchedSet.add(candy.id);
214
- matches.push(candy);
215
- }
216
- });
217
- row += matchLength - 1;
218
- }
219
- }
220
- }
221
- const score = matches.length * CANDY_CRUSH_GAME_CONFIG.POINTS_PER_CANDY;
222
- return {
223
- matches,
224
- score,
225
- hasMatches: matches.length > 0
226
- };
227
- }
228
-
229
- // Remove matched candies from grid
230
- removeMatches(grid, matches) {
231
- matches.forEach(candy => {
232
- const gridRow = grid[candy.row];
233
- if (gridRow) {
234
- gridRow[candy.col] = null;
235
- }
236
- });
237
- }
238
-
239
- // Apply gravity - make candies fall down
240
- applyGravity(grid) {
241
- let hasMoved = false;
242
- const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;
243
-
244
- // Process from bottom to top
245
- for (let col = 0; col < size; col++) {
246
- for (let row = size - 1; row >= 0; row--) {
247
- const gridRow = grid[row];
248
- if (!gridRow) continue;
249
- const candy = gridRow[col];
250
- if (candy) {
251
- // Find the lowest empty position below this candy
252
- let newRow = row;
253
- for (let r = row + 1; r < size; r++) {
254
- const checkRow = grid[r];
255
- if (checkRow && !checkRow[col]) {
256
- newRow = r;
257
- } else {
258
- break;
259
- }
260
- }
261
-
262
- // Move candy down if there's an empty space
263
- if (newRow !== row) {
264
- const targetRow = grid[newRow];
265
- if (targetRow) {
266
- targetRow[col] = candy;
267
- gridRow[col] = null;
268
- candy.row = newRow;
269
- candy.isFalling = true;
270
- hasMoved = true;
271
- }
272
- }
273
- }
274
- }
275
- }
276
- return hasMoved;
277
- }
278
-
279
- // Fill empty spaces with new candies
280
- fillEmptySpaces(grid, candyTypes) {
281
- const newCandies = [];
282
- const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;
283
- for (let col = 0; col < size; col++) {
284
- // Count empty spaces in this column
285
- let emptyCount = 0;
286
- for (let row = 0; row < size; row++) {
287
- const gridRow = grid[row];
288
- if (gridRow && !gridRow[col]) {
289
- emptyCount++;
290
- }
291
- }
292
-
293
- // Fill from top
294
- for (let i = 0; i < emptyCount; i++) {
295
- const row = i;
296
- const candy = {
297
- id: this.nextCandyId++,
298
- row,
299
- col,
300
- type: Math.floor(Math.random() * candyTypes),
301
- specialType: CANDY_TYPES.NORMAL,
302
- animatedValue: new Animated.Value(0),
303
- scaleValue: new Animated.Value(1),
304
- isMatched: false,
305
- isFalling: true
306
- };
307
- const gridRow = grid[row];
308
- if (gridRow) {
309
- gridRow[col] = candy;
310
- newCandies.push(candy);
311
- }
312
- }
313
- }
314
- return newCandies;
315
- }
316
-
317
- // Check if there are any possible moves
318
- hasPossibleMoves(grid) {
319
- const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;
320
- for (let row = 0; row < size; row++) {
321
- for (let col = 0; col < size; col++) {
322
- const gridRow = grid[row];
323
- if (!gridRow) continue;
324
- const candy = gridRow[col];
325
- if (!candy) continue;
326
-
327
- // Try swapping with right neighbor
328
- if (col < size - 1) {
329
- const rightCandy = gridRow[col + 1];
330
- if (rightCandy) {
331
- this.swapCandies(grid, candy, rightCandy);
332
- const result = this.findMatches(grid);
333
- this.swapCandies(grid, candy, rightCandy); // Swap back
334
-
335
- if (result.hasMatches) {
336
- return true;
337
- }
338
- }
339
- }
340
-
341
- // Try swapping with bottom neighbor
342
- if (row < size - 1) {
343
- const bottomRow = grid[row + 1];
344
- const bottomCandy = bottomRow ? bottomRow[col] : null;
345
- if (bottomCandy) {
346
- this.swapCandies(grid, candy, bottomCandy);
347
- const result = this.findMatches(grid);
348
- this.swapCandies(grid, candy, bottomCandy); // Swap back
349
-
350
- if (result.hasMatches) {
351
- return true;
352
- }
353
- }
354
- }
355
- }
356
- }
357
- return false;
358
- }
359
-
360
- // Get candy color
361
- getCandyColor(type) {
362
- return CANDY_COLORS[type % CANDY_COLORS.length] || CANDY_COLORS[0];
363
- }
364
-
365
- // Reset candy ID counter
366
- resetIdCounter() {
367
- this.nextCandyId = 1;
368
- }
369
- }
370
- //# sourceMappingURL=CandyCrushService.js.map
1
+ "use strict";import{Animated}from 'react-native';import{CANDY_CRUSH_GAME_CONFIG,CANDY_COLORS,CANDY_TYPES}from "./CandyCrushConstants.js";export class CandyCrushService{nextCandyId = 1;createGrid(){return Array(CANDY_CRUSH_GAME_CONFIG.GRID_SIZE).fill(null).map(()=> Array(CANDY_CRUSH_GAME_CONFIG.GRID_SIZE).fill(null));}initializeGrid(candyTypes){const grid = this.createGrid();const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;for(let row = 0;row < size;row++){for(let col = 0;col < size;col++){let candyType;let attempts = 0;do{candyType = Math.floor(Math.random()* candyTypes);attempts++;}while(attempts < 10 && this.wouldCreateMatch(grid,row,col,candyType));const candy ={id:this.nextCandyId++,row,col,type:candyType,specialType:CANDY_TYPES.NORMAL,animatedValue:new Animated.Value(1),scaleValue:new Animated.Value(1),isMatched:false,isFalling:false};const gridRow = grid[row];if(gridRow){gridRow[col] = candy;}}}return grid;}wouldCreateMatch(grid,row,col,type){let horizontalCount = 1;for(let c = col - 1;c >= 0;c--){const gridRow = grid[row];const candy = gridRow ? gridRow[c]:null;if(candy && candy.type === type){horizontalCount++;}else{break;}}for(let c = col + 1;c < CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;c++){const gridRow = grid[row];const candy = gridRow ? gridRow[c]:null;if(candy && candy.type === type){horizontalCount++;}else{break;}}if(horizontalCount >= CANDY_CRUSH_GAME_CONFIG.MIN_MATCH){return true;}let verticalCount = 1;for(let r = row - 1;r >= 0;r--){const gridRow = grid[r];const candy = gridRow ? gridRow[col]:null;if(candy && candy.type === type){verticalCount++;}else{break;}}for(let r = row + 1;r < CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;r++){const gridRow = grid[r];const candy = gridRow ? gridRow[col]:null;if(candy && candy.type === type){verticalCount++;}else{break;}}return verticalCount >= CANDY_CRUSH_GAME_CONFIG.MIN_MATCH;}canSwap(candy1,candy2){const rowDiff = Math.abs(candy1.row - candy2.row);const colDiff = Math.abs(candy1.col - candy2.col);return rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1;}swapCandies(grid,candy1,candy2){const row1 = candy1.row;const col1 = candy1.col;const row2 = candy2.row;const col2 = candy2.col;const gridRow1 = grid[row1];const gridRow2 = grid[row2];if(gridRow1 && gridRow2){const temp1 = gridRow1[col1];const temp2 = gridRow2[col2];gridRow1[col1] = temp2 || null;gridRow2[col2] = temp1 || null;if(temp1){temp1.row = row2;temp1.col = col2;}if(temp2){temp2.row = row1;temp2.col = col1;}}}findMatches(grid){const matches = [];const matchedSet = new Set();const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;for(let row = 0;row < size;row++){for(let col = 0;col < size - 2;col++){const gridRow = grid[row];if(!gridRow)continue;const candy1 = gridRow[col];const candy2 = gridRow[col + 1];const candy3 = gridRow[col + 2];if(candy1 && candy2 && candy3 && candy1.type === candy2.type && candy2.type === candy3.type){let matchLength = 3;const matchCandies = [candy1,candy2,candy3];for(let c = col + 3;c < size;c++){const nextCandy = gridRow[c];if(nextCandy && nextCandy.type === candy1.type){matchLength++;matchCandies.push(nextCandy);}else{break;}}matchCandies.forEach(candy =>{if(!matchedSet.has(candy.id)){matchedSet.add(candy.id);matches.push(candy);}});col += matchLength - 1;}}}for(let col = 0;col < size;col++){for(let row = 0;row < size - 2;row++){const gridRow1 = grid[row];const gridRow2 = grid[row + 1];const gridRow3 = grid[row + 2];if(!gridRow1 || !gridRow2 || !gridRow3)continue;const candy1 = gridRow1[col];const candy2 = gridRow2[col];const candy3 = gridRow3[col];if(candy1 && candy2 && candy3 && candy1.type === candy2.type && candy2.type === candy3.type){let matchLength = 3;const matchCandies = [candy1,candy2,candy3];for(let r = row + 3;r < size;r++){const nextRow = grid[r];const nextCandy = nextRow ? nextRow[col]:null;if(nextCandy && nextCandy.type === candy1.type){matchLength++;matchCandies.push(nextCandy);}else{break;}}matchCandies.forEach(candy =>{if(!matchedSet.has(candy.id)){matchedSet.add(candy.id);matches.push(candy);}});row += matchLength - 1;}}}const score = matches.length * CANDY_CRUSH_GAME_CONFIG.POINTS_PER_CANDY;return{matches,score,hasMatches:matches.length > 0};}removeMatches(grid,matches){matches.forEach(candy =>{const gridRow = grid[candy.row];if(gridRow){gridRow[candy.col] = null;}});}applyGravity(grid){let hasMoved = false;const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;for(let col = 0;col < size;col++){for(let row = size - 1;row >= 0;row--){const gridRow = grid[row];if(!gridRow)continue;const candy = gridRow[col];if(candy){let newRow = row;for(let r = row + 1;r < size;r++){const checkRow = grid[r];if(checkRow && !checkRow[col]){newRow = r;}else{break;}}if(newRow !== row){const targetRow = grid[newRow];if(targetRow){targetRow[col] = candy;gridRow[col] = null;candy.row = newRow;candy.isFalling = true;hasMoved = true;}}}}}return hasMoved;}fillEmptySpaces(grid,candyTypes){const newCandies = [];const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;for(let col = 0;col < size;col++){let emptyCount = 0;for(let row = 0;row < size;row++){const gridRow = grid[row];if(gridRow && !gridRow[col]){emptyCount++;}}for(let i = 0;i < emptyCount;i++){const row = i;const candy ={id:this.nextCandyId++,row,col,type:Math.floor(Math.random()* candyTypes),specialType:CANDY_TYPES.NORMAL,animatedValue:new Animated.Value(0),scaleValue:new Animated.Value(1),isMatched:false,isFalling:true};const gridRow = grid[row];if(gridRow){gridRow[col] = candy;newCandies.push(candy);}}}return newCandies;}hasPossibleMoves(grid){const size = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;for(let row = 0;row < size;row++){for(let col = 0;col < size;col++){const gridRow = grid[row];if(!gridRow)continue;const candy = gridRow[col];if(!candy)continue;if(col < size - 1){const rightCandy = gridRow[col + 1];if(rightCandy){this.swapCandies(grid,candy,rightCandy);const result = this.findMatches(grid);this.swapCandies(grid,candy,rightCandy);if(result.hasMatches){return true;}}}if(row < size - 1){const bottomRow = grid[row + 1];const bottomCandy = bottomRow ? bottomRow[col]:null;if(bottomCandy){this.swapCandies(grid,candy,bottomCandy);const result = this.findMatches(grid);this.swapCandies(grid,candy,bottomCandy);if(result.hasMatches){return true;}}}}}return false;}getCandyColor(type){return CANDY_COLORS[type % CANDY_COLORS.length] || CANDY_COLORS[0];}resetIdCounter(){this.nextCandyId = 1;}}
@@ -1,303 +1 @@
1
- "use strict";
2
-
3
- import { create } from 'zustand';
4
- import { subscribeWithSelector } from 'zustand/middleware';
5
- import { CandyCrushService } from "./CandyCrushService.js";
6
- import { CANDY_CRUSH_GAME_CONFIG, DIFFICULTY_CONFIG, CANDY_CRUSH_SOUNDS } from "./CandyCrushConstants.js";
7
- import { immerMiddleware } from "../../services/UtilsService.js";
8
- import { playSound } from "../../services/SoundsService.js";
9
- import { playHaptic, HapticType } from "../../services/HapticsService.js";
10
- const gameService = new CandyCrushService();
11
- export const useCandyCrushStore = create()(subscribeWithSelector(immerMiddleware((set, get) => ({
12
- // Initial state
13
- grid: gameService.createGrid(),
14
- score: 0,
15
- timeRemaining: 180,
16
- gameDuration: 180,
17
- isPlaying: false,
18
- isGameOver: false,
19
- selectedCandy: null,
20
- isProcessing: false,
21
- difficulty: 'easy',
22
- candyTypes: 4,
23
- enableSounds: true,
24
- enableHaptics: true,
25
- comboCount: 0,
26
- gameTimer: null,
27
- matchedCandyIds: new Set(),
28
- fallingCandyIds: new Set(),
29
- startGame: () => {
30
- const state = get();
31
-
32
- // Clear any existing timer
33
- if (state.gameTimer) {
34
- clearInterval(state.gameTimer);
35
- }
36
-
37
- // Play start sound
38
- playSound(CANDY_CRUSH_SOUNDS.SWAP, state.enableSounds);
39
- playHaptic(HapticType.MEDIUM, state.enableHaptics);
40
-
41
- // Start countdown timer
42
- const timer = setInterval(() => {
43
- const currentState = get();
44
- if (currentState.timeRemaining > 0 && currentState.isPlaying) {
45
- set(draft => {
46
- draft.timeRemaining--;
47
-
48
- // Warning sound at 30 seconds
49
- if (draft.timeRemaining === 30) {
50
- playSound(CANDY_CRUSH_SOUNDS.SPECIAL, draft.enableSounds);
51
- playHaptic(HapticType.MEDIUM, draft.enableHaptics);
52
- }
53
-
54
- // Warning sound at 10 seconds
55
- if (draft.timeRemaining === 10) {
56
- playSound(CANDY_CRUSH_SOUNDS.SPECIAL, draft.enableSounds);
57
- playHaptic(HapticType.HEAVY, draft.enableHaptics);
58
- }
59
-
60
- // Check if time is up
61
- if (draft.timeRemaining <= 0) {
62
- draft.isGameOver = true;
63
- draft.isPlaying = false;
64
- if (draft.gameTimer) {
65
- clearInterval(draft.gameTimer);
66
- draft.gameTimer = null;
67
- }
68
- playSound(CANDY_CRUSH_SOUNDS.LOSE, draft.enableSounds);
69
- playHaptic(HapticType.HEAVY, draft.enableHaptics);
70
- }
71
- });
72
- }
73
- }, 1000);
74
- set(state => {
75
- state.isPlaying = true;
76
- state.gameTimer = timer;
77
- });
78
- },
79
- stopGame: () => {
80
- const state = get();
81
- if (state.gameTimer) {
82
- clearInterval(state.gameTimer);
83
- }
84
-
85
- // Play stop sound
86
- playSound(CANDY_CRUSH_SOUNDS.LOSE, state.enableSounds);
87
- playHaptic(HapticType.MEDIUM, state.enableHaptics);
88
-
89
- // Reset the game instead of showing game over modal
90
- state.initializeGame(state.difficulty);
91
- },
92
- resetGame: () => {
93
- const state = get();
94
- state.initializeGame(state.difficulty);
95
- state.startGame();
96
- },
97
- initializeGame: (difficulty = 'easy') => {
98
- const state = get();
99
- if (state.gameTimer) {
100
- clearInterval(state.gameTimer);
101
- }
102
- set(state => {
103
- const config = DIFFICULTY_CONFIG[difficulty];
104
- gameService.resetIdCounter();
105
- state.grid = gameService.initializeGrid(config.candyTypes);
106
- state.score = 0;
107
- state.timeRemaining = config.gameDuration;
108
- state.gameDuration = config.gameDuration;
109
- state.isPlaying = false;
110
- state.isGameOver = false;
111
- state.selectedCandy = null;
112
- state.isProcessing = false;
113
- state.difficulty = difficulty;
114
- state.candyTypes = config.candyTypes;
115
- state.comboCount = 0;
116
- state.gameTimer = null;
117
- state.matchedCandyIds = new Set();
118
- state.fallingCandyIds = new Set();
119
- });
120
- },
121
- selectCandy: candy => {
122
- const state = get();
123
- if (state.isProcessing || !state.isPlaying || state.isGameOver) {
124
- return;
125
- }
126
- set(draft => {
127
- if (!draft.selectedCandy) {
128
- // First candy selected
129
- draft.selectedCandy = candy;
130
- playSound(CANDY_CRUSH_SOUNDS.SWAP, draft.enableSounds);
131
- playHaptic(HapticType.LIGHT, draft.enableHaptics);
132
- } else if (draft.selectedCandy.id === candy.id) {
133
- // Deselect same candy
134
- draft.selectedCandy = null;
135
- } else if (gameService.canSwap(draft.selectedCandy, candy)) {
136
- // Valid swap - process it
137
- const candy1 = draft.selectedCandy;
138
- const candy2 = candy;
139
-
140
- // Swap candies
141
- gameService.swapCandies(draft.grid, candy1, candy2);
142
-
143
- // Only update affected rows to minimize re-renders
144
- const affectedRows = new Set([candy1.row, candy2.row]);
145
- affectedRows.forEach(rowIndex => {
146
- if (draft.grid[rowIndex]) {
147
- draft.grid[rowIndex] = [...draft.grid[rowIndex]];
148
- }
149
- });
150
-
151
- // Check for matches
152
- const matchResult = gameService.findMatches(draft.grid);
153
- if (matchResult.hasMatches) {
154
- // Valid move
155
- draft.selectedCandy = null;
156
- draft.isProcessing = true;
157
- playSound(CANDY_CRUSH_SOUNDS.SWAP, draft.enableSounds);
158
- playHaptic(HapticType.MEDIUM, draft.enableHaptics);
159
-
160
- // Process matches after animation
161
- setTimeout(() => {
162
- get().processMatches();
163
- }, CANDY_CRUSH_GAME_CONFIG.SWAP_DURATION);
164
- } else {
165
- // Invalid move - swap back
166
- gameService.swapCandies(draft.grid, candy1, candy2);
167
- draft.selectedCandy = null;
168
-
169
- // Only update affected rows to minimize re-renders
170
- const affectedRows = new Set([candy1.row, candy2.row]);
171
- affectedRows.forEach(rowIndex => {
172
- if (draft.grid[rowIndex]) {
173
- draft.grid[rowIndex] = [...draft.grid[rowIndex]];
174
- }
175
- });
176
- playSound(CANDY_CRUSH_SOUNDS.SWAP, draft.enableSounds);
177
- playHaptic(HapticType.LIGHT, draft.enableHaptics);
178
- }
179
- } else {
180
- // Not adjacent - select new candy
181
- draft.selectedCandy = candy;
182
- playSound(CANDY_CRUSH_SOUNDS.SWAP, draft.enableSounds);
183
- playHaptic(HapticType.LIGHT, draft.enableHaptics);
184
- }
185
- });
186
- },
187
- processMatches: async () => {
188
- let hasMatches = true;
189
- let comboCount = 0;
190
- while (hasMatches) {
191
- // Get fresh state at the start of each iteration
192
- const state = get();
193
-
194
- // Find matches
195
- const matchResult = gameService.findMatches(state.grid);
196
- if (!matchResult.hasMatches) {
197
- hasMatches = false;
198
- break;
199
- }
200
- comboCount++;
201
-
202
- // Calculate score with combo multiplier
203
- const baseScore = matchResult.score;
204
- const comboMultiplier = comboCount > 1 ? Math.pow(CANDY_CRUSH_GAME_CONFIG.COMBO_MULTIPLIER, comboCount - 1) : 1;
205
- const finalScore = Math.floor(baseScore * comboMultiplier);
206
-
207
- // Update score
208
- set(draft => {
209
- draft.score += finalScore;
210
- draft.comboCount = comboCount;
211
- });
212
-
213
- // Play sound
214
- if (comboCount > 1) {
215
- playSound(CANDY_CRUSH_SOUNDS.COMBO, state.enableSounds);
216
- playHaptic(HapticType.HEAVY, state.enableHaptics);
217
- } else {
218
- playSound(CANDY_CRUSH_SOUNDS.MATCH, state.enableSounds);
219
- playHaptic(HapticType.MEDIUM, state.enableHaptics);
220
- }
221
-
222
- // Mark candies as matched for animation using Set (no grid mutation needed)
223
- set(draft => {
224
- draft.matchedCandyIds = new Set(matchResult.matches.map(c => c.id));
225
- // No grid update needed - animation state is separate
226
- });
227
-
228
- // Wait for animation
229
- await new Promise(resolve => setTimeout(resolve, CANDY_CRUSH_GAME_CONFIG.ANIMATION_DURATION));
230
-
231
- // Remove matches, apply gravity, and fill empty spaces (all in one set call)
232
- set(draft => {
233
- // Clear matched IDs
234
- draft.matchedCandyIds = new Set();
235
-
236
- // Track which rows will be affected by matches
237
- const affectedRows = new Set();
238
- matchResult.matches.forEach(candy => affectedRows.add(candy.row));
239
-
240
- // Store original candy IDs per row to detect changes
241
- const originalRowIds = draft.grid.map(row => row.map(c => c?.id).join(','));
242
-
243
- // Remove matches
244
- gameService.removeMatches(draft.grid, matchResult.matches);
245
-
246
- // Apply gravity (affects all rows below matches)
247
- gameService.applyGravity(draft.grid);
248
-
249
- // Fill empty spaces (affects top rows)
250
- gameService.fillEmptySpaces(draft.grid, state.candyTypes);
251
-
252
- // Mark falling candies
253
- const fallingIds = new Set();
254
- draft.grid.forEach(row => {
255
- row.forEach(candy => {
256
- if (candy && candy.isFalling) {
257
- fallingIds.add(candy.id);
258
- }
259
- });
260
- });
261
- draft.fallingCandyIds = fallingIds;
262
-
263
- // Only update rows that actually changed
264
- draft.grid.forEach((row, rowIndex) => {
265
- const newRowIds = row.map(c => c?.id).join(',');
266
- if (originalRowIds[rowIndex] !== newRowIds) {
267
- draft.grid[rowIndex] = [...row];
268
- }
269
- });
270
- });
271
-
272
- // Wait for fall animation
273
- await new Promise(resolve => setTimeout(resolve, CANDY_CRUSH_GAME_CONFIG.FALL_DURATION));
274
- }
275
-
276
- // Reset processing state and clear animation states
277
- set(draft => {
278
- draft.isProcessing = false;
279
- draft.comboCount = 0;
280
- draft.matchedCandyIds = new Set();
281
- draft.fallingCandyIds = new Set();
282
- });
283
- },
284
- updateSettings: (enableSounds, enableHaptics) => {
285
- set(state => {
286
- state.enableSounds = enableSounds;
287
- state.enableHaptics = enableHaptics;
288
- });
289
- }
290
- }))));
291
-
292
- // Selector hooks for optimal re-renders
293
- export const useGrid = () => useCandyCrushStore(state => state.grid);
294
- export const useScore = () => useCandyCrushStore(state => state.score);
295
- export const useTimeRemaining = () => useCandyCrushStore(state => state.timeRemaining);
296
- export const useGameDuration = () => useCandyCrushStore(state => state.gameDuration);
297
- export const useIsPlaying = () => useCandyCrushStore(state => state.isPlaying);
298
- export const useIsGameOver = () => useCandyCrushStore(state => state.isGameOver);
299
- export const useSelectedCandy = () => useCandyCrushStore(state => state.selectedCandy);
300
- export const useComboCount = () => useCandyCrushStore(state => state.comboCount);
301
- export const useMatchedCandyIds = () => useCandyCrushStore(state => state.matchedCandyIds);
302
- export const useFallingCandyIds = () => useCandyCrushStore(state => state.fallingCandyIds);
303
- //# sourceMappingURL=CandyCrushStore.js.map
1
+ "use strict";import{create}from 'zustand';import{subscribeWithSelector}from 'zustand/middleware';import{CandyCrushService}from "./CandyCrushService.js";import{CANDY_CRUSH_GAME_CONFIG,DIFFICULTY_CONFIG,CANDY_CRUSH_SOUNDS}from "./CandyCrushConstants.js";import{immerMiddleware}from "../../services/UtilsService.js";import{playSound}from "../../services/SoundsService.js";import{playHaptic,HapticType}from "../../services/HapticsService.js";const gameService = new CandyCrushService();export const useCandyCrushStore = create()(subscribeWithSelector(immerMiddleware((set,get)=>({grid:gameService.createGrid(),score:0,timeRemaining:180,gameDuration:180,isPlaying:false,isGameOver:false,selectedCandy:null,isProcessing:false,difficulty:'easy',candyTypes:4,enableSounds:true,enableHaptics:true,comboCount:0,gameTimer:null,matchedCandyIds:new Set(),fallingCandyIds:new Set(),startGame:()=>{const state = get();if(state.gameTimer){clearInterval(state.gameTimer);}playSound(CANDY_CRUSH_SOUNDS.SWAP,state.enableSounds);playHaptic(HapticType.MEDIUM,state.enableHaptics);const timer = setInterval(()=>{const currentState = get();if(currentState.timeRemaining > 0 && currentState.isPlaying){set(draft =>{draft.timeRemaining--;if(draft.timeRemaining === 30){playSound(CANDY_CRUSH_SOUNDS.SPECIAL,draft.enableSounds);playHaptic(HapticType.MEDIUM,draft.enableHaptics);}if(draft.timeRemaining === 10){playSound(CANDY_CRUSH_SOUNDS.SPECIAL,draft.enableSounds);playHaptic(HapticType.HEAVY,draft.enableHaptics);}if(draft.timeRemaining <= 0){draft.isGameOver = true;draft.isPlaying = false;if(draft.gameTimer){clearInterval(draft.gameTimer);draft.gameTimer = null;}playSound(CANDY_CRUSH_SOUNDS.LOSE,draft.enableSounds);playHaptic(HapticType.HEAVY,draft.enableHaptics);}});}},1000);set(state =>{state.isPlaying = true;state.gameTimer = timer;});},stopGame:()=>{const state = get();if(state.gameTimer){clearInterval(state.gameTimer);}playSound(CANDY_CRUSH_SOUNDS.LOSE,state.enableSounds);playHaptic(HapticType.MEDIUM,state.enableHaptics);state.initializeGame(state.difficulty);},resetGame:()=>{const state = get();state.initializeGame(state.difficulty);state.startGame();},initializeGame:(difficulty = 'easy')=>{const state = get();if(state.gameTimer){clearInterval(state.gameTimer);}set(state =>{const config = DIFFICULTY_CONFIG[difficulty];gameService.resetIdCounter();state.grid = gameService.initializeGrid(config.candyTypes);state.score = 0;state.timeRemaining = config.gameDuration;state.gameDuration = config.gameDuration;state.isPlaying = false;state.isGameOver = false;state.selectedCandy = null;state.isProcessing = false;state.difficulty = difficulty;state.candyTypes = config.candyTypes;state.comboCount = 0;state.gameTimer = null;state.matchedCandyIds = new Set();state.fallingCandyIds = new Set();});},selectCandy:candy =>{const state = get();if(state.isProcessing || !state.isPlaying || state.isGameOver){return;}set(draft =>{if(!draft.selectedCandy){draft.selectedCandy = candy;playSound(CANDY_CRUSH_SOUNDS.SWAP,draft.enableSounds);playHaptic(HapticType.LIGHT,draft.enableHaptics);}else if(draft.selectedCandy.id === candy.id){draft.selectedCandy = null;}else if(gameService.canSwap(draft.selectedCandy,candy)){const candy1 = draft.selectedCandy;const candy2 = candy;gameService.swapCandies(draft.grid,candy1,candy2);const affectedRows = new Set([candy1.row,candy2.row]);affectedRows.forEach(rowIndex =>{if(draft.grid[rowIndex]){draft.grid[rowIndex] = [...draft.grid[rowIndex]];}});const matchResult = gameService.findMatches(draft.grid);if(matchResult.hasMatches){draft.selectedCandy = null;draft.isProcessing = true;playSound(CANDY_CRUSH_SOUNDS.SWAP,draft.enableSounds);playHaptic(HapticType.MEDIUM,draft.enableHaptics);setTimeout(()=>{get().processMatches();},CANDY_CRUSH_GAME_CONFIG.SWAP_DURATION);}else{gameService.swapCandies(draft.grid,candy1,candy2);draft.selectedCandy = null;const affectedRows = new Set([candy1.row,candy2.row]);affectedRows.forEach(rowIndex =>{if(draft.grid[rowIndex]){draft.grid[rowIndex] = [...draft.grid[rowIndex]];}});playSound(CANDY_CRUSH_SOUNDS.SWAP,draft.enableSounds);playHaptic(HapticType.LIGHT,draft.enableHaptics);}}else{draft.selectedCandy = candy;playSound(CANDY_CRUSH_SOUNDS.SWAP,draft.enableSounds);playHaptic(HapticType.LIGHT,draft.enableHaptics);}});},processMatches:async()=>{let hasMatches = true;let comboCount = 0;while(hasMatches){const state = get();const matchResult = gameService.findMatches(state.grid);if(!matchResult.hasMatches){hasMatches = false;break;}comboCount++;const baseScore = matchResult.score;const comboMultiplier = comboCount > 1 ? Math.pow(CANDY_CRUSH_GAME_CONFIG.COMBO_MULTIPLIER,comboCount - 1):1;const finalScore = Math.floor(baseScore * comboMultiplier);set(draft =>{draft.score += finalScore;draft.comboCount = comboCount;});if(comboCount > 1){playSound(CANDY_CRUSH_SOUNDS.COMBO,state.enableSounds);playHaptic(HapticType.HEAVY,state.enableHaptics);}else{playSound(CANDY_CRUSH_SOUNDS.MATCH,state.enableSounds);playHaptic(HapticType.MEDIUM,state.enableHaptics);}set(draft =>{draft.matchedCandyIds = new Set(matchResult.matches.map(c => c.id));});await new Promise(resolve => setTimeout(resolve,CANDY_CRUSH_GAME_CONFIG.ANIMATION_DURATION));set(draft =>{draft.matchedCandyIds = new Set();const affectedRows = new Set();matchResult.matches.forEach(candy => affectedRows.add(candy.row));const originalRowIds = draft.grid.map(row => row.map(c => c?.id).join(','));gameService.removeMatches(draft.grid,matchResult.matches);gameService.applyGravity(draft.grid);gameService.fillEmptySpaces(draft.grid,state.candyTypes);const fallingIds = new Set();draft.grid.forEach(row =>{row.forEach(candy =>{if(candy && candy.isFalling){fallingIds.add(candy.id);}});});draft.fallingCandyIds = fallingIds;draft.grid.forEach((row,rowIndex)=>{const newRowIds = row.map(c => c?.id).join(',');if(originalRowIds[rowIndex] !== newRowIds){draft.grid[rowIndex] = [...row];}});});await new Promise(resolve => setTimeout(resolve,CANDY_CRUSH_GAME_CONFIG.FALL_DURATION));}set(draft =>{draft.isProcessing = false;draft.comboCount = 0;draft.matchedCandyIds = new Set();draft.fallingCandyIds = new Set();});},updateSettings:(enableSounds,enableHaptics)=>{set(state =>{state.enableSounds = enableSounds;state.enableHaptics = enableHaptics;});}}))));export const useGrid =()=> useCandyCrushStore(state => state.grid);export const useScore =()=> useCandyCrushStore(state => state.score);export const useTimeRemaining =()=> useCandyCrushStore(state => state.timeRemaining);export const useGameDuration =()=> useCandyCrushStore(state => state.gameDuration);export const useIsPlaying =()=> useCandyCrushStore(state => state.isPlaying);export const useIsGameOver =()=> useCandyCrushStore(state => state.isGameOver);export const useSelectedCandy =()=> useCandyCrushStore(state => state.selectedCandy);export const useComboCount =()=> useCandyCrushStore(state => state.comboCount);export const useMatchedCandyIds =()=> useCandyCrushStore(state => state.matchedCandyIds);export const useFallingCandyIds =()=> useCandyCrushStore(state => state.fallingCandyIds);