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,13 +1 @@
1
- "use strict";
2
-
3
- export const formatTime = seconds => {
4
- const mins = Math.floor(seconds / 60);
5
- const secs = seconds % 60;
6
- return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
7
- };
8
- export class FruitMergerService {
9
- cleanup() {
10
- // Cleanup logic if needed
11
- }
12
- }
13
- //# sourceMappingURL=FruitMergerService.js.map
1
+ "use strict";export const formatTime = seconds =>{const mins = Math.floor(seconds / 60);const secs = seconds % 60;return `${mins.toString().padStart(2,'0')}:${secs.toString().padStart(2,'0')}`;};export class FruitMergerService{cleanup(){}}
@@ -1,315 +1 @@
1
- "use strict";
2
-
3
- import { create } from 'zustand';
4
- import { subscribeWithSelector } from 'zustand/middleware';
5
- import { immerMiddleware } from "../../services/UtilsService.js";
6
- import { FRUIT_TYPES, FRUIT_MERGER_GAME_CONFIG } from "./FruitMergerConstants.js";
7
- import { playSound, GAME_SOUNDS } from "../../services/SoundsService.js";
8
- import { playHaptic, HapticType } from "../../services/HapticsService.js";
9
- const generateRandomFruitType = () => {
10
- return Math.floor(Math.random() * FRUIT_MERGER_GAME_CONFIG.MAX_FRUIT_TYPE);
11
- };
12
- export const useFruitMergerStore = create()(immerMiddleware(subscribeWithSelector((set, get) => ({
13
- isPlaying: false,
14
- isGameOver: false,
15
- fruits: [],
16
- currentFruit: null,
17
- nextFruitType: 0,
18
- score: 0,
19
- time: 0,
20
- timerInterval: null,
21
- gameLoopInterval: null,
22
- spawnInterval: null,
23
- initializeGame: () => {
24
- set(state => {
25
- state.fruits = [];
26
- state.currentFruit = null;
27
- state.nextFruitType = generateRandomFruitType();
28
- state.score = 0;
29
- state.time = 0;
30
- state.isPlaying = false;
31
- state.isGameOver = false;
32
- });
33
- },
34
- startGame: () => {
35
- const state = get();
36
- if (state.timerInterval) clearInterval(state.timerInterval);
37
- if (state.gameLoopInterval) clearInterval(state.gameLoopInterval);
38
- if (state.spawnInterval) clearInterval(state.spawnInterval);
39
- const timerInterval = setInterval(() => {
40
- get().incrementTime();
41
- }, 1000);
42
- const gameLoopInterval = setInterval(() => {
43
- get().updatePhysics();
44
- }, 1000 / 30);
45
- set(state => {
46
- state.isPlaying = true;
47
- state.isGameOver = false;
48
- state.time = 0;
49
- state.timerInterval = timerInterval;
50
- state.gameLoopInterval = gameLoopInterval;
51
- });
52
- get().spawnCurrentFruit();
53
- },
54
- stopGame: () => {
55
- const state = get();
56
- if (state.timerInterval) clearInterval(state.timerInterval);
57
- if (state.gameLoopInterval) clearInterval(state.gameLoopInterval);
58
- if (state.spawnInterval) clearInterval(state.spawnInterval);
59
-
60
- // Reset the game instead of showing game over modal
61
- state.initializeGame();
62
- },
63
- resetGame: () => {
64
- const state = get();
65
- if (state.timerInterval) clearInterval(state.timerInterval);
66
- if (state.gameLoopInterval) clearInterval(state.gameLoopInterval);
67
- if (state.spawnInterval) clearInterval(state.spawnInterval);
68
- set(state => {
69
- state.isPlaying = false;
70
- state.isGameOver = false;
71
- state.fruits = [];
72
- state.currentFruit = null;
73
- state.score = 0;
74
- state.time = 0;
75
- state.timerInterval = null;
76
- state.gameLoopInterval = null;
77
- state.spawnInterval = null;
78
- });
79
- },
80
- spawnCurrentFruit: () => {
81
- const state = get();
82
- const fruitType = state.nextFruitType;
83
- const fruit = {
84
- id: `fruit-${Date.now()}-${Math.random()}`,
85
- typeId: fruitType,
86
- x: FRUIT_MERGER_GAME_CONFIG.CONTAINER_WIDTH / 2,
87
- y: 30,
88
- vx: 0,
89
- vy: 0,
90
- isActive: false,
91
- isMerging: false
92
- };
93
- set(state => {
94
- state.currentFruit = fruit;
95
- });
96
- },
97
- dropCurrentFruit: () => {
98
- const state = get();
99
- if (!state.currentFruit) return;
100
- set(draftState => {
101
- if (draftState.currentFruit) {
102
- draftState.currentFruit.isActive = true;
103
- draftState.fruits.push(draftState.currentFruit);
104
- draftState.currentFruit = null;
105
- draftState.nextFruitType = generateRandomFruitType();
106
- }
107
- });
108
- setTimeout(() => {
109
- get().spawnCurrentFruit();
110
- }, 300);
111
- },
112
- updateCurrentFruitPosition: x => {
113
- set(state => {
114
- if (state.currentFruit) {
115
- const nextFruitData = FRUIT_TYPES[state.nextFruitType];
116
- if (!nextFruitData) return;
117
- const fruitData = FRUIT_TYPES[state.currentFruit.typeId];
118
- if (fruitData) {
119
- const radius = fruitData.size / 2;
120
- state.currentFruit.x = Math.max(radius, Math.min(FRUIT_MERGER_GAME_CONFIG.PLAY_AREA_WIDTH - radius, x));
121
- }
122
- }
123
- });
124
- },
125
- updatePhysics: () => {
126
- const state = get();
127
- if (!state.isPlaying || state.fruits.length === 0) return;
128
- const {
129
- PLAY_AREA_WIDTH,
130
- PLAY_AREA_HEIGHT,
131
- GRAVITY,
132
- BOUNCE,
133
- FRICTION
134
- } = FRUIT_MERGER_GAME_CONFIG;
135
-
136
- // Use set() but ONLY update fruits array (not other state)
137
- set(draftState => {
138
- // Apply physics
139
- for (let i = 0; i < draftState.fruits.length; i++) {
140
- const fruit = draftState.fruits[i];
141
- if (!fruit || !fruit.isActive || fruit.isMerging) continue;
142
- const fruitData = FRUIT_TYPES[fruit.typeId];
143
- if (!fruitData) continue;
144
- const radius = fruitData.size / 2;
145
- fruit.vy += GRAVITY;
146
- fruit.x += fruit.vx;
147
- fruit.y += fruit.vy;
148
- fruit.vx *= FRICTION;
149
- fruit.vy *= FRICTION;
150
-
151
- // Wall collisions
152
- if (fruit.x - radius < 0) {
153
- fruit.x = radius;
154
- fruit.vx *= -BOUNCE;
155
- }
156
- if (fruit.x + radius > PLAY_AREA_WIDTH) {
157
- fruit.x = PLAY_AREA_WIDTH - radius;
158
- fruit.vx *= -BOUNCE;
159
- }
160
-
161
- // Ground collision with stronger response
162
- if (fruit.y + radius >= PLAY_AREA_HEIGHT) {
163
- fruit.y = PLAY_AREA_HEIGHT - radius;
164
- fruit.vy *= -BOUNCE;
165
- fruit.vx *= FRICTION;
166
- if (Math.abs(fruit.vy) < 0.5) {
167
- fruit.vy = 0;
168
- }
169
- }
170
-
171
- // Top boundary
172
- if (fruit.y - radius < 0) {
173
- fruit.y = radius;
174
- fruit.vy = Math.abs(fruit.vy) * 0.5;
175
- }
176
- }
177
-
178
- // Collision detection and response
179
- for (let i = 0; i < draftState.fruits.length; i++) {
180
- const fruit = draftState.fruits[i];
181
- if (!fruit || !fruit.isActive || fruit.isMerging) continue;
182
- const fruitData = FRUIT_TYPES[fruit.typeId];
183
- if (!fruitData) continue;
184
- const radius = fruitData.size / 2;
185
- for (let j = i + 1; j < draftState.fruits.length; j++) {
186
- const otherFruit = draftState.fruits[j];
187
- if (!otherFruit || !otherFruit.isActive || otherFruit.isMerging) continue;
188
- const otherFruitData = FRUIT_TYPES[otherFruit.typeId];
189
- if (!otherFruitData) continue;
190
- const otherRadius = otherFruitData.size / 2;
191
- const dx = otherFruit.x - fruit.x;
192
- const dy = otherFruit.y - fruit.y;
193
- const distance = Math.sqrt(dx * dx + dy * dy);
194
- const minDistance = radius + otherRadius;
195
- if (distance < minDistance && distance > 0) {
196
- // Separate overlapping fruits
197
- const overlap = minDistance - distance;
198
- const angle = Math.atan2(dy, dx);
199
- const separationX = Math.cos(angle) * overlap * 0.5;
200
- const separationY = Math.sin(angle) * overlap * 0.5;
201
- fruit.x -= separationX;
202
- fruit.y -= separationY;
203
- otherFruit.x += separationX;
204
- otherFruit.y += separationY;
205
-
206
- // Apply collision response
207
- const relativeVx = otherFruit.vx - fruit.vx;
208
- const relativeVy = otherFruit.vy - fruit.vy;
209
- const dotProduct = relativeVx * Math.cos(angle) + relativeVy * Math.sin(angle);
210
- if (dotProduct < 0) {
211
- const impulse = dotProduct * 0.8;
212
- fruit.vx += Math.cos(angle) * impulse;
213
- fruit.vy += Math.sin(angle) * impulse;
214
- otherFruit.vx -= Math.cos(angle) * impulse;
215
- otherFruit.vy -= Math.sin(angle) * impulse;
216
- }
217
-
218
- // Re-apply boundary constraints after separation
219
- fruit.x = Math.max(radius, Math.min(PLAY_AREA_WIDTH - radius, fruit.x));
220
- fruit.y = Math.max(radius, Math.min(PLAY_AREA_HEIGHT - radius, fruit.y));
221
- otherFruit.x = Math.max(otherRadius, Math.min(PLAY_AREA_WIDTH - otherRadius, otherFruit.x));
222
- otherFruit.y = Math.max(otherRadius, Math.min(PLAY_AREA_HEIGHT - otherRadius, otherFruit.y));
223
- }
224
- }
225
- }
226
- });
227
- get().checkMerges({
228
- enableSounds: true,
229
- enableHaptics: true
230
- });
231
- },
232
- checkMerges: settings => {
233
- const state = get();
234
- const {
235
- MERGE_DISTANCE
236
- } = FRUIT_MERGER_GAME_CONFIG;
237
- for (let i = 0; i < state.fruits.length; i++) {
238
- const fruit1 = state.fruits[i];
239
- if (!fruit1 || !fruit1.isActive || fruit1.isMerging || fruit1.y < 0) continue;
240
- for (let j = i + 1; j < state.fruits.length; j++) {
241
- const fruit2 = state.fruits[j];
242
- if (!fruit2 || !fruit2.isActive || fruit2.isMerging || fruit2.y < 0) continue;
243
- if (fruit1.typeId === fruit2.typeId) {
244
- const dx = fruit2.x - fruit1.x;
245
- const dy = fruit2.y - fruit1.y;
246
- const distance = Math.sqrt(dx * dx + dy * dy);
247
- const fruit1Data = FRUIT_TYPES[fruit1.typeId];
248
- const fruit2Data = FRUIT_TYPES[fruit2.typeId];
249
- if (!fruit1Data || !fruit2Data) continue;
250
- const radius1 = fruit1Data.size / 2;
251
- const radius2 = fruit2Data.size / 2;
252
- const touchDistance = radius1 + radius2;
253
-
254
- // Check if fruits are touching or overlapping
255
- if (distance <= touchDistance + MERGE_DISTANCE) {
256
- // Check if both fruits have low velocity (relatively stable)
257
- const fruit1Speed = Math.sqrt(fruit1.vx * fruit1.vx + fruit1.vy * fruit1.vy);
258
- const fruit2Speed = Math.sqrt(fruit2.vx * fruit2.vx + fruit2.vy * fruit2.vy);
259
-
260
- // Merge if at least one fruit is relatively stable (speed < 5)
261
- if (fruit1Speed < 5 || fruit2Speed < 5) {
262
- get().mergeFruits(fruit1, fruit2, settings);
263
- return;
264
- }
265
- }
266
- }
267
- }
268
- }
269
- const maxFruitReached = state.fruits.some(f => f.typeId === FRUIT_TYPES.length - 1 && f.isActive);
270
- if (maxFruitReached) {
271
- playSound(GAME_SOUNDS.FRUIT_MERGER.COMPLETE, settings.enableSounds);
272
- playHaptic(HapticType.SUCCESS, settings.enableHaptics);
273
- get().stopGame();
274
- }
275
- },
276
- mergeFruits: (fruit1, fruit2, settings) => {
277
- const nextTypeId = fruit1.typeId + 1;
278
- if (nextTypeId >= FRUIT_TYPES.length) return;
279
- const mergeX = (fruit1.x + fruit2.x) / 2;
280
- const mergeY = (fruit1.y + fruit2.y) / 2;
281
- set(state => {
282
- state.fruits = state.fruits.filter(f => f.id !== fruit1.id && f.id !== fruit2.id);
283
- const newFruit = {
284
- id: `fruit-${Date.now()}-${Math.random()}`,
285
- typeId: nextTypeId,
286
- x: mergeX,
287
- y: mergeY,
288
- vx: 0,
289
- vy: -2,
290
- isActive: true,
291
- isMerging: false
292
- };
293
- state.fruits.push(newFruit);
294
- const nextFruitType = FRUIT_TYPES[nextTypeId];
295
- if (nextFruitType) {
296
- state.score += nextFruitType.score;
297
- }
298
- });
299
- playSound(GAME_SOUNDS.FRUIT_MERGER.MERGE, settings.enableSounds);
300
- playHaptic(HapticType.MEDIUM, settings.enableHaptics);
301
- },
302
- incrementTime: () => {
303
- set(state => {
304
- state.time += 1;
305
- });
306
- }
307
- }))));
308
- export const useIsPlaying = () => useFruitMergerStore(state => state.isPlaying);
309
- export const useIsGameOver = () => useFruitMergerStore(state => state.isGameOver);
310
- export const useFruits = () => useFruitMergerStore(state => state.fruits);
311
- export const useCurrentFruit = () => useFruitMergerStore(state => state.currentFruit);
312
- export const useNextFruitType = () => useFruitMergerStore(state => state.nextFruitType);
313
- export const useScore = () => useFruitMergerStore(state => state.score);
314
- export const useTime = () => useFruitMergerStore(state => state.time);
315
- //# sourceMappingURL=FruitMergerStore.js.map
1
+ "use strict";import{create}from 'zustand';import{subscribeWithSelector}from 'zustand/middleware';import{immerMiddleware}from "../../services/UtilsService.js";import{FRUIT_TYPES,FRUIT_MERGER_GAME_CONFIG}from "./FruitMergerConstants.js";import{playSound,GAME_SOUNDS}from "../../services/SoundsService.js";import{playHaptic,HapticType}from "../../services/HapticsService.js";const generateRandomFruitType =()=>{return Math.floor(Math.random()* FRUIT_MERGER_GAME_CONFIG.MAX_FRUIT_TYPE);};export const useFruitMergerStore = create()(immerMiddleware(subscribeWithSelector((set,get)=>({isPlaying:false,isGameOver:false,fruits:[],currentFruit:null,nextFruitType:0,score:0,time:0,timerInterval:null,gameLoopInterval:null,spawnInterval:null,initializeGame:()=>{set(state =>{state.fruits = [];state.currentFruit = null;state.nextFruitType = generateRandomFruitType();state.score = 0;state.time = 0;state.isPlaying = false;state.isGameOver = false;});},startGame:()=>{const state = get();if(state.timerInterval)clearInterval(state.timerInterval);if(state.gameLoopInterval)clearInterval(state.gameLoopInterval);if(state.spawnInterval)clearInterval(state.spawnInterval);const timerInterval = setInterval(()=>{get().incrementTime();},1000);const gameLoopInterval = setInterval(()=>{get().updatePhysics();},1000 / 30);set(state =>{state.isPlaying = true;state.isGameOver = false;state.time = 0;state.timerInterval = timerInterval;state.gameLoopInterval = gameLoopInterval;});get().spawnCurrentFruit();},stopGame:()=>{const state = get();if(state.timerInterval)clearInterval(state.timerInterval);if(state.gameLoopInterval)clearInterval(state.gameLoopInterval);if(state.spawnInterval)clearInterval(state.spawnInterval);state.initializeGame();},resetGame:()=>{const state = get();if(state.timerInterval)clearInterval(state.timerInterval);if(state.gameLoopInterval)clearInterval(state.gameLoopInterval);if(state.spawnInterval)clearInterval(state.spawnInterval);set(state =>{state.isPlaying = false;state.isGameOver = false;state.fruits = [];state.currentFruit = null;state.score = 0;state.time = 0;state.timerInterval = null;state.gameLoopInterval = null;state.spawnInterval = null;});},spawnCurrentFruit:()=>{const state = get();const fruitType = state.nextFruitType;const fruit ={id:`fruit-${Date.now()}-${Math.random()}`,typeId:fruitType,x:FRUIT_MERGER_GAME_CONFIG.CONTAINER_WIDTH / 2,y:30,vx:0,vy:0,isActive:false,isMerging:false};set(state =>{state.currentFruit = fruit;});},dropCurrentFruit:()=>{const state = get();if(!state.currentFruit)return;set(draftState =>{if(draftState.currentFruit){draftState.currentFruit.isActive = true;draftState.fruits.push(draftState.currentFruit);draftState.currentFruit = null;draftState.nextFruitType = generateRandomFruitType();}});setTimeout(()=>{get().spawnCurrentFruit();},300);},updateCurrentFruitPosition:x =>{set(state =>{if(state.currentFruit){const nextFruitData = FRUIT_TYPES[state.nextFruitType];if(!nextFruitData)return;const fruitData = FRUIT_TYPES[state.currentFruit.typeId];if(fruitData){const radius = fruitData.size / 2;state.currentFruit.x = Math.max(radius,Math.min(FRUIT_MERGER_GAME_CONFIG.PLAY_AREA_WIDTH - radius,x));}}});},updatePhysics:()=>{const state = get();if(!state.isPlaying || state.fruits.length === 0)return;const{PLAY_AREA_WIDTH,PLAY_AREA_HEIGHT,GRAVITY,BOUNCE,FRICTION}= FRUIT_MERGER_GAME_CONFIG;set(draftState =>{for(let i = 0;i < draftState.fruits.length;i++){const fruit = draftState.fruits[i];if(!fruit || !fruit.isActive || fruit.isMerging)continue;const fruitData = FRUIT_TYPES[fruit.typeId];if(!fruitData)continue;const radius = fruitData.size / 2;fruit.vy += GRAVITY;fruit.x += fruit.vx;fruit.y += fruit.vy;fruit.vx *= FRICTION;fruit.vy *= FRICTION;if(fruit.x - radius < 0){fruit.x = radius;fruit.vx *= -BOUNCE;}if(fruit.x + radius > PLAY_AREA_WIDTH){fruit.x = PLAY_AREA_WIDTH - radius;fruit.vx *= -BOUNCE;}if(fruit.y + radius >= PLAY_AREA_HEIGHT){fruit.y = PLAY_AREA_HEIGHT - radius;fruit.vy *= -BOUNCE;fruit.vx *= FRICTION;if(Math.abs(fruit.vy)< 0.5){fruit.vy = 0;}}if(fruit.y - radius < 0){fruit.y = radius;fruit.vy = Math.abs(fruit.vy)* 0.5;}}for(let i = 0;i < draftState.fruits.length;i++){const fruit = draftState.fruits[i];if(!fruit || !fruit.isActive || fruit.isMerging)continue;const fruitData = FRUIT_TYPES[fruit.typeId];if(!fruitData)continue;const radius = fruitData.size / 2;for(let j = i + 1;j < draftState.fruits.length;j++){const otherFruit = draftState.fruits[j];if(!otherFruit || !otherFruit.isActive || otherFruit.isMerging)continue;const otherFruitData = FRUIT_TYPES[otherFruit.typeId];if(!otherFruitData)continue;const otherRadius = otherFruitData.size / 2;const dx = otherFruit.x - fruit.x;const dy = otherFruit.y - fruit.y;const distance = Math.sqrt(dx * dx + dy * dy);const minDistance = radius + otherRadius;if(distance < minDistance && distance > 0){const overlap = minDistance - distance;const angle = Math.atan2(dy,dx);const separationX = Math.cos(angle)* overlap * 0.5;const separationY = Math.sin(angle)* overlap * 0.5;fruit.x -= separationX;fruit.y -= separationY;otherFruit.x += separationX;otherFruit.y += separationY;const relativeVx = otherFruit.vx - fruit.vx;const relativeVy = otherFruit.vy - fruit.vy;const dotProduct = relativeVx * Math.cos(angle)+ relativeVy * Math.sin(angle);if(dotProduct < 0){const impulse = dotProduct * 0.8;fruit.vx += Math.cos(angle)* impulse;fruit.vy += Math.sin(angle)* impulse;otherFruit.vx -= Math.cos(angle)* impulse;otherFruit.vy -= Math.sin(angle)* impulse;}fruit.x = Math.max(radius,Math.min(PLAY_AREA_WIDTH - radius,fruit.x));fruit.y = Math.max(radius,Math.min(PLAY_AREA_HEIGHT - radius,fruit.y));otherFruit.x = Math.max(otherRadius,Math.min(PLAY_AREA_WIDTH - otherRadius,otherFruit.x));otherFruit.y = Math.max(otherRadius,Math.min(PLAY_AREA_HEIGHT - otherRadius,otherFruit.y));}}}});get().checkMerges({enableSounds:true,enableHaptics:true});},checkMerges:settings =>{const state = get();const{MERGE_DISTANCE}= FRUIT_MERGER_GAME_CONFIG;for(let i = 0;i < state.fruits.length;i++){const fruit1 = state.fruits[i];if(!fruit1 || !fruit1.isActive || fruit1.isMerging || fruit1.y < 0)continue;for(let j = i + 1;j < state.fruits.length;j++){const fruit2 = state.fruits[j];if(!fruit2 || !fruit2.isActive || fruit2.isMerging || fruit2.y < 0)continue;if(fruit1.typeId === fruit2.typeId){const dx = fruit2.x - fruit1.x;const dy = fruit2.y - fruit1.y;const distance = Math.sqrt(dx * dx + dy * dy);const fruit1Data = FRUIT_TYPES[fruit1.typeId];const fruit2Data = FRUIT_TYPES[fruit2.typeId];if(!fruit1Data || !fruit2Data)continue;const radius1 = fruit1Data.size / 2;const radius2 = fruit2Data.size / 2;const touchDistance = radius1 + radius2;if(distance <= touchDistance + MERGE_DISTANCE){const fruit1Speed = Math.sqrt(fruit1.vx * fruit1.vx + fruit1.vy * fruit1.vy);const fruit2Speed = Math.sqrt(fruit2.vx * fruit2.vx + fruit2.vy * fruit2.vy);if(fruit1Speed < 5 || fruit2Speed < 5){get().mergeFruits(fruit1,fruit2,settings);return;}}}}}const maxFruitReached = state.fruits.some(f => f.typeId === FRUIT_TYPES.length - 1 && f.isActive);if(maxFruitReached){playSound(GAME_SOUNDS.FRUIT_MERGER.COMPLETE,settings.enableSounds);playHaptic(HapticType.SUCCESS,settings.enableHaptics);get().stopGame();}},mergeFruits:(fruit1,fruit2,settings)=>{const nextTypeId = fruit1.typeId + 1;if(nextTypeId >= FRUIT_TYPES.length)return;const mergeX =(fruit1.x + fruit2.x)/ 2;const mergeY =(fruit1.y + fruit2.y)/ 2;set(state =>{state.fruits = state.fruits.filter(f => f.id !== fruit1.id && f.id !== fruit2.id);const newFruit ={id:`fruit-${Date.now()}-${Math.random()}`,typeId:nextTypeId,x:mergeX,y:mergeY,vx:0,vy:-2,isActive:true,isMerging:false};state.fruits.push(newFruit);const nextFruitType = FRUIT_TYPES[nextTypeId];if(nextFruitType){state.score += nextFruitType.score;}});playSound(GAME_SOUNDS.FRUIT_MERGER.MERGE,settings.enableSounds);playHaptic(HapticType.MEDIUM,settings.enableHaptics);},incrementTime:()=>{set(state =>{state.time += 1;});}}))));export const useIsPlaying =()=> useFruitMergerStore(state => state.isPlaying);export const useIsGameOver =()=> useFruitMergerStore(state => state.isGameOver);export const useFruits =()=> useFruitMergerStore(state => state.fruits);export const useCurrentFruit =()=> useFruitMergerStore(state => state.currentFruit);export const useNextFruitType =()=> useFruitMergerStore(state => state.nextFruitType);export const useScore =()=> useFruitMergerStore(state => state.score);export const useTime =()=> useFruitMergerStore(state => state.time);
@@ -1,102 +1 @@
1
- "use strict";
2
-
3
- import React from 'react';
4
- import { Text, StyleSheet } from 'react-native';
5
- import Animated, { useAnimatedStyle, useSharedValue, runOnJS } from 'react-native-reanimated';
6
- import { Gesture, GestureDetector } from 'react-native-gesture-handler';
7
- import { FRUIT_TYPES, FRUIT_MERGER_GAME_CONFIG } from "../FruitMergerConstants.js";
8
- import { jsx as _jsx } from "react/jsx-runtime";
9
- export const FruitItem = /*#__PURE__*/React.memo(({
10
- fruit,
11
- onDrag,
12
- isDraggable
13
- }) => {
14
- const fruitData = FRUIT_TYPES[fruit.typeId];
15
- if (!fruitData) {
16
- return null;
17
- }
18
- const translateX = useSharedValue(fruit.x - fruitData.size / 2);
19
- const translateY = useSharedValue(fruit.y - fruitData.size / 2);
20
- const startX = useSharedValue(0);
21
- const isDragging = useSharedValue(false);
22
-
23
- // Update position when fruit changes (but not during drag)
24
- // Only update if position actually changed to avoid unnecessary updates
25
- const prevXRef = React.useRef(fruit.x);
26
- const prevYRef = React.useRef(fruit.y);
27
- React.useEffect(() => {
28
- if (!isDragging.value && (prevXRef.current !== fruit.x || prevYRef.current !== fruit.y)) {
29
- translateX.value = fruit.x - fruitData.size / 2;
30
- translateY.value = fruit.y - fruitData.size / 2;
31
- prevXRef.current = fruit.x;
32
- prevYRef.current = fruit.y;
33
- }
34
- }, [fruit.x, fruit.y, fruitData.size, isDragging, translateX, translateY]);
35
- const animatedStyle = useAnimatedStyle(() => ({
36
- transform: [{
37
- translateX: translateX.value
38
- }, {
39
- translateY: translateY.value
40
- }]
41
- }));
42
- const panGesture = Gesture.Pan().enabled(isDraggable).onStart(() => {
43
- 'worklet';
44
-
45
- isDragging.value = true;
46
- startX.value = translateX.value;
47
- }).onUpdate(event => {
48
- 'worklet';
49
-
50
- // Use translationX which is the offset from start position
51
- const newX = startX.value + event.translationX;
52
-
53
- // Clamp position to keep fruit within container boundaries
54
- const radius = fruitData.size / 2;
55
- const minX = 0; // Left edge (translateX is already offset by radius)
56
- const maxX = FRUIT_MERGER_GAME_CONFIG.PLAY_AREA_WIDTH - fruitData.size; // Right edge
57
- const clampedX = Math.max(minX, Math.min(maxX, newX));
58
- translateX.value = clampedX;
59
-
60
- // Calculate actual fruit center position and sync to store
61
- const fruitCenterX = clampedX + radius;
62
- if (onDrag) {
63
- runOnJS(onDrag)(fruitCenterX);
64
- }
65
- }).onEnd(() => {
66
- 'worklet';
67
-
68
- isDragging.value = false;
69
- });
70
- return /*#__PURE__*/_jsx(GestureDetector, {
71
- gesture: panGesture,
72
- children: /*#__PURE__*/_jsx(Animated.View, {
73
- style: [styles.fruit, animatedStyle, {
74
- width: fruitData.size,
75
- height: fruitData.size,
76
- backgroundColor: fruitData.color
77
- }],
78
- children: /*#__PURE__*/_jsx(Text, {
79
- style: [styles.emoji, {
80
- fontSize: fruitData.size * 0.7
81
- }],
82
- children: fruitData.emoji
83
- })
84
- })
85
- });
86
- }, (prevProps, nextProps) => {
87
- // Custom comparison to prevent unnecessary re-renders
88
- return prevProps.fruit.id === nextProps.fruit.id && prevProps.fruit.x === nextProps.fruit.x && prevProps.fruit.y === nextProps.fruit.y && prevProps.fruit.typeId === nextProps.fruit.typeId && prevProps.isDraggable === nextProps.isDraggable;
89
- });
90
- const styles = StyleSheet.create({
91
- fruit: {
92
- position: 'absolute',
93
- borderRadius: 1000,
94
- justifyContent: 'center',
95
- alignItems: 'center'
96
- },
97
- emoji: {
98
- textAlign: 'center'
99
- }
100
- });
101
- FruitItem.displayName = 'FruitItem';
102
- //# sourceMappingURL=FruitItem.js.map
1
+ "use strict";import React from 'react';import{Text,StyleSheet}from 'react-native';import Animated,{useAnimatedStyle,useSharedValue,runOnJS}from 'react-native-reanimated';import{Gesture,GestureDetector}from 'react-native-gesture-handler';import{FRUIT_TYPES,FRUIT_MERGER_GAME_CONFIG}from "../FruitMergerConstants.js";import{jsx as _jsx}from "react/jsx-runtime";export const FruitItem = React.memo(({fruit,onDrag,isDraggable})=>{const fruitData = FRUIT_TYPES[fruit.typeId];if(!fruitData){return null;}const translateX = useSharedValue(fruit.x - fruitData.size / 2);const translateY = useSharedValue(fruit.y - fruitData.size / 2);const startX = useSharedValue(0);const isDragging = useSharedValue(false);const prevXRef = React.useRef(fruit.x);const prevYRef = React.useRef(fruit.y);React.useEffect(()=>{if(!isDragging.value &&(prevXRef.current !== fruit.x || prevYRef.current !== fruit.y)){translateX.value = fruit.x - fruitData.size / 2;translateY.value = fruit.y - fruitData.size / 2;prevXRef.current = fruit.x;prevYRef.current = fruit.y;}},[fruit.x,fruit.y,fruitData.size,isDragging,translateX,translateY]);const animatedStyle = useAnimatedStyle(()=>({transform:[{translateX:translateX.value},{translateY:translateY.value}]}));const panGesture = Gesture.Pan().enabled(isDraggable).onStart(()=>{'worklet';isDragging.value = true;startX.value = translateX.value;}).onUpdate(event =>{'worklet';const newX = startX.value + event.translationX;const radius = fruitData.size / 2;const minX = 0;const maxX = FRUIT_MERGER_GAME_CONFIG.PLAY_AREA_WIDTH - fruitData.size;const clampedX = Math.max(minX,Math.min(maxX,newX));translateX.value = clampedX;const fruitCenterX = clampedX + radius;if(onDrag){runOnJS(onDrag)(fruitCenterX);}}).onEnd(()=>{'worklet';isDragging.value = false;});return _jsx(GestureDetector,{gesture:panGesture,children:_jsx(Animated.View,{style:[styles.fruit,animatedStyle,{width:fruitData.size,height:fruitData.size,backgroundColor:fruitData.color}],children:_jsx(Text,{style:[styles.emoji,{fontSize:fruitData.size * 0.7}],children:fruitData.emoji})})});},(prevProps,nextProps)=>{return prevProps.fruit.id === nextProps.fruit.id && prevProps.fruit.x === nextProps.fruit.x && prevProps.fruit.y === nextProps.fruit.y && prevProps.fruit.typeId === nextProps.fruit.typeId && prevProps.isDraggable === nextProps.isDraggable;});const styles = StyleSheet.create({fruit:{position:'absolute',borderRadius:1000,justifyContent:'center',alignItems:'center'},emoji:{textAlign:'center'}});FruitItem.displayName = 'FruitItem';
@@ -1,103 +1 @@
1
- "use strict";
2
-
3
- import React, { useCallback, useMemo } from 'react';
4
- import { View, StyleSheet, TouchableOpacity } from 'react-native';
5
- import { GestureHandlerRootView } from 'react-native-gesture-handler';
6
- import { useFruits, useCurrentFruit, useNextFruitType, useFruitMergerStore, useIsPlaying } from "../FruitMergerStore.js";
7
- import { FruitItem } from "./FruitItem.js";
8
- import { FRUIT_MERGER_GAME_CONFIG, FRUIT_TYPES } from "../FruitMergerConstants.js";
9
- import { playSound, GAME_SOUNDS } from "../../../services/SoundsService.js";
10
- import { playHaptic, HapticType } from "../../../services/HapticsService.js";
11
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
- export const GameArea = /*#__PURE__*/React.memo(({
13
- settings
14
- }) => {
15
- const fruits = useFruits();
16
- const currentFruit = useCurrentFruit();
17
- const nextFruitType = useNextFruitType();
18
- const isPlaying = useIsPlaying();
19
- const dropCurrentFruit = useFruitMergerStore(state => state.dropCurrentFruit);
20
- const updateCurrentFruitPosition = useFruitMergerStore(state => state.updateCurrentFruitPosition);
21
-
22
- // Memoize next fruit data to prevent recalculation
23
- const nextFruitData = useMemo(() => FRUIT_TYPES[nextFruitType], [nextFruitType]);
24
- if (!nextFruitData) {
25
- return null;
26
- }
27
- const handleTap = useCallback(() => {
28
- if (!isPlaying || !currentFruit) return;
29
- dropCurrentFruit();
30
- playSound(GAME_SOUNDS.FRUIT_MERGER.DROP, settings.enableSounds);
31
- playHaptic(HapticType.LIGHT, settings.enableHaptics);
32
- }, [isPlaying, currentFruit, dropCurrentFruit, settings.enableSounds, settings.enableHaptics]);
33
- const lastUpdateRef = React.useRef(0);
34
- const handleDrag = useCallback(x => {
35
- // Throttle store updates to every 16ms (60fps) to reduce state updates
36
- const now = Date.now();
37
- if (now - lastUpdateRef.current > 16) {
38
- updateCurrentFruitPosition(x);
39
- lastUpdateRef.current = now;
40
- }
41
- }, [updateCurrentFruitPosition]);
42
- return /*#__PURE__*/_jsx(View, {
43
- style: styles.container,
44
- children: /*#__PURE__*/_jsx(GestureHandlerRootView, {
45
- children: /*#__PURE__*/_jsx(TouchableOpacity, {
46
- style: styles.container,
47
- activeOpacity: 1,
48
- onPress: handleTap,
49
- children: /*#__PURE__*/_jsxs(View, {
50
- style: styles.gameContainer,
51
- children: [currentFruit && /*#__PURE__*/_jsx(FruitItem, {
52
- fruit: currentFruit,
53
- onDrag: handleDrag,
54
- isDraggable: true
55
- }, currentFruit.id), fruits.map(fruit => /*#__PURE__*/_jsx(FruitItem, {
56
- fruit: fruit,
57
- isDraggable: false
58
- }, fruit.id))]
59
- })
60
- })
61
- })
62
- });
63
- });
64
- const styles = StyleSheet.create({
65
- container: {
66
- flex: 1,
67
- justifyContent: 'center',
68
- alignItems: 'center'
69
- },
70
- gameContainer: {
71
- width: FRUIT_MERGER_GAME_CONFIG.CONTAINER_WIDTH,
72
- height: FRUIT_MERGER_GAME_CONFIG.CONTAINER_HEIGHT,
73
- backgroundColor: 'rgba(255, 248, 231, 0.65)',
74
- borderRadius: 15,
75
- borderWidth: 5,
76
- borderColor: '#8B4513',
77
- overflow: 'hidden',
78
- position: 'relative'
79
- },
80
- nextFruitPreview: {
81
- position: 'absolute',
82
- top: -80,
83
- alignItems: 'center'
84
- },
85
- previewLabel: {
86
- fontSize: 12,
87
- fontWeight: '700',
88
- color: '#4CAF50',
89
- marginBottom: 6
90
- },
91
- previewFruit: {
92
- borderRadius: 1000,
93
- justifyContent: 'center',
94
- alignItems: 'center',
95
- borderWidth: 2,
96
- borderColor: '#4CAF50'
97
- },
98
- emoji: {
99
- textAlign: 'center'
100
- }
101
- });
102
- GameArea.displayName = 'GameArea';
103
- //# sourceMappingURL=GameArea.js.map
1
+ "use strict";import React,{useCallback,useMemo}from 'react';import{View,StyleSheet,TouchableOpacity}from 'react-native';import{GestureHandlerRootView}from 'react-native-gesture-handler';import{useFruits,useCurrentFruit,useNextFruitType,useFruitMergerStore,useIsPlaying}from "../FruitMergerStore.js";import{FruitItem}from "./FruitItem.js";import{FRUIT_MERGER_GAME_CONFIG,FRUIT_TYPES}from "../FruitMergerConstants.js";import{playSound,GAME_SOUNDS}from "../../../services/SoundsService.js";import{playHaptic,HapticType}from "../../../services/HapticsService.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";export const GameArea = React.memo(({settings})=>{const fruits = useFruits();const currentFruit = useCurrentFruit();const nextFruitType = useNextFruitType();const isPlaying = useIsPlaying();const dropCurrentFruit = useFruitMergerStore(state => state.dropCurrentFruit);const updateCurrentFruitPosition = useFruitMergerStore(state => state.updateCurrentFruitPosition);const nextFruitData = useMemo(()=> FRUIT_TYPES[nextFruitType],[nextFruitType]);if(!nextFruitData){return null;}const handleTap = useCallback(()=>{if(!isPlaying || !currentFruit)return;dropCurrentFruit();playSound(GAME_SOUNDS.FRUIT_MERGER.DROP,settings.enableSounds);playHaptic(HapticType.LIGHT,settings.enableHaptics);},[isPlaying,currentFruit,dropCurrentFruit,settings.enableSounds,settings.enableHaptics]);const lastUpdateRef = React.useRef(0);const handleDrag = useCallback(x =>{const now = Date.now();if(now - lastUpdateRef.current > 16){updateCurrentFruitPosition(x);lastUpdateRef.current = now;}},[updateCurrentFruitPosition]);return _jsx(View,{style:styles.container,children:_jsx(GestureHandlerRootView,{children:_jsx(TouchableOpacity,{style:styles.container,activeOpacity:1,onPress:handleTap,children:_jsxs(View,{style:styles.gameContainer,children:[currentFruit && _jsx(FruitItem,{fruit:currentFruit,onDrag:handleDrag,isDraggable:true},currentFruit.id),fruits.map(fruit => _jsx(FruitItem,{fruit:fruit,isDraggable:false},fruit.id))]})})})});});const styles = StyleSheet.create({container:{flex:1,justifyContent:'center',alignItems:'center'},gameContainer:{width:FRUIT_MERGER_GAME_CONFIG.CONTAINER_WIDTH,height:FRUIT_MERGER_GAME_CONFIG.CONTAINER_HEIGHT,backgroundColor:'rgba(255,248,231,0.65)',borderRadius:15,borderWidth:5,borderColor:'#8B4513',overflow:'hidden',position:'relative'},nextFruitPreview:{position:'absolute',top:-80,alignItems:'center'},previewLabel:{fontSize:12,fontWeight:'700',color:'#4CAF50',marginBottom:6},previewFruit:{borderRadius:1000,justifyContent:'center',alignItems:'center',borderWidth:2,borderColor:'#4CAF50'},emoji:{textAlign:'center'}});GameArea.displayName = 'GameArea';