react-native-games 1.3.0 → 1.5.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 (195) hide show
  1. package/lib/module/games/balloon-blaster/BalloonBlaster.js +1 -1
  2. package/lib/module/games/balloon-blaster/BalloonBlasterConstants.js +1 -1
  3. package/lib/module/games/balloon-blaster/BalloonBlasterService.js +1 -1
  4. package/lib/module/games/balloon-blaster/BalloonBlasterStore.js +1 -1
  5. package/lib/module/games/balloon-blaster/components/BalloonComponent.js +1 -1
  6. package/lib/module/games/balloon-blaster/components/GameArea.js +1 -1
  7. package/lib/module/games/balloon-blaster/components/GameBackground.js +1 -1
  8. package/lib/module/games/balloon-blaster/components/ScoreBoard.js +1 -1
  9. package/lib/module/games/balloon-blaster/components/index.js +1 -1
  10. package/lib/module/games/bike-racing/BikeRacing.js +1 -1
  11. package/lib/module/games/bike-racing/BikeRacingConstants.js +1 -1
  12. package/lib/module/games/bike-racing/BikeRacingService.js +1 -1
  13. package/lib/module/games/bike-racing/BikeRacingStore.js +1 -1
  14. package/lib/module/games/bike-racing/components/BikeComponent.js +1 -1
  15. package/lib/module/games/bike-racing/components/GameBackground.js +1 -1
  16. package/lib/module/games/bike-racing/components/ScoreBoard.js +1 -1
  17. package/lib/module/games/bike-racing/components/index.js +1 -1
  18. package/lib/module/games/bike-racing/index.js +1 -1
  19. package/lib/module/games/block-blast/BlockBlast.js +1 -1
  20. package/lib/module/games/block-blast/BlockBlastConstants.js +1 -1
  21. package/lib/module/games/block-blast/BlockBlastService.js +1 -1
  22. package/lib/module/games/block-blast/BlockBlastStore.js +1 -1
  23. package/lib/module/games/block-blast/components/BlockPieceComponent.js +1 -1
  24. package/lib/module/games/block-blast/components/GameArea.js +1 -1
  25. package/lib/module/games/block-blast/components/GameBackground.js +1 -1
  26. package/lib/module/games/block-blast/components/GridComponent.js +1 -1
  27. package/lib/module/games/block-blast/components/ScoreBoard.js +1 -1
  28. package/lib/module/games/block-blast/components/index.js +1 -1
  29. package/lib/module/games/block-blast/index.js +1 -1
  30. package/lib/module/games/bubble-shooter/BubbleShooter.js +1 -1
  31. package/lib/module/games/bubble-shooter/BubbleShooterConstants.js +1 -1
  32. package/lib/module/games/bubble-shooter/BubbleShooterService.js +1 -1
  33. package/lib/module/games/bubble-shooter/BubbleShooterStore.js +1 -1
  34. package/lib/module/games/bubble-shooter/components/GameArea.js +1 -1
  35. package/lib/module/games/bubble-shooter/components/GameBackground.js +1 -1
  36. package/lib/module/games/bubble-shooter/components/ScoreBoard.js +1 -1
  37. package/lib/module/games/bubble-shooter/components/index.js +1 -1
  38. package/lib/module/games/bubble-shooter/index.js +1 -1
  39. package/lib/module/games/candy-crush/CandyCrush.js +1 -1
  40. package/lib/module/games/candy-crush/CandyCrushConstants.js +1 -1
  41. package/lib/module/games/candy-crush/CandyCrushService.js +1 -1
  42. package/lib/module/games/candy-crush/CandyCrushStore.js +1 -1
  43. package/lib/module/games/candy-crush/components/CandyItem.js +1 -1
  44. package/lib/module/games/candy-crush/components/GameBackground.js +1 -1
  45. package/lib/module/games/candy-crush/components/GameGrid.js +1 -1
  46. package/lib/module/games/candy-crush/components/ScoreBoard.js +1 -1
  47. package/lib/module/games/candy-crush/components/index.js +1 -1
  48. package/lib/module/games/candy-crush/index.js +1 -1
  49. package/lib/module/games/car-racing/CarRacing.js +1 -1
  50. package/lib/module/games/car-racing/CarRacingConstants.js +1 -1
  51. package/lib/module/games/car-racing/CarRacingService.js +1 -1
  52. package/lib/module/games/car-racing/CarRacingStore.js +1 -1
  53. package/lib/module/games/car-racing/components/CarComponent.js +1 -1
  54. package/lib/module/games/car-racing/components/GameBackground.js +1 -1
  55. package/lib/module/games/car-racing/components/ScoreBoard.js +1 -1
  56. package/lib/module/games/car-racing/components/index.js +1 -1
  57. package/lib/module/games/colors-sort/ColorsSort.js +1 -1
  58. package/lib/module/games/colors-sort/ColorsSortConstants.js +1 -1
  59. package/lib/module/games/colors-sort/ColorsSortService.js +1 -1
  60. package/lib/module/games/colors-sort/ColorsSortStore.js +1 -1
  61. package/lib/module/games/colors-sort/components/ColorContainer.js +1 -1
  62. package/lib/module/games/colors-sort/components/GameBackground.js +1 -1
  63. package/lib/module/games/colors-sort/components/ScoreBoard.js +1 -1
  64. package/lib/module/games/colors-sort/components/index.js +1 -1
  65. package/lib/module/games/dino-jump/DinoJump.js +1 -1
  66. package/lib/module/games/dino-jump/DinoJumpConstants.js +1 -1
  67. package/lib/module/games/dino-jump/DinoJumpService.js +1 -1
  68. package/lib/module/games/dino-jump/DinoJumpStore.js +1 -1
  69. package/lib/module/games/dino-jump/components/DinoSprite.js +1 -1
  70. package/lib/module/games/dino-jump/components/GameArea.js +1 -1
  71. package/lib/module/games/dino-jump/components/GameBackground.js +1 -1
  72. package/lib/module/games/dino-jump/components/ObstacleSprite.js +1 -1
  73. package/lib/module/games/dino-jump/components/ScoreBoard.js +1 -1
  74. package/lib/module/games/dino-jump/components/StarSprite.js +1 -1
  75. package/lib/module/games/dino-jump/components/index.js +1 -1
  76. package/lib/module/games/flappy-bird/FlappyBird.js +1 -1
  77. package/lib/module/games/flappy-bird/FlappyBirdConstants.js +1 -1
  78. package/lib/module/games/flappy-bird/FlappyBirdStore.js +1 -1
  79. package/lib/module/games/flappy-bird/components/Bird.js +1 -1
  80. package/lib/module/games/flappy-bird/components/GameArea.js +1 -1
  81. package/lib/module/games/flappy-bird/components/GameBackground.js +1 -1
  82. package/lib/module/games/flappy-bird/components/Pipes.js +1 -1
  83. package/lib/module/games/flappy-bird/components/ScoreBoard.js +1 -1
  84. package/lib/module/games/flappy-bird/components/index.js +1 -1
  85. package/lib/module/games/fruit-merger/FruitMerger.js +1 -1
  86. package/lib/module/games/fruit-merger/FruitMergerConstants.js +1 -1
  87. package/lib/module/games/fruit-merger/FruitMergerService.js +1 -1
  88. package/lib/module/games/fruit-merger/FruitMergerStore.js +1 -1
  89. package/lib/module/games/fruit-merger/components/FruitItem.js +1 -1
  90. package/lib/module/games/fruit-merger/components/GameArea.js +1 -1
  91. package/lib/module/games/fruit-merger/components/GameBackground.js +1 -1
  92. package/lib/module/games/fruit-merger/components/ScoreBoard.js +1 -1
  93. package/lib/module/games/fruit-merger/components/index.js +1 -1
  94. package/lib/module/games/fruit-ninja/FruitNinja.js +1 -1
  95. package/lib/module/games/fruit-ninja/FruitNinjaConstants.js +1 -1
  96. package/lib/module/games/fruit-ninja/FruitNinjaService.js +1 -1
  97. package/lib/module/games/fruit-ninja/FruitNinjaStore.js +1 -1
  98. package/lib/module/games/fruit-ninja/components/FruitComponent.js +1 -1
  99. package/lib/module/games/fruit-ninja/components/GameArea.js +1 -1
  100. package/lib/module/games/fruit-ninja/components/GameBackground.js +1 -1
  101. package/lib/module/games/fruit-ninja/components/ScoreBoard.js +1 -1
  102. package/lib/module/games/fruit-ninja/components/index.js +1 -1
  103. package/lib/module/games/game-2048/Game2048.js +1 -1
  104. package/lib/module/games/game-2048/Game2048Constants.js +1 -1
  105. package/lib/module/games/game-2048/Game2048Service.js +1 -1
  106. package/lib/module/games/game-2048/Game2048Store.js +1 -1
  107. package/lib/module/games/game-2048/components/GameBackground.js +1 -1
  108. package/lib/module/games/game-2048/components/GameGrid.js +1 -1
  109. package/lib/module/games/game-2048/components/GameTile.js +1 -1
  110. package/lib/module/games/game-2048/components/ScoreBoard.js +1 -1
  111. package/lib/module/games/game-2048/components/index.js +1 -1
  112. package/lib/module/games/maze-runner/MazeRunner.js +1 -1
  113. package/lib/module/games/maze-runner/MazeRunnerConstants.js +1 -1
  114. package/lib/module/games/maze-runner/MazeRunnerService.js +1 -1
  115. package/lib/module/games/maze-runner/components/EnhancedBallComponent.js +1 -1
  116. package/lib/module/games/maze-runner/components/EnhancedGameArea.js +1 -1
  117. package/lib/module/games/maze-runner/components/GameBackground.js +1 -1
  118. package/lib/module/games/maze-runner/components/ScoreBoard.js +1 -1
  119. package/lib/module/games/maze-runner/components/SkiaPipeComponent.js +1 -1
  120. package/lib/module/games/maze-runner/components/StaticGameBackground.js +1 -1
  121. package/lib/module/games/maze-runner/components/WallComponent.js +1 -1
  122. package/lib/module/games/maze-runner/components/index.js +1 -1
  123. package/lib/module/games/perfect-circle/PerfectCircle.js +1 -1
  124. package/lib/module/games/perfect-circle/PerfectCircleConstants.js +1 -1
  125. package/lib/module/games/perfect-circle/PerfectCircleService.js +1 -1
  126. package/lib/module/games/perfect-circle/PerfectCircleStore.js +1 -1
  127. package/lib/module/games/perfect-circle/components/DrawingCanvas.js +1 -1
  128. package/lib/module/games/perfect-circle/components/GameBackground.js +1 -1
  129. package/lib/module/games/perfect-circle/components/ScoreBoard.js +1 -1
  130. package/lib/module/games/perfect-circle/index.js +1 -1
  131. package/lib/module/games/popit-fidget/PopitFidget.js +1 -1
  132. package/lib/module/games/popit-fidget/PopitFidgetConstants.js +1 -1
  133. package/lib/module/games/popit-fidget/PopitFidgetService.js +1 -1
  134. package/lib/module/games/popit-fidget/PopitFidgetStore.js +1 -1
  135. package/lib/module/games/popit-fidget/components/BubbleComponent.js +1 -1
  136. package/lib/module/games/popit-fidget/components/FidgetGrid.js +1 -1
  137. package/lib/module/games/popit-fidget/components/GameBackground.js +1 -1
  138. package/lib/module/games/popit-fidget/components/ScoreBoard.js +1 -1
  139. package/lib/module/games/popit-fidget/components/index.js +1 -1
  140. package/lib/module/games/sliding-numbers/SlidingNumbers.js +1 -1
  141. package/lib/module/games/sliding-numbers/SlidingNumbersConstants.js +1 -1
  142. package/lib/module/games/sliding-numbers/SlidingNumbersService.js +1 -1
  143. package/lib/module/games/sliding-numbers/SlidingNumbersStore.js +1 -1
  144. package/lib/module/games/sliding-numbers/components/GameBackground.js +1 -1
  145. package/lib/module/games/sliding-numbers/components/NumbersGrid.js +1 -1
  146. package/lib/module/games/sliding-numbers/components/NumbersTile.js +1 -1
  147. package/lib/module/games/sliding-numbers/components/ScoreBoard.js +1 -1
  148. package/lib/module/games/sliding-numbers/components/index.js +1 -1
  149. package/lib/module/games/snake/Snake.js +1 -1
  150. package/lib/module/games/snake/SnakeConstants.js +1 -1
  151. package/lib/module/games/snake/SnakeService.js +1 -1
  152. package/lib/module/games/snake/SnakeStore.js +1 -1
  153. package/lib/module/games/snake/components/GameBackground.js +1 -1
  154. package/lib/module/games/snake/components/GameGrid.js +1 -1
  155. package/lib/module/games/snake/components/ScoreBoard.js +1 -1
  156. package/lib/module/games/snake/components/index.js +1 -1
  157. package/lib/module/games/snake/index.js +1 -1
  158. package/lib/module/games/space-fighter/SpaceFighter.js +1 -1
  159. package/lib/module/games/space-fighter/SpaceFighterConstants.js +1 -1
  160. package/lib/module/games/space-fighter/SpaceFighterService.js +1 -1
  161. package/lib/module/games/space-fighter/SpaceFighterStore.js +1 -1
  162. package/lib/module/games/space-fighter/components/AsteroidComponent.js +1 -1
  163. package/lib/module/games/space-fighter/components/GameArea.js +1 -1
  164. package/lib/module/games/space-fighter/components/GameBackground.js +1 -1
  165. package/lib/module/games/space-fighter/components/ScoreBoard.js +1 -1
  166. package/lib/module/games/space-fighter/components/Spacecraft3D.js +1 -1
  167. package/lib/module/games/space-fighter/components/SpacecraftPath.js +1 -1
  168. package/lib/module/games/space-fighter/components/index.js +1 -1
  169. package/lib/module/games/whack-a-mole/WhackAMole.js +1 -1
  170. package/lib/module/games/whack-a-mole/WhackAMoleConstants.js +1 -1
  171. package/lib/module/games/whack-a-mole/WhackAMoleService.js +1 -1
  172. package/lib/module/games/whack-a-mole/WhackAMoleStore.js +1 -1
  173. package/lib/module/games/whack-a-mole/components/GameBackground.js +1 -1
  174. package/lib/module/games/whack-a-mole/components/GameGrid.js +1 -1
  175. package/lib/module/games/whack-a-mole/components/GameHole.js +1 -1
  176. package/lib/module/games/whack-a-mole/components/MoleCharacter.js +1 -1
  177. package/lib/module/games/whack-a-mole/components/ScoreBoard.js +1 -1
  178. package/lib/module/games/whack-a-mole/components/index.js +1 -1
  179. package/lib/module/helpers/AnimationFrame.js +1 -1
  180. package/lib/module/helpers/AnimationTracker.js +1 -1
  181. package/lib/module/helpers/ErrorHandler.js +1 -1
  182. package/lib/module/helpers/GameControlButton.js +1 -1
  183. package/lib/module/helpers/GameOverModal.js +1 -1
  184. package/lib/module/helpers/GameSettingsModal.js +1 -1
  185. package/lib/module/helpers/ParticleBlast.js +1 -1
  186. package/lib/module/helpers/ScoreBoardContainer.js +1 -1
  187. package/lib/module/helpers/index.js +1 -1
  188. package/lib/module/index.js +1 -1
  189. package/lib/module/services/GamesConstants.js +1 -1
  190. package/lib/module/services/GamesService.js +1 -1
  191. package/lib/module/services/HapticsService.js +1 -1
  192. package/lib/module/services/ScoringService.js +1 -1
  193. package/lib/module/services/SoundsService.js +1 -1
  194. package/lib/module/services/UtilsService.js +1 -1
  195. package/package.json +5 -2
@@ -1 +1 @@
1
- "use strict";export const CANDY_CRUSH_GAME_CONFIG ={GRID_SIZE:8,CANDY_TYPES:6,MIN_MATCH:3,ANIMATION_DURATION:300,FALL_DURATION:400,SWAP_DURATION:200,POINTS_PER_CANDY:10,COMBO_MULTIPLIER:1.5,SPECIAL_CANDY_THRESHOLD:4};export const CANDY_COLORS = ['#FF3B30','#34C759','#007AFF','#FFCC00','#9D4EDD','#FF6B9D' ];export const CANDY_TYPES ={NORMAL:'normal',STRIPED_HORIZONTAL:'striped_h',STRIPED_VERTICAL:'striped_v',WRAPPED:'wrapped',COLOR_BOMB:'color_bomb'};export const CANDY_CRUSH_COLORS ={BACKGROUND:'#2C3E50',GRID_BACKGROUND:'rgba(255,149,0,0.1)',GRID_BORDER:'rgba(255,149,0,0.3)',SELECTED:'rgba(255,149,0,0.5)',BUTTON_PRIMARY:'#FF9500',BUTTON_SECONDARY:'#E68600',SCORE_BACKGROUND:'rgba(255,149,0,0.4)',SCORE_TEXT:'#FFFFFF',TIME_GOOD:'#FF9500',TIME_WARNING:'#FF9500',TIME_CRITICAL:'#FF9500',COMBO_TEXT:'#FF9500',MODAL_PRIMARY:'rgba(255,149,0,0.95)',MODAL_BORDER:'rgba(230,134,0,0.9)',MODAL_BUTTON:'#FF9500',MODAL_BUTTON_BORDER:'#E68600'};export const DIFFICULTY_CONFIG ={easy:{gameDuration:60,candyTypes:4},medium:{gameDuration:180,candyTypes:5},hard:{gameDuration:300,candyTypes:6}};export const CANDY_CRUSH_SOUNDS ={MATCH:{text:'Pop!',pitch:1.2,rate:1.5},SWAP:{text:'Swap',pitch:1.0,rate:1.8},SPECIAL:{text:'Boom!',pitch:1.5,rate:2.0},COMBO:{text:'Combo!',pitch:1.8,rate:2.2},WIN:{text:'Victory!',pitch:1.6,rate:1.8},LOSE:{text:'Game Over',pitch:0.8,rate:1.2}};export const CANDY_CRUSH_THEME ={backgroundColor:'rgba(0,0,0,0.7)',headerBackgroundColor:'#FF9500',headerTextColor:'#ffffff',sectionBackgroundColor:'rgba(255,149,0,0.15)',sectionTitleColor:'#FF9500',buttonSelectedColor:'#FF9500',buttonUnselectedColor:'rgba(255,255,255,0.2)',buttonSelectedTextColor:'#ffffff',buttonUnselectedTextColor:'rgba(255,255,255,0.7)',switchTrackColorFalse:'rgba(255,149,0,0.3)',switchTrackColorTrue:'#FF9500',switchThumbColor:'#ffffff',infoTextColor:'rgba(255,255,255,0.9)'};export const CANDY_CRUSH_DIFFICULTY_DESCRIPTIONS ={easy:'1 minute 4 candy types',medium:'3 minutes 5 candy types',hard:'5 minutes 6 candy types'};
1
+ "use strict";export const CANDY_CRUSH_GAME_CONFIG={GRID_SIZE:8,CANDY_TYPES:6,MIN_MATCH:3,ANIMATION_DURATION:300,FALL_DURATION:400,SWAP_DURATION:200,POINTS_PER_CANDY:10,COMBO_MULTIPLIER:1.5,SPECIAL_CANDY_THRESHOLD:4};export const CANDY_COLORS=["#FF3B30","#34C759","#007AFF","#FFCC00","#9D4EDD","#FF6B9D"];export const CANDY_TYPES={NORMAL:"normal",STRIPED_HORIZONTAL:"striped_h",STRIPED_VERTICAL:"striped_v",WRAPPED:"wrapped",COLOR_BOMB:"color_bomb"};export const CANDY_CRUSH_COLORS={BACKGROUND:"#2C3E50",GRID_BACKGROUND:"rgba(255, 149, 0, 0.1)",GRID_BORDER:"rgba(255, 149, 0, 0.3)",SELECTED:"rgba(255, 149, 0, 0.5)",BUTTON_PRIMARY:"#FF9500",BUTTON_SECONDARY:"#E68600",SCORE_BACKGROUND:"rgba(255, 149, 0, 0.4)",SCORE_TEXT:"#FFFFFF",TIME_GOOD:"#FF9500",TIME_WARNING:"#FF9500",TIME_CRITICAL:"#FF9500",COMBO_TEXT:"#FF9500",MODAL_PRIMARY:"rgba(255, 149, 0, 0.95)",MODAL_BORDER:"rgba(230, 134, 0, 0.9)",MODAL_BUTTON:"#FF9500",MODAL_BUTTON_BORDER:"#E68600"};export const DIFFICULTY_CONFIG={easy:{gameDuration:60,candyTypes:4},medium:{gameDuration:180,candyTypes:5},hard:{gameDuration:300,candyTypes:6}};export const CANDY_CRUSH_SOUNDS={MATCH:{text:"Pop!",pitch:1.2,rate:1.5},SWAP:{text:"Swap",pitch:1,rate:1.8},SPECIAL:{text:"Boom!",pitch:1.5,rate:2},COMBO:{text:"Combo!",pitch:1.8,rate:2.2},WIN:{text:"Victory!",pitch:1.6,rate:1.8},LOSE:{text:"Game Over",pitch:.8,rate:1.2}};export const CANDY_CRUSH_THEME={backgroundColor:"rgba(0, 0, 0, 0.7)",headerBackgroundColor:"#FF9500",headerTextColor:"#ffffff",sectionBackgroundColor:"rgba(255, 149, 0, 0.15)",sectionTitleColor:"#FF9500",buttonSelectedColor:"#FF9500",buttonUnselectedColor:"rgba(255, 255, 255, 0.2)",buttonSelectedTextColor:"#ffffff",buttonUnselectedTextColor:"rgba(255, 255, 255, 0.7)",switchTrackColorFalse:"rgba(255, 149, 0, 0.3)",switchTrackColorTrue:"#FF9500",switchThumbColor:"#ffffff",infoTextColor:"rgba(255, 255, 255, 0.9)"};export const CANDY_CRUSH_DIFFICULTY_DESCRIPTIONS={easy:"1 minute \u2022 4 candy types",medium:"3 minutes \u2022 5 candy types",hard:"5 minutes \u2022 6 candy types"};
@@ -1 +1 @@
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
+ "use strict";import{Animated as t}from"react-native";import{CANDY_CRUSH_GAME_CONFIG as e,CANDY_COLORS as n,CANDY_TYPES as o}from"./CandyCrushConstants.js";export class CandyCrushService{nextCandyId=1;createGrid(){return Array(e.GRID_SIZE).fill(null).map(()=>Array(e.GRID_SIZE).fill(null))}initializeGrid(n){const r=this.createGrid(),s=e.GRID_SIZE;for(let e=0;s>e;e++)for(let l=0;s>l;l++){let s,i=0;do{s=Math.floor(Math.random()*n),i++}while(10>i&&this.wouldCreateMatch(r,e,l,s));const c={id:this.nextCandyId++,row:e,col:l,type:s,specialType:o.NORMAL,animatedValue:new t.Value(1),scaleValue:new t.Value(1),isMatched:!1,isFalling:!1},a=r[e];a&&(a[l]=c)}return r}wouldCreateMatch(t,n,o,r){let s=1;for(let e=o-1;e>=0;e--){const o=t[n],l=o?o[e]:null;if(!l||l.type!==r)break;s++}for(let l=o+1;l<e.GRID_SIZE;l++){const e=t[n],o=e?e[l]:null;if(!o||o.type!==r)break;s++}if(s>=e.MIN_MATCH)return!0;let l=1;for(let e=n-1;e>=0;e--){const n=t[e],s=n?n[o]:null;if(!s||s.type!==r)break;l++}for(let s=n+1;s<e.GRID_SIZE;s++){const e=t[s],n=e?e[o]:null;if(!n||n.type!==r)break;l++}return l>=e.MIN_MATCH}canSwap(t,e){const n=Math.abs(t.row-e.row),o=Math.abs(t.col-e.col);return 1===n&&0===o||0===n&&1===o}swapCandies(t,e,n){const o=e.row,r=e.col,s=n.row,l=n.col,i=t[o],c=t[s];if(i&&c){const t=i[r],e=c[l];i[r]=e||null,c[l]=t||null,t&&(t.row=s,t.col=l),e&&(e.row=o,e.col=r)}}findMatches(t){const n=[],o=new Set,r=e.GRID_SIZE;for(let e=0;r>e;e++)for(let s=0;r-2>s;s++){const l=t[e];if(!l)continue;const i=l[s],c=l[s+1],a=l[s+2];if(i&&c&&a&&i.type===c.type&&c.type===a.type){let t=3;const e=[i,c,a];for(let n=s+3;r>n;n++){const o=l[n];if(!o||o.type!==i.type)break;t++,e.push(o)}e.forEach(t=>{o.has(t.id)||(o.add(t.id),n.push(t))}),s+=t-1}}for(let e=0;r>e;e++)for(let s=0;r-2>s;s++){const l=t[s],i=t[s+1],c=t[s+2];if(!l||!i||!c)continue;const a=l[e],f=i[e],u=c[e];if(a&&f&&u&&a.type===f.type&&f.type===u.type){let l=3;const i=[a,f,u];for(let n=s+3;r>n;n++){const o=t[n],r=o?o[e]:null;if(!r||r.type!==a.type)break;l++,i.push(r)}i.forEach(t=>{o.has(t.id)||(o.add(t.id),n.push(t))}),s+=l-1}}const s=n.length*e.POINTS_PER_CANDY;return{matches:n,score:s,hasMatches:n.length>0}}removeMatches(t,e){e.forEach(e=>{const n=t[e.row];n&&(n[e.col]=null)})}applyGravity(t){let n=!1;const o=e.GRID_SIZE;for(let e=0;o>e;e++)for(let r=o-1;r>=0;r--){const s=t[r];if(!s)continue;const l=s[e];if(l){let i=r;for(let n=r+1;o>n;n++){const o=t[n];if(!o||o[e])break;i=n}if(i!==r){const o=t[i];o&&(o[e]=l,s[e]=null,l.row=i,l.isFalling=!0,n=!0)}}}return n}fillEmptySpaces(n,r){const s=[],l=e.GRID_SIZE;for(let e=0;l>e;e++){let i=0;for(let t=0;l>t;t++){const o=n[t];o&&!o[e]&&i++}for(let l=0;i>l;l++){const i=l,c={id:this.nextCandyId++,row:i,col:e,type:Math.floor(Math.random()*r),specialType:o.NORMAL,animatedValue:new t.Value(0),scaleValue:new t.Value(1),isMatched:!1,isFalling:!0},a=n[i];a&&(a[e]=c,s.push(c))}}return s}hasPossibleMoves(t){const n=e.GRID_SIZE;for(let e=0;n>e;e++)for(let o=0;n>o;o++){const r=t[e];if(!r)continue;const s=r[o];if(s){if(n-1>o){const e=r[o+1];if(e){this.swapCandies(t,s,e);const n=this.findMatches(t);if(this.swapCandies(t,s,e),n.hasMatches)return!0}}if(n-1>e){const n=t[e+1],r=n?n[o]:null;if(r){this.swapCandies(t,s,r);const e=this.findMatches(t);if(this.swapCandies(t,s,r),e.hasMatches)return!0}}}}return!1}getCandyColor(t){return n[t%n.length]||n[0]}resetIdCounter(){this.nextCandyId=1}}
@@ -1 +1 @@
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);
1
+ "use strict";import{create as e}from"zustand";import{subscribeWithSelector as s}from"zustand/middleware";import{CandyCrushService as t}from"./CandyCrushService.js";import{CANDY_CRUSH_GAME_CONFIG as n,DIFFICULTY_CONFIG as o,CANDY_CRUSH_SOUNDS as r}from"./CandyCrushConstants.js";import{immerMiddleware as a}from"../../services/UtilsService.js";import{playSound as i}from"../../services/SoundsService.js";import{playHaptic as u,HapticType as c}from"../../services/HapticsService.js";const l=new t;export const useCandyCrushStore=e()(s(a((e,s)=>({grid:l.createGrid(),score:0,timeRemaining:180,gameDuration:180,isPlaying:!1,isGameOver:!1,selectedCandy:null,isProcessing:!1,difficulty:"easy",candyTypes:4,enableSounds:!0,enableHaptics:!0,comboCount:0,gameTimer:null,matchedCandyIds:new Set,fallingCandyIds:new Set,startGame:()=>{const t=s();t.gameTimer&&clearInterval(t.gameTimer),i(r.SWAP,t.enableSounds),u(c.MEDIUM,t.enableHaptics);const n=setInterval(()=>{const t=s();t.timeRemaining>0&&t.isPlaying&&e(e=>{e.timeRemaining--,30===e.timeRemaining&&(i(r.SPECIAL,e.enableSounds),u(c.MEDIUM,e.enableHaptics)),10===e.timeRemaining&&(i(r.SPECIAL,e.enableSounds),u(c.HEAVY,e.enableHaptics)),e.timeRemaining>0||(e.isGameOver=!0,e.isPlaying=!1,e.gameTimer&&(clearInterval(e.gameTimer),e.gameTimer=null),i(r.LOSE,e.enableSounds),u(c.HEAVY,e.enableHaptics))})},1e3);e(e=>{e.isPlaying=!0,e.gameTimer=n})},stopGame:()=>{const e=s();e.gameTimer&&clearInterval(e.gameTimer),i(r.LOSE,e.enableSounds),u(c.MEDIUM,e.enableHaptics),e.initializeGame(e.difficulty)},resetGame:()=>{const e=s();e.initializeGame(e.difficulty),e.startGame()},initializeGame:(t="easy")=>{const n=s();n.gameTimer&&clearInterval(n.gameTimer),e(e=>{const s=o[t];l.resetIdCounter(),e.grid=l.initializeGrid(s.candyTypes),e.score=0,e.timeRemaining=s.gameDuration,e.gameDuration=s.gameDuration,e.isPlaying=!1,e.isGameOver=!1,e.selectedCandy=null,e.isProcessing=!1,e.difficulty=t,e.candyTypes=s.candyTypes,e.comboCount=0,e.gameTimer=null,e.matchedCandyIds=new Set,e.fallingCandyIds=new Set})},selectCandy:t=>{const o=s();o.isProcessing||!o.isPlaying||o.isGameOver||e(e=>{if(e.selectedCandy)if(e.selectedCandy.id===t.id)e.selectedCandy=null;else if(l.canSwap(e.selectedCandy,t)){const o=e.selectedCandy,a=t;l.swapCandies(e.grid,o,a),new Set([o.row,a.row]).forEach(s=>{e.grid[s]&&(e.grid[s]=[...e.grid[s]])}),l.findMatches(e.grid).hasMatches?(e.selectedCandy=null,e.isProcessing=!0,i(r.SWAP,e.enableSounds),u(c.MEDIUM,e.enableHaptics),setTimeout(()=>{s().processMatches()},n.SWAP_DURATION)):(l.swapCandies(e.grid,o,a),e.selectedCandy=null,new Set([o.row,a.row]).forEach(s=>{e.grid[s]&&(e.grid[s]=[...e.grid[s]])}),i(r.SWAP,e.enableSounds),u(c.LIGHT,e.enableHaptics))}else e.selectedCandy=t,i(r.SWAP,e.enableSounds),u(c.LIGHT,e.enableHaptics);else e.selectedCandy=t,i(r.SWAP,e.enableSounds),u(c.LIGHT,e.enableHaptics)})},processMatches:async()=>{let t=!0,o=0;for(;t;){const a=s(),d=l.findMatches(a.grid);if(!d.hasMatches){t=!1;break}o++;const m=d.score,C=o>1?Math.pow(n.COMBO_MULTIPLIER,o-1):1,S=Math.floor(m*C);e(e=>{e.score+=S,e.comboCount=o}),o>1?(i(r.COMBO,a.enableSounds),u(c.HEAVY,a.enableHaptics)):(i(r.MATCH,a.enableSounds),u(c.MEDIUM,a.enableHaptics)),e(e=>{e.matchedCandyIds=new Set(d.matches.map(e=>e.id))}),await new Promise(e=>setTimeout(e,n.ANIMATION_DURATION)),e(e=>{e.matchedCandyIds=new Set;const s=new Set;d.matches.forEach(e=>s.add(e.row));const t=e.grid.map(e=>e.map(e=>e?.id).join(","));l.removeMatches(e.grid,d.matches),l.applyGravity(e.grid),l.fillEmptySpaces(e.grid,a.candyTypes);const n=new Set;e.grid.forEach(e=>{e.forEach(e=>{e&&e.isFalling&&n.add(e.id)})}),e.fallingCandyIds=n,e.grid.forEach((s,n)=>{const o=s.map(e=>e?.id).join(",");t[n]!==o&&(e.grid[n]=[...s])})}),await new Promise(e=>setTimeout(e,n.FALL_DURATION))}e(e=>{e.isProcessing=!1,e.comboCount=0,e.matchedCandyIds=new Set,e.fallingCandyIds=new Set})},updateSettings:(s,t)=>{e(e=>{e.enableSounds=s,e.enableHaptics=t})}}))));export const useGrid=()=>useCandyCrushStore(e=>e.grid);export const useScore=()=>useCandyCrushStore(e=>e.score);export const useTimeRemaining=()=>useCandyCrushStore(e=>e.timeRemaining);export const useGameDuration=()=>useCandyCrushStore(e=>e.gameDuration);export const useIsPlaying=()=>useCandyCrushStore(e=>e.isPlaying);export const useIsGameOver=()=>useCandyCrushStore(e=>e.isGameOver);export const useSelectedCandy=()=>useCandyCrushStore(e=>e.selectedCandy);export const useComboCount=()=>useCandyCrushStore(e=>e.comboCount);export const useMatchedCandyIds=()=>useCandyCrushStore(e=>e.matchedCandyIds);export const useFallingCandyIds=()=>useCandyCrushStore(e=>e.fallingCandyIds);
@@ -1 +1 @@
1
- "use strict";import React,{useEffect,useRef}from 'react';import{StyleSheet}from 'react-native';import{Gesture,GestureDetector}from 'react-native-gesture-handler';import Animated,{useSharedValue,useAnimatedStyle,withSpring,withTiming,runOnJS}from 'react-native-reanimated';import{Canvas,RoundedRect,Group,Shadow}from '@shopify/react-native-skia';import{CandyCrushService}from "../CandyCrushService.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";const gameService = new CandyCrushService();const CandyItemComponent =({candy,size,isSelected,isMatched,isFalling,onSwipe})=>{const translateX = useSharedValue(0);const translateY = useSharedValue(0);const scale = useSharedValue(1);const opacity = useSharedValue(1);const zIndex = useSharedValue(0);const prevMatchedRef = useRef(isMatched);const prevFallingRef = useRef(isFalling);const prevRowRef = useRef(candy.row);useEffect(()=>{if(isMatched && !prevMatchedRef.current){scale.value = withTiming(0,{duration:300});opacity.value = withTiming(0,{duration:300});}else if(!isMatched && prevMatchedRef.current){scale.value = 1;opacity.value = 1;}prevMatchedRef.current = isMatched;},[isMatched]);useEffect(()=>{const rowChanged = candy.row !== prevRowRef.current;if(isFalling && !prevFallingRef.current){scale.value = withSpring(1,{damping:8,stiffness:40});}else if(rowChanged && isFalling){scale.value = withSpring(1,{damping:8,stiffness:40});}prevFallingRef.current = isFalling;prevRowRef.current = candy.row;},[isFalling,candy.row]);const panGesture = Gesture.Pan().onStart(()=>{zIndex.value = 1000;scale.value = withSpring(1.1);}).onUpdate(event =>{translateX.value = event.translationX;translateY.value = event.translationY;}).onEnd(event =>{const threshold = size * 0.3;const absX = Math.abs(event.translationX);const absY = Math.abs(event.translationY);if(absX > threshold || absY > threshold){if(absX > absY){if(event.translationX > 0){runOnJS(onSwipe)('right');}else{runOnJS(onSwipe)('left');}}else{if(event.translationY > 0){runOnJS(onSwipe)('down');}else{runOnJS(onSwipe)('up');}}}translateX.value = withSpring(0);translateY.value = withSpring(0);scale.value = withSpring(1);zIndex.value = withTiming(0,{duration:300});});const candyColor = gameService.getCandyColor(candy.type);const borderRadius = 8;const animatedStyle = useAnimatedStyle(()=>({transform:[{translateX:translateX.value},{translateY:translateY.value},{scale:scale.value}],opacity:opacity.value,zIndex:zIndex.value}));return _jsx(GestureDetector,{gesture:panGesture,children:_jsx(Animated.View,{style:[styles.container,{width:size,height:size},animatedStyle],children:_jsx(Canvas,{style:{width:size,height:size},children:_jsxs(Group,{children:[_jsx(RoundedRect,{x:2,y:2,width:size - 4,height:size - 4,r:borderRadius,color:candyColor}),_jsx(RoundedRect,{x:size * 0.15,y:size * 0.15,width:size * 0.35,height:size * 0.35,r:6,color:"rgba(255,255,255,0.5)"}),_jsx(RoundedRect,{x:6,y:6,width:size - 12,height:size - 12,r:borderRadius - 2,color:"rgba(255,255,255,0.2)"}),isSelected && _jsx(RoundedRect,{x:1,y:1,width:size - 2,height:size - 2,r:borderRadius + 1,color:"transparent",style:"stroke",strokeWidth:3,children:_jsx(Shadow,{dx:0,dy:0,blur:6,color:"rgba(255,255,255,1)"})})]})})})});};export const CandyItem = React.memo(CandyItemComponent,(prevProps,nextProps)=>{return prevProps.candy.id === nextProps.candy.id && prevProps.candy.type === nextProps.candy.type && prevProps.candy.row === nextProps.candy.row && prevProps.candy.col === nextProps.candy.col && prevProps.isMatched === nextProps.isMatched && prevProps.isFalling === nextProps.isFalling && prevProps.isSelected === nextProps.isSelected && prevProps.size === nextProps.size;});CandyItem.displayName = 'CandyItem';const styles = StyleSheet.create({container:{justifyContent:'center',alignItems:'center'}});
1
+ "use strict";import t,{useEffect as e,useRef as r}from"react";import{StyleSheet as i}from"react-native";import{Gesture as n,GestureDetector as o}from"react-native-gesture-handler";import a,{useSharedValue as s,useAnimatedStyle as c,withSpring as h,withTiming as d,runOnJS as l}from"react-native-reanimated";import{Canvas as m,RoundedRect as y,Group as g,Shadow as p}from"@shopify/react-native-skia";import{CandyCrushService as f}from"../CandyCrushService.js";import{jsx as u,jsxs as x}from"react/jsx-runtime";const w=new f,C=({candy:t,size:i,isSelected:f,isMatched:C,isFalling:v,onSwipe:I})=>{const b=s(0),k=s(0),M=s(1),S=s(1),z=s(0),F=r(C),W=r(v),X=r(t.row);e(()=>{C&&!F.current?(M.value=d(0,{duration:300}),S.value=d(0,{duration:300})):!C&&F.current&&(M.value=1,S.value=1),F.current=C},[C]),e(()=>{const e=t.row!==X.current;(v&&!W.current||e&&v)&&(M.value=h(1,{damping:8,stiffness:40})),W.current=v,X.current=t.row},[v,t.row]);const Y=n.Pan().onStart(()=>{z.value=1e3,M.value=h(1.1)}).onUpdate(t=>{b.value=t.translationX,k.value=t.translationY}).onEnd(t=>{const e=.3*i,r=Math.abs(t.translationX),n=Math.abs(t.translationY);(r>e||n>e)&&(r>n?t.translationX>0?l(I)("right"):l(I)("left"):t.translationY>0?l(I)("down"):l(I)("up")),b.value=h(0),k.value=h(0),M.value=h(1),z.value=d(0,{duration:300})}),q=w.getCandyColor(t.type),A=c(()=>({transform:[{translateX:b.value},{translateY:k.value},{scale:M.value}],opacity:S.value,zIndex:z.value}));return u(o,{gesture:Y,children:u(a.View,{style:[j.container,{width:i,height:i},A],children:u(m,{style:{width:i,height:i},children:x(g,{children:[u(y,{x:2,y:2,width:i-4,height:i-4,r:8,color:q}),u(y,{x:.15*i,y:.15*i,width:.35*i,height:.35*i,r:6,color:"rgba(255, 255, 255, 0.5)"}),u(y,{x:6,y:6,width:i-12,height:i-12,r:6,color:"rgba(255, 255, 255, 0.2)"}),f&&u(y,{x:1,y:1,width:i-2,height:i-2,r:9,color:"transparent",style:"stroke",strokeWidth:3,children:u(p,{dx:0,dy:0,blur:6,color:"rgba(255, 255, 255, 1)"})})]})})})})};export const CandyItem=t.memo(C,(t,e)=>t.candy.id===e.candy.id&&t.candy.type===e.candy.type&&t.candy.row===e.candy.row&&t.candy.col===e.candy.col&&t.isMatched===e.isMatched&&t.isFalling===e.isFalling&&t.isSelected===e.isSelected&&t.size===e.size);CandyItem.displayName="CandyItem";const j=i.create({container:{justifyContent:"center",alignItems:"center"}});
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{Canvas,Rect,LinearGradient,vec,Circle,Path,Skia}from '@shopify/react-native-skia';import{Dimensions}from 'react-native';import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from "react/jsx-runtime";const{width,height}= Dimensions.get('window');const createStarPaths =()=>{return [...Array(15)].map((_,i)=>{const x = width *(i * 7 + 3)% width;const y = height *(i * 11 + 5)% height;const size = 3 + i % 3;const starPath = Skia.Path.Make();starPath.moveTo(x,y - size);starPath.lineTo(x + size * 0.3,y + size * 0.3);starPath.lineTo(x + size,y + size * 0.3);starPath.lineTo(x + size * 0.5,y + size * 0.8);starPath.lineTo(x + size * 0.7,y + size * 1.5);starPath.lineTo(x,y + size);starPath.lineTo(x - size * 0.7,y + size * 1.5);starPath.lineTo(x - size * 0.5,y + size * 0.8);starPath.lineTo(x - size,y + size * 0.3);starPath.lineTo(x - size * 0.3,y + size * 0.3);starPath.close();return{path:starPath,opacity:0.1 + i % 3 * 0.05};});};const starPaths = createStarPaths();export const GameBackground = React.memo(({children})=>{return _jsxs(_Fragment,{children:[_jsxs(Canvas,{style:{position:'absolute',width,height},children:[_jsx(Rect,{x:0,y:0,width:width,height:height,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(0,height),colors:['#667eea','#764ba2','#f093fb']})}),_jsx(Circle,{cx:width * 0.1,cy:height * 0.15,r:60,color:"rgba(255,255,255,0.05)"}),_jsx(Circle,{cx:width * 0.85,cy:height * 0.25,r:80,color:"rgba(255,255,255,0.05)"}),_jsx(Circle,{cx:width * 0.2,cy:height * 0.7,r:50,color:"rgba(255,255,255,0.05)"}),_jsx(Circle,{cx:width * 0.9,cy:height * 0.8,r:70,color:"rgba(255,255,255,0.05)"}),starPaths.map((star,i)=> _jsx(Path,{path:star.path,color:`rgba(255,255,255,${star.opacity})`},i))]}),children]});});GameBackground.displayName = 'GameBackground';
1
+ "use strict";import r from"react";import{Canvas as o,Rect as t,LinearGradient as a,vec as c,Circle as e,Path as i,Skia as s}from"@shopify/react-native-skia";import{Dimensions as n}from"react-native";import{jsx as h,jsxs as m,Fragment as d}from"react/jsx-runtime";const{width:g,height:l}=n.get("window"),p=()=>[...Array(15)].map((r,o)=>{const t=g*(7*o+3)%g,a=l*(11*o+5)%l,c=3+o%3,e=s.Path.Make();return e.moveTo(t,a-c),e.lineTo(t+.3*c,a+.3*c),e.lineTo(t+c,a+.3*c),e.lineTo(t+.5*c,a+.8*c),e.lineTo(t+.7*c,a+1.5*c),e.lineTo(t,a+c),e.lineTo(t-.7*c,a+1.5*c),e.lineTo(t-.5*c,a+.8*c),e.lineTo(t-c,a+.3*c),e.lineTo(t-.3*c,a+.3*c),e.close(),{path:e,opacity:.1+o%3*.05}}),x=p();export const GameBackground=r.memo(({children:r})=>m(d,{children:[m(o,{style:{position:"absolute",width:g,height:l},children:[h(t,{x:0,y:0,width:g,height:l,children:h(a,{start:c(0,0),end:c(0,l),colors:["#667eea","#764ba2","#f093fb"]})}),h(e,{cx:.1*g,cy:.15*l,r:60,color:"rgba(255, 255, 255, 0.05)"}),h(e,{cx:.85*g,cy:.25*l,r:80,color:"rgba(255, 255, 255, 0.05)"}),h(e,{cx:.2*g,cy:.7*l,r:50,color:"rgba(255, 255, 255, 0.05)"}),h(e,{cx:.9*g,cy:.8*l,r:70,color:"rgba(255, 255, 255, 0.05)"}),x.map((r,o)=>h(i,{path:r.path,color:`rgba(255, 255, 255, ${r.opacity})`},o))]}),r]}));GameBackground.displayName="GameBackground";
@@ -1 +1 @@
1
- "use strict";import React,{useMemo,useRef,useEffect}from 'react';import{View,StyleSheet,Dimensions}from 'react-native';import{Canvas,RoundedRect,LinearGradient,vec,Shadow,Circle,Group}from '@shopify/react-native-skia';import{useGrid,useSelectedCandy,useCandyCrushStore,useMatchedCandyIds,useFallingCandyIds}from "../CandyCrushStore.js";import{CandyItem}from "./CandyItem.js";import{CANDY_CRUSH_GAME_CONFIG,CANDY_CRUSH_COLORS}from "../CandyCrushConstants.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";const{width:screenWidth}= Dimensions.get('window');const GridRow = React.memo(({row,rowIndex,candySize,gap,selectedCandyId,matchedCandyIds,fallingCandyIds,onSwipe})=>{return _jsx(View,{style:[styles.row,{gap}],children:row.map((candy,colIndex)=>{if(!candy){return _jsx(View,{style:[styles.cell,{width:candySize,height:candySize}]},`empty-${rowIndex}-${colIndex}`);}const isSelected = selectedCandyId === candy.id;const isMatched = matchedCandyIds.has(candy.id);const isFalling = fallingCandyIds.has(candy.id);const handleSwipe = direction =>{onSwipe(candy,direction);};return _jsx(View,{style:[styles.cell,{width:candySize,height:candySize}],children:_jsx(CandyItem,{candy:candy,size:candySize,isSelected:isSelected,isMatched:isMatched,isFalling:isFalling,onSwipe:handleSwipe})},candy.id);})},`row-${rowIndex}`);},(prevProps,nextProps)=>{if(prevProps.row === nextProps.row){return true;}if(prevProps.row.length !== nextProps.row.length)return false;if(prevProps.candySize !== nextProps.candySize)return false;if(prevProps.gap !== nextProps.gap)return false;const hadSelectedCandy = prevProps.row.some(c => c?.id === prevProps.selectedCandyId);const hasSelectedCandy = nextProps.row.some(c => c?.id === nextProps.selectedCandyId);if(hadSelectedCandy !== hasSelectedCandy || hadSelectedCandy && prevProps.selectedCandyId !== nextProps.selectedCandyId){return false;}for(let i = 0;i < prevProps.row.length;i++){const candy = prevProps.row[i];if(candy){const wasMatched = prevProps.matchedCandyIds.has(candy.id);const isMatched = nextProps.matchedCandyIds.has(candy.id);const wasFalling = prevProps.fallingCandyIds.has(candy.id);const isFalling = nextProps.fallingCandyIds.has(candy.id);if(wasMatched !== isMatched || wasFalling !== isFalling){return false;}}}for(let i = 0;i < prevProps.row.length;i++){const prevCandy = prevProps.row[i];const nextCandy = nextProps.row[i];if(prevCandy?.id !== nextCandy?.id)return false;if(prevCandy?.type !== nextCandy?.type)return false;if(prevCandy?.row !== nextCandy?.row)return false;if(prevCandy?.col !== nextCandy?.col)return false;}return true;});export const GameGrid = React.memo(()=>{const grid = useGrid();const selectedCandy = useSelectedCandy();const matchedCandyIds = useMatchedCandyIds();const fallingCandyIds = useFallingCandyIds();const selectCandy = useCandyCrushStore(state => state.selectCandy);const selectedCandyId = selectedCandy?.id || null;const gridRef = useRef(grid);useEffect(()=>{gridRef.current = grid;},[grid]);const handleSwipe = React.useCallback((candy,direction)=>{const currentGrid = gridRef.current;let targetRow = candy.row;let targetCol = candy.col;switch(direction){case 'up':targetRow = candy.row - 1;break;case 'down':targetRow = candy.row + 1;break;case 'left':targetCol = candy.col - 1;break;case 'right':targetCol = candy.col + 1;break;}if(targetRow >= 0 && targetRow < currentGrid.length && targetCol >= 0 && currentGrid[0] && targetCol < currentGrid[0].length){const targetRowData = currentGrid[targetRow];if(targetRowData){const targetCandy = targetRowData[targetCol];if(targetCandy){selectCandy(candy);setTimeout(()=> selectCandy(targetCandy),50);}}}},[selectCandy]);const gridCalculations = useMemo(()=>{const horizontalPadding = 40;const availableWidth = screenWidth - horizontalPadding;const gridSize = CANDY_CRUSH_GAME_CONFIG.GRID_SIZE;const gap = 2;const totalGaps =(gridSize - 1)* gap;const candySize =(availableWidth - totalGaps)/ gridSize;const padding = 10;const contentWidth = Math.floor(candySize)* gridSize + totalGaps;const contentHeight = Math.floor(candySize)* gridSize + totalGaps;const gridWidth = contentWidth + padding * 2;const gridHeight = contentHeight + padding * 2;return{candySize:Math.floor(candySize),gap,gridSize,gridWidth,gridHeight};},[]);const{candySize,gap,gridWidth,gridHeight}= gridCalculations;const jellyBubbles = useMemo(()=>{const bubbles = [];const bubbleCount = 25;for(let i = 0;i < bubbleCount;i++){bubbles.push({x:Math.random()* gridWidth,y:Math.random()* gridHeight,radius:Math.random()* 15 + 5,opacity:Math.random()* 0.15 + 0.05});}return bubbles;},[gridWidth,gridHeight]);return _jsxs(View,{style:styles.container,children:[_jsx(View,{style:[styles.jellyContainer,{width:gridWidth,height:gridHeight}],children:_jsxs(Canvas,{style:{width:gridWidth,height:gridHeight},children:[_jsxs(RoundedRect,{x:0,y:0,width:gridWidth,height:gridHeight,r:15,children:[_jsx(LinearGradient,{start:vec(0,0),end:vec(gridWidth,gridHeight),colors:['rgba(255,149,0,0.35)','rgba(255,120,0,0.25)','rgba(255,149,0,0.3)']}),_jsx(Shadow,{dx:0,dy:6,blur:12,color:"rgba(255,100,0,0.4)",inner:true})]}),_jsx(Group,{children:jellyBubbles.map((bubble,index)=> _jsx(Circle,{cx:bubble.x,cy:bubble.y,r:bubble.radius,color:`rgba(255,255,255,${bubble.opacity})`},index))}),_jsx(RoundedRect,{x:5,y:5,width:gridWidth - 10,height:gridHeight - 10,r:12,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(0,gridHeight),colors:['rgba(255,200,100,0.3)','rgba(255,149,0,0)','rgba(255,180,80,0.2)']})}),_jsx(RoundedRect,{x:15,y:15,width:gridWidth - 30,height:gridHeight * 0.25,r:8,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(0,gridHeight * 0.25),colors:['rgba(255,255,255,0.5)','rgba(255,255,255,0)']})}),_jsx(RoundedRect,{x:15,y:gridHeight * 0.75,width:gridWidth - 30,height:gridHeight * 0.2,r:8,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(0,gridHeight * 0.2),colors:['rgba(0,0,0,0)','rgba(255,100,0,0.2)']})})]})}),_jsx(View,{style:[styles.grid,{gap}],children:grid.map((row,rowIndex)=> _jsx(GridRow,{row:row,rowIndex:rowIndex,candySize:candySize,gap:gap,selectedCandyId:selectedCandyId,matchedCandyIds:matchedCandyIds,fallingCandyIds:fallingCandyIds,onSwipe:handleSwipe},rowIndex))})]});});GameGrid.displayName = 'GameGrid';const styles = StyleSheet.create({container:{flex:1,justifyContent:'center',alignItems:'center',position:'relative'},jellyContainer:{position:'absolute',borderRadius:15,borderWidth:3,borderColor:CANDY_CRUSH_COLORS.GRID_BORDER,overflow:'hidden'},grid:{padding:13,zIndex:1},row:{flexDirection:'row'},cell:{justifyContent:'center',alignItems:'center'}});
1
+ "use strict";import r,{useMemo as t,useRef as e,useEffect as i}from"react";import{View as n,StyleSheet as a,Dimensions as o}from"react-native";import{Canvas as d,RoundedRect as s,LinearGradient as c,vec as h,Shadow as l,Circle as g,Group as y}from"@shopify/react-native-skia";import{useGrid as f,useSelectedCandy as u,useCandyCrushStore as m,useMatchedCandyIds as p,useFallingCandyIds as w}from"../CandyCrushStore.js";import{CandyItem as b}from"./CandyItem.js";import{CANDY_CRUSH_GAME_CONFIG as x,CANDY_CRUSH_COLORS as C}from"../CandyCrushConstants.js";import{jsx as I,jsxs as S}from"react/jsx-runtime";const{width:j}=o.get("window"),M=r.memo(({row:r,rowIndex:t,candySize:e,gap:i,selectedCandyId:a,matchedCandyIds:o,fallingCandyIds:d,onSwipe:s})=>I(n,{style:[z.row,{gap:i}],children:r.map((r,i)=>{if(!r)return I(n,{style:[z.cell,{width:e,height:e}]},`empty-${t}-${i}`);const c=a===r.id,h=o.has(r.id),l=d.has(r.id);return I(n,{style:[z.cell,{width:e,height:e}],children:I(b,{candy:r,size:e,isSelected:c,isMatched:h,isFalling:l,onSwipe:t=>{s(r,t)}})},r.id)})},"row-"+t),(r,t)=>{if(r.row===t.row)return!0;if(r.row.length!==t.row.length)return!1;if(r.candySize!==t.candySize)return!1;if(r.gap!==t.gap)return!1;const e=r.row.some(t=>t?.id===r.selectedCandyId);if(e!==t.row.some(r=>r?.id===t.selectedCandyId)||e&&r.selectedCandyId!==t.selectedCandyId)return!1;for(let e=0;e<r.row.length;e++){const i=r.row[e];if(i){const e=r.matchedCandyIds.has(i.id),n=t.matchedCandyIds.has(i.id),a=r.fallingCandyIds.has(i.id),o=t.fallingCandyIds.has(i.id);if(e!==n||a!==o)return!1}}for(let e=0;e<r.row.length;e++){const i=r.row[e],n=t.row[e];if(i?.id!==n?.id)return!1;if(i?.type!==n?.type)return!1;if(i?.row!==n?.row)return!1;if(i?.col!==n?.col)return!1}return!0});export const GameGrid=r.memo(()=>{const a=f(),o=u(),b=p(),C=w(),G=m(r=>r.selectCandy),k=o?.id||null,v=e(a);i(()=>{v.current=a},[a]);const W=r.useCallback((r,t)=>{const e=v.current;let i=r.row,n=r.col;switch(t){case"up":i=r.row-1;break;case"down":i=r.row+1;break;case"left":n=r.col-1;break;case"right":n=r.col+1}if(i>=0&&i<e.length&&n>=0&&e[0]&&n<e[0].length){const t=e[i];if(t){const e=t[n];e&&(G(r),setTimeout(()=>G(e),50))}}},[G]),$=t(()=>{const r=j-40,t=x.GRID_SIZE,e=2*(t-1),i=(r-e)/t,n=Math.floor(i)*t+e+20,a=Math.floor(i)*t+e+20;return{candySize:Math.floor(i),gap:2,gridSize:t,gridWidth:n,gridHeight:a}},[]),{candySize:H,gap:D,gridWidth:F,gridHeight:R}=$,T=t(()=>{const r=[];for(let t=0;25>t;t++)r.push({x:Math.random()*F,y:Math.random()*R,radius:15*Math.random()+5,opacity:.15*Math.random()+.05});return r},[F,R]);return S(n,{style:z.container,children:[I(n,{style:[z.jellyContainer,{width:F,height:R}],children:S(d,{style:{width:F,height:R},children:[S(s,{x:0,y:0,width:F,height:R,r:15,children:[I(c,{start:h(0,0),end:h(F,R),colors:["rgba(255, 149, 0, 0.35)","rgba(255, 120, 0, 0.25)","rgba(255, 149, 0, 0.3)"]}),I(l,{dx:0,dy:6,blur:12,color:"rgba(255, 100, 0, 0.4)",inner:!0})]}),I(y,{children:T.map((r,t)=>I(g,{cx:r.x,cy:r.y,r:r.radius,color:`rgba(255, 255, 255, ${r.opacity})`},t))}),I(s,{x:5,y:5,width:F-10,height:R-10,r:12,children:I(c,{start:h(0,0),end:h(0,R),colors:["rgba(255, 200, 100, 0.3)","rgba(255, 149, 0, 0)","rgba(255, 180, 80, 0.2)"]})}),I(s,{x:15,y:15,width:F-30,height:.25*R,r:8,children:I(c,{start:h(0,0),end:h(0,.25*R),colors:["rgba(255, 255, 255, 0.5)","rgba(255, 255, 255, 0)"]})}),I(s,{x:15,y:.75*R,width:F-30,height:.2*R,r:8,children:I(c,{start:h(0,0),end:h(0,.2*R),colors:["rgba(0, 0, 0, 0)","rgba(255, 100, 0, 0.2)"]})})]})}),I(n,{style:[z.grid,{gap:D}],children:a.map((r,t)=>I(M,{row:r,rowIndex:t,candySize:H,gap:D,selectedCandyId:k,matchedCandyIds:b,fallingCandyIds:C,onSwipe:W},t))})]})});GameGrid.displayName="GameGrid";const z=a.create({container:{flex:1,justifyContent:"center",alignItems:"center",position:"relative"},jellyContainer:{position:"absolute",borderRadius:15,borderWidth:3,borderColor:C.GRID_BORDER,overflow:"hidden"},grid:{padding:13,zIndex:1},row:{flexDirection:"row"},cell:{justifyContent:"center",alignItems:"center"}});
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{View,Text,StyleSheet}from 'react-native';import{useScore,useTimeRemaining}from "../CandyCrushStore.js";import{CANDY_CRUSH_COLORS}from "../CandyCrushConstants.js";import{ScoreBoardContainer}from "../../../helpers/index.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";export const ScoreBoard = React.memo(({offset = 0})=>{const score = useScore();const timeRemaining = useTimeRemaining();const timeDisplay = React.useMemo(()=>{const minutes = Math.floor(timeRemaining / 60);const seconds = timeRemaining % 60;return `${minutes}:${seconds.toString().padStart(2,'0')}`;},[timeRemaining]);const timeColor = React.useMemo(()=>{if(timeRemaining <= 30)return CANDY_CRUSH_COLORS.TIME_CRITICAL;if(timeRemaining <= 60)return CANDY_CRUSH_COLORS.TIME_WARNING;return CANDY_CRUSH_COLORS.TIME_GOOD;},[timeRemaining]);return _jsx(ScoreBoardContainer,{offset:offset,backgroundColor:CANDY_CRUSH_COLORS.SCORE_BACKGROUND,borderColor:CANDY_CRUSH_COLORS.GRID_BORDER,children:_jsxs(View,{style:styles.scoreRow,children:[_jsxs(View,{style:styles.scoreItem,children:[_jsx(Text,{style:styles.label,children:"Score"}),_jsx(Text,{style:styles.value,children:score})]}),_jsxs(View,{style:styles.scoreItem,children:[_jsx(Text,{style:styles.label,children:"Time"}),_jsx(Text,{style:[styles.value,{color:timeColor}],children:timeDisplay})]})]})});});ScoreBoard.displayName = 'ScoreBoard';const styles = StyleSheet.create({scoreRow:{flex:1,flexDirection:'row',justifyContent:'space-around'},scoreItem:{alignItems:'center'},label:{fontSize:16,color:'rgba(255,255,255,0.7)',marginBottom:4},value:{fontSize:25,color:CANDY_CRUSH_COLORS.SCORE_TEXT,fontWeight:'bold'}});
1
+ "use strict";import r from"react";import{View as o,Text as e,StyleSheet as t}from"react-native";import{useScore as s,useTimeRemaining as n}from"../CandyCrushStore.js";import{CANDY_CRUSH_COLORS as c}from"../CandyCrushConstants.js";import{ScoreBoardContainer as l}from"../../../helpers/index.js";import{jsx as i,jsxs as a}from"react/jsx-runtime";export const ScoreBoard=r.memo(({offset:t=0})=>{const m=s(),f=n(),h=r.useMemo(()=>`${Math.floor(f/60)}:${(""+f%60).padStart(2,"0")}`,[f]),y=r.useMemo(()=>f>30?f>60?c.TIME_GOOD:c.TIME_WARNING:c.TIME_CRITICAL,[f]);return i(l,{offset:t,backgroundColor:c.SCORE_BACKGROUND,borderColor:c.GRID_BORDER,children:a(o,{style:d.scoreRow,children:[a(o,{style:d.scoreItem,children:[i(e,{style:d.label,children:"Score"}),i(e,{style:d.value,children:m})]}),a(o,{style:d.scoreItem,children:[i(e,{style:d.label,children:"Time"}),i(e,{style:[d.value,{color:y}],children:h})]})]})})});ScoreBoard.displayName="ScoreBoard";const d=t.create({scoreRow:{flex:1,flexDirection:"row",justifyContent:"space-around"},scoreItem:{alignItems:"center"},label:{fontSize:16,color:"rgba(255, 255, 255, 0.7)",marginBottom:4},value:{fontSize:25,color:c.SCORE_TEXT,fontWeight:"bold"}});
@@ -1 +1 @@
1
- "use strict";export{GameBackground}from "./GameBackground.js";export{GameGrid}from "./GameGrid.js";export{ScoreBoard}from "./ScoreBoard.js";export{CandyItem}from "./CandyItem.js";
1
+ "use strict";export{GameBackground}from"./GameBackground.js";export{GameGrid}from"./GameGrid.js";export{ScoreBoard}from"./ScoreBoard.js";export{CandyItem}from"./CandyItem.js";
@@ -1 +1 @@
1
- "use strict";export{CandyCrush}from "./CandyCrush.js";export{useCandyCrushStore}from "./CandyCrushStore.js";export * from "./CandyCrushConstants.js";
1
+ "use strict";export{CandyCrush}from"./CandyCrush.js";export{useCandyCrushStore}from"./CandyCrushStore.js";export*from"./CandyCrushConstants.js";
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{View,StyleSheet,Dimensions}from 'react-native';import{GestureDetector,Gesture,GestureHandlerRootView}from 'react-native-gesture-handler';import{useCarRacingStore,useScore,useIsPlaying,useGameOver,useObstacles,usePlayerCar,useRoadOffset,useParticleEffects,useLives}from "./CarRacingStore.js";import{CarRacingService}from "./CarRacingService.js";import{GameBackground,CarComponent,ScoreBoard}from "./components/index.js";import{GameControlButton,GameOverModal,GameSettingsModal,ParticleBlast}from "../../helpers/index.js";import{GAME_IDS,DEFAULT_GAME_SETTINGS}from "../../services/UtilsService.js";import{getDifficultySettings,CAR_RACING_COLORS,CAR_RACING_GAME_CONFIG}from "./CarRacingConstants.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";const{width,height}= Dimensions.get('window');export const CarRacing =({settings:externalSettings = DEFAULT_GAME_SETTINGS,onSettingsChange,onEndGame})=>{const difficulty = externalSettings?.difficulty || 'medium';const soundEnabled = externalSettings?.enableSounds ?? true;const hapticEnabled = externalSettings?.enableHaptics ?? true;const offset = externalSettings?.offset ?? 0;const score = useScore();const isPlaying = useIsPlaying();const gameOver = useGameOver();const lives = useLives();const obstacles = useObstacles();const playerCar = usePlayerCar();const roadOffset = useRoadOffset();const particleEffects = useParticleEffects();const gameReportedRef = React.useRef(false);const reportGameEnd = React.useCallback(status =>{if(onEndGame && !gameReportedRef.current){onEndGame({status,score:score.toString()});gameReportedRef.current = true;}},[onEndGame,score]);const startGame = React.useCallback((duration,offset)=> useCarRacingStore.getState().startGame(duration,offset),[]);const stopGame = React.useCallback(()=> useCarRacingStore.getState().stopGame(),[]);const resetGame = React.useCallback(()=> useCarRacingStore.getState().resetGame(),[]);const handleParticleComplete = React.useCallback(effectId =>{useCarRacingStore.getState().removeParticleEffect(effectId);},[]);const difficultySettings = React.useMemo(()=> getDifficultySettings(difficulty),[difficulty]);const gameService = React.useMemo(()=> new CarRacingService(difficultySettings.roadSpeed,difficultySettings.obstacleSpawnInterval),[difficultySettings.roadSpeed,difficultySettings.obstacleSpawnInterval]);React.useEffect(()=>{useCarRacingStore.getState().setOffset(offset);},[offset]);React.useEffect(()=>{const handleCollision =()=>{playSound(GAME_SOUNDS.CAR_RACING.CRASH,soundEnabled);playHaptic(HapticType.ERROR,hapticEnabled);};const handlePass =()=>{playSound(GAME_SOUNDS.CAR_RACING.PASS,soundEnabled);playHaptic(HapticType.LIGHT,hapticEnabled);};gameService.setCallbacks(handleCollision,handlePass);},[gameService,soundEnabled,hapticEnabled]);React.useEffect(()=>{if(!isPlaying)return;const timer = setInterval(()=>{useCarRacingStore.getState().decrementTime();},1000);return()=> clearInterval(timer);},[isPlaying]);React.useEffect(()=>{if(gameOver && !gameReportedRef.current){const status = lives > 0 ? 'win':'lose';reportGameEnd(status);}if(!gameOver){gameReportedRef.current = false;}},[gameOver,lives,reportGameEnd]);React.useEffect(()=>{return()=>{gameService.cleanup();stopGame();};},[gameService]);const handleStartGame = React.useCallback(()=>{gameReportedRef.current = false;startGame(difficultySettings.gameDuration,offset);gameService.startGame();playSound(GAME_SOUNDS.CAR_RACING.START,soundEnabled);playHaptic(HapticType.SUCCESS,hapticEnabled);},[startGame,gameService,difficultySettings.gameDuration,offset,soundEnabled,hapticEnabled]);const handleStopGame = React.useCallback(()=>{reportGameEnd('cancel');stopGame();gameService.stopGame();},[stopGame,gameService,reportGameEnd]);const handleResetGame = React.useCallback(()=>{resetGame();gameService.cleanup();},[resetGame,gameService]);const handlePlayAgain = React.useCallback(()=>{handleResetGame();},[handleResetGame]);const previousLaneRef = React.useRef(1);const panGesture = Gesture.Pan().onUpdate(event =>{if(!isPlaying)return;const roadWidth = CAR_RACING_GAME_CONFIG.LANE_WIDTH * CAR_RACING_GAME_CONFIG.ROAD_LANES;const roadStartX =(width - roadWidth)/ 2;const relativeX = event.absoluteX - roadStartX;const lane = Math.floor(relativeX / CAR_RACING_GAME_CONFIG.LANE_WIDTH);const clampedLane = Math.max(0,Math.min(CAR_RACING_GAME_CONFIG.ROAD_LANES - 1,lane));if(clampedLane !== previousLaneRef.current){previousLaneRef.current = clampedLane;playSound(GAME_SOUNDS.CAR_RACING.LANE_SWITCH,soundEnabled);playHaptic(HapticType.SELECTION,hapticEnabled);}gameService.movePlayerToLane(clampedLane);}).runOnJS(true);const gameControlButtonProps = React.useMemo(()=>({isPlaying,gameOver,onStartGame:handleStartGame,onStopGame:handleStopGame,startButtonColor:CAR_RACING_COLORS.UI,stopButtonColor:CAR_RACING_COLORS.UI,startButtonBorderColor:CAR_RACING_COLORS.UI,stopButtonBorderColor:CAR_RACING_COLORS.UI,startButtonText:'START RACING',stopButtonText:'STOP GAME',startButtonSubtext:'Dodge traffic to score!'}),[isPlaying,gameOver,handleStartGame,handleStopGame]);const gameOverModalProps = React.useMemo(()=>({isVisible:gameOver,score,onPlayAgain:handlePlayAgain,buttonText:"Race Again!",primaryColor:"rgba(255,68,68,0.5)",borderColor:"rgba(255,68,68,0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:CAR_RACING_COLORS.UI}),[gameOver,score,handlePlayAgain]);return _jsx(GestureHandlerRootView,{style:styles.container,children:_jsxs(View,{style:styles.container,children:[_jsx(View,{style:StyleSheet.absoluteFillObject,children:_jsx(GameBackground,{width:width,height:height,roadOffset:roadOffset})}),_jsx(ScoreBoard,{offset:offset}),_jsx(GestureDetector,{gesture:panGesture,children:_jsxs(View,{style:styles.gameArea,children:[obstacles.map(obstacle => _jsx(CarComponent,{x:obstacle.x,y:obstacle.y,width:obstacle.width,height:obstacle.height,color:obstacle.color,isPlayer:false},obstacle.id)),_jsx(CarComponent,{x:playerCar.x,y:playerCar.y,width:playerCar.width,height:playerCar.height,color:CAR_RACING_COLORS.PLAYER_CAR,isPlayer:true})]})}),particleEffects.map(effect => _jsx(ParticleBlast,{x:effect.x,y:effect.y,particleCount:12,colors:['#ff4444','#ff6b6b','#ff8888','#ffaa00','#ffcc00','#ffffff'],duration:800,onComplete:()=> handleParticleComplete(effect.id)},effect.id)),_jsx(GameControlButton,{...gameControlButtonProps}),_jsx(GameOverModal,{...gameOverModalProps}),_jsx(GameSettingsModal,{gameId:GAME_IDS.CAR_RACING,settings:externalSettings || DEFAULT_GAME_SETTINGS,onSettingsChange:onSettingsChange})]})});};const styles = StyleSheet.create({container:{flex:1,backgroundColor:'#000'},gameArea:{flex:1}});
1
+ "use strict";import t from"react";import{View as r,StyleSheet as o,Dimensions as e}from"react-native";import{GestureDetector as n,Gesture as s,GestureHandlerRootView as i}from"react-native-gesture-handler";import{useCarRacingStore as a,useScore as f,useIsPlaying as c,useGameOver as l,useObstacles as m,usePlayerCar as g,useRoadOffset as u,useParticleEffects as d,useLives as h}from"./CarRacingStore.js";import{CarRacingService as p}from"./CarRacingService.js";import{GameBackground as C,CarComponent as x,ScoreBoard as S}from"./components/index.js";import{GameControlButton as b,GameOverModal as v,GameSettingsModal as y,ParticleBlast as j}from"../../helpers/index.js";import{GAME_IDS as B,DEFAULT_GAME_SETTINGS as w}from"../../services/UtilsService.js";import{getDifficultySettings as R,CAR_RACING_COLORS as T,CAR_RACING_GAME_CONFIG as A}from"./CarRacingConstants.js";import{playSound as G,GAME_SOUNDS as P}from"../../services/SoundsService.js";import{playHaptic as I,HapticType as M}from"../../services/HapticsService.js";import{jsx as O,jsxs as E}from"react/jsx-runtime";const{width:k,height:D}=e.get("window");export const CarRacing=({settings:e=w,onSettingsChange:N,onEndGame:U})=>{const V=e?.difficulty||"medium",q=e?.enableSounds??!0,z=e?.enableHaptics??!0,F=e?.offset??0,J=f(),K=c(),L=l(),Q=h(),W=m(),X=g(),Y=u(),Z=d(),$=t.useRef(!1),_=t.useCallback(t=>{U&&!$.current&&(U({status:t,score:J.toString()}),$.current=!0)},[U,J]),tt=t.useCallback((t,r)=>a.getState().startGame(t,r),[]),rt=t.useCallback(()=>a.getState().stopGame(),[]),ot=t.useCallback(()=>a.getState().resetGame(),[]),et=t.useCallback(t=>{a.getState().removeParticleEffect(t)},[]),nt=t.useMemo(()=>R(V),[V]),st=t.useMemo(()=>new p(nt.roadSpeed,nt.obstacleSpawnInterval),[nt.roadSpeed,nt.obstacleSpawnInterval]);t.useEffect(()=>{a.getState().setOffset(F)},[F]),t.useEffect(()=>{st.setCallbacks(()=>{G(P.CAR_RACING.CRASH,q),I(M.ERROR,z)},()=>{G(P.CAR_RACING.PASS,q),I(M.LIGHT,z)})},[st,q,z]),t.useEffect(()=>{if(!K)return;const t=setInterval(()=>{a.getState().decrementTime()},1e3);return()=>clearInterval(t)},[K]),t.useEffect(()=>{L&&!$.current&&_(Q>0?"win":"lose"),L||($.current=!1)},[L,Q,_]),t.useEffect(()=>()=>{st.cleanup(),rt()},[st]);const it=t.useCallback(()=>{$.current=!1,tt(nt.gameDuration,F),st.startGame(),G(P.CAR_RACING.START,q),I(M.SUCCESS,z)},[tt,st,nt.gameDuration,F,q,z]),at=t.useCallback(()=>{_("cancel"),rt(),st.stopGame()},[rt,st,_]),ft=t.useCallback(()=>{ot(),st.cleanup()},[ot,st]),ct=t.useCallback(()=>{ft()},[ft]),lt=t.useRef(1),mt=s.Pan().onUpdate(t=>{if(!K)return;const r=A.LANE_WIDTH*A.ROAD_LANES,o=(k-r)/2,e=t.absoluteX-o,n=Math.floor(e/A.LANE_WIDTH),s=Math.max(0,Math.min(A.ROAD_LANES-1,n));s!==lt.current&&(lt.current=s,G(P.CAR_RACING.LANE_SWITCH,q),I(M.SELECTION,z)),st.movePlayerToLane(s)}).runOnJS(!0),gt=t.useMemo(()=>({isPlaying:K,gameOver:L,onStartGame:it,onStopGame:at,startButtonColor:T.UI,stopButtonColor:T.UI,startButtonBorderColor:T.UI,stopButtonBorderColor:T.UI,startButtonText:"START RACING",stopButtonText:"STOP GAME",startButtonSubtext:"Dodge traffic to score!"}),[K,L,it,at]),ut=t.useMemo(()=>({isVisible:L,score:J,onPlayAgain:ct,buttonText:"Race Again!",primaryColor:"rgba(255, 68, 68, 0.5)",borderColor:"rgba(255, 68, 68, 0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:T.UI}),[L,J,ct]);return O(i,{style:H.container,children:E(r,{style:H.container,children:[O(r,{style:o.absoluteFillObject,children:O(C,{width:k,height:D,roadOffset:Y})}),O(S,{offset:F}),O(n,{gesture:mt,children:E(r,{style:H.gameArea,children:[W.map(t=>O(x,{x:t.x,y:t.y,width:t.width,height:t.height,color:t.color,isPlayer:!1},t.id)),O(x,{x:X.x,y:X.y,width:X.width,height:X.height,color:T.PLAYER_CAR,isPlayer:!0})]})}),Z.map(t=>O(j,{x:t.x,y:t.y,particleCount:12,colors:["#ff4444","#ff6b6b","#ff8888","#ffaa00","#ffcc00","#ffffff"],duration:800,onComplete:()=>et(t.id)},t.id)),O(b,{...gt}),O(v,{...ut}),O(y,{gameId:B.CAR_RACING,settings:e||w,onSettingsChange:N})]})})};const H=o.create({container:{flex:1,backgroundColor:"#000"},gameArea:{flex:1}});
@@ -1 +1 @@
1
- "use strict";export const CAR_RACING_DIFFICULTY_CONFIG ={easy:{gameDuration:60,obstacleSpawnInterval:2500,roadSpeed:4},medium:{gameDuration:120,obstacleSpawnInterval:2000,roadSpeed:6},hard:{gameDuration:180,obstacleSpawnInterval:1500,roadSpeed:8}};export const getDifficultySettings = difficulty =>{return CAR_RACING_DIFFICULTY_CONFIG[difficulty];};export const DEFAULT_CAR_RACING_SETTINGS ={difficulty:'medium',soundEnabled:true,hapticEnabled:true,gameDuration:CAR_RACING_DIFFICULTY_CONFIG.medium.gameDuration,obstacleSpawnInterval:CAR_RACING_DIFFICULTY_CONFIG.medium.obstacleSpawnInterval,roadSpeed:CAR_RACING_DIFFICULTY_CONFIG.medium.roadSpeed};export const CAR_RACING_GAME_CONFIG ={GAME_DURATION:120,CAR_WIDTH:50,CAR_HEIGHT:80,OBSTACLE_WIDTH:50,OBSTACLE_HEIGHT:80,ROAD_LANES:3,LANE_WIDTH:100,ROAD_SPEED:6,OBSTACLE_SPAWN_INTERVAL:2000,COLLISION_TOLERANCE:5,POINTS_PER_OBSTACLE_PASSED:10,LANE_SWITCH_DURATION:200};export const CAR_RACING_COLORS ={ROAD_DARK:'#2a2a2a',ROAD_LIGHT:'#3a3a3a',ROAD_LINE:'#ffffff',GRASS_GREEN:'#2d5016',GRASS_DARK:'#1a3009',SKY_BLUE:'#87ceeb',PLAYER_CAR:'#ff4444',OBSTACLE_CAR_1:'#4444ff',OBSTACLE_CAR_2:'#44ff44',OBSTACLE_CAR_3:'#ffff44',SCORE:'#ffd700',UI:'#ff4444'};export const CAR_RACING_THEME ={backgroundColor:'rgba(0,0,0,0.7)',headerBackgroundColor:'#ff4444',headerTextColor:'#ffffff',sectionBackgroundColor:'rgba(255,68,68,0.15)',sectionTitleColor:'#ff4444',buttonSelectedColor:'#ff4444',buttonUnselectedColor:'rgba(255,255,255,0.2)',buttonSelectedTextColor:'#ffffff',buttonUnselectedTextColor:'rgba(255,255,255,0.7)',switchTrackColorFalse:'rgba(255,68,68,0.3)',switchTrackColorTrue:'#ff4444',switchThumbColor:'#ffffff',infoTextColor:'rgba(255,255,255,0.9)'};export const CAR_RACING_DIFFICULTY_DESCRIPTIONS ={easy:'1 min,slower traffic,relaxed driving',medium:'2 mins,normal traffic speed,balanced challenge',hard:'3 mins,fast traffic,quick reflexes needed!'};export const getLanePosition =(laneIndex,screenWidth)=>{const roadWidth = CAR_RACING_GAME_CONFIG.LANE_WIDTH * CAR_RACING_GAME_CONFIG.ROAD_LANES;const roadStartX =(screenWidth - roadWidth)/ 2;const laneCenterX = roadStartX + laneIndex * CAR_RACING_GAME_CONFIG.LANE_WIDTH + CAR_RACING_GAME_CONFIG.LANE_WIDTH / 2;return laneCenterX - CAR_RACING_GAME_CONFIG.CAR_WIDTH / 2;};
1
+ "use strict";export const CAR_RACING_DIFFICULTY_CONFIG={easy:{gameDuration:60,obstacleSpawnInterval:2500,roadSpeed:4},medium:{gameDuration:120,obstacleSpawnInterval:2e3,roadSpeed:6},hard:{gameDuration:180,obstacleSpawnInterval:1500,roadSpeed:8}};export const getDifficultySettings=e=>CAR_RACING_DIFFICULTY_CONFIG[e];export const DEFAULT_CAR_RACING_SETTINGS={difficulty:"medium",soundEnabled:!0,hapticEnabled:!0,gameDuration:CAR_RACING_DIFFICULTY_CONFIG.medium.gameDuration,obstacleSpawnInterval:CAR_RACING_DIFFICULTY_CONFIG.medium.obstacleSpawnInterval,roadSpeed:CAR_RACING_DIFFICULTY_CONFIG.medium.roadSpeed};export const CAR_RACING_GAME_CONFIG={GAME_DURATION:120,CAR_WIDTH:50,CAR_HEIGHT:80,OBSTACLE_WIDTH:50,OBSTACLE_HEIGHT:80,ROAD_LANES:3,LANE_WIDTH:100,ROAD_SPEED:6,OBSTACLE_SPAWN_INTERVAL:2e3,COLLISION_TOLERANCE:5,POINTS_PER_OBSTACLE_PASSED:10,LANE_SWITCH_DURATION:200};export const CAR_RACING_COLORS={ROAD_DARK:"#2a2a2a",ROAD_LIGHT:"#3a3a3a",ROAD_LINE:"#ffffff",GRASS_GREEN:"#2d5016",GRASS_DARK:"#1a3009",SKY_BLUE:"#87ceeb",PLAYER_CAR:"#ff4444",OBSTACLE_CAR_1:"#4444ff",OBSTACLE_CAR_2:"#44ff44",OBSTACLE_CAR_3:"#ffff44",SCORE:"#ffd700",UI:"#ff4444"};export const CAR_RACING_THEME={backgroundColor:"rgba(0, 0, 0, 0.7)",headerBackgroundColor:"#ff4444",headerTextColor:"#ffffff",sectionBackgroundColor:"rgba(255, 68, 68, 0.15)",sectionTitleColor:"#ff4444",buttonSelectedColor:"#ff4444",buttonUnselectedColor:"rgba(255, 255, 255, 0.2)",buttonSelectedTextColor:"#ffffff",buttonUnselectedTextColor:"rgba(255, 255, 255, 0.7)",switchTrackColorFalse:"rgba(255, 68, 68, 0.3)",switchTrackColorTrue:"#ff4444",switchThumbColor:"#ffffff",infoTextColor:"rgba(255, 255, 255, 0.9)"};export const CAR_RACING_DIFFICULTY_DESCRIPTIONS={easy:"1 min, slower traffic, relaxed driving",medium:"2 mins, normal traffic speed, balanced challenge",hard:"3 mins, fast traffic, quick reflexes needed!"};export const getLanePosition=(e,o)=>(o-300)/2+100*e+50-25;
@@ -1 +1 @@
1
- "use strict";import{Dimensions}from 'react-native';import{useCarRacingStore}from "./CarRacingStore.js";import{CAR_RACING_GAME_CONFIG,CAR_RACING_COLORS,getLanePosition}from "./CarRacingConstants.js";const{width,height}= Dimensions.get('window');export class CarRacingService{obstacleSpawnTimer = null;gameLoopTimer = null;obstacleIdCounter = 0;roadSpeed = CAR_RACING_GAME_CONFIG.ROAD_SPEED;obstacleSpawnInterval = CAR_RACING_GAME_CONFIG.OBSTACLE_SPAWN_INTERVAL;collisionCooldown = new Map();constructor(roadSpeed,obstacleSpawnInterval){if(roadSpeed)this.roadSpeed = roadSpeed;if(obstacleSpawnInterval)this.obstacleSpawnInterval = obstacleSpawnInterval;}setCallbacks(onCollision,onPass){this.onCollision = onCollision;this.onPass = onPass;}startGame(){this.cleanup();this.obstacleIdCounter = 0;this.collisionCooldown.clear();this.startObstacleSpawning();this.gameLoopTimer = setInterval(()=>{this.updateGameState();},16);}stopGame(){this.cleanup();}updateGameState(){const store = useCarRacingStore.getState();const{obstacles,playerCar,isPlaying}= store;if(!isPlaying)return;const newRoadOffset =(store.roadOffset + this.roadSpeed)% 100;store.updateRoadOffset(newRoadOffset);for(let i = 0;i < obstacles.length;i++){const obstacle = obstacles[i];if(!obstacle)continue;const newY = obstacle.y + this.roadSpeed;if(newY > height + 50){store.removeObstacle(obstacle.id);continue;}if(!obstacle.passed && newY > playerCar.y + playerCar.height){store.markObstaclePassed(obstacle.id);if(this.onPass){this.onPass();}}store.updateObstacle(obstacle.id,{y:newY});this.checkCollision(obstacle,playerCar);}}checkCollision(obstacle,playerCar){const store = useCarRacingStore.getState();const cooldownTime = this.collisionCooldown.get(obstacle.id);if(cooldownTime && Date.now()- cooldownTime < 1000){return;}const tolerance = CAR_RACING_GAME_CONFIG.COLLISION_TOLERANCE;const collision = playerCar.x < obstacle.x + obstacle.width - tolerance && playerCar.x + playerCar.width > obstacle.x + tolerance && playerCar.y < obstacle.y + obstacle.height - tolerance && playerCar.y + playerCar.height > obstacle.y + tolerance;if(collision){this.collisionCooldown.set(obstacle.id,Date.now());const collisionX =(playerCar.x + playerCar.width / 2 + obstacle.x + obstacle.width / 2)/ 2;const collisionY =(playerCar.y + playerCar.height / 2 + obstacle.y + obstacle.height / 2)/ 2;store.addParticleEffect(collisionX,collisionY);store.loseLife();store.removeObstacle(obstacle.id);if(this.onCollision){this.onCollision();}}}startObstacleSpawning(){this.obstacleSpawnTimer = setInterval(()=>{this.spawnObstacle();},this.obstacleSpawnInterval);this.spawnObstacle();}spawnObstacle(){const store = useCarRacingStore.getState();if(!store.isPlaying)return;const lane = this.fastRandom(0,CAR_RACING_GAME_CONFIG.ROAD_LANES);const x = getLanePosition(lane,width);const colors = [CAR_RACING_COLORS.OBSTACLE_CAR_1,CAR_RACING_COLORS.OBSTACLE_CAR_2,CAR_RACING_COLORS.OBSTACLE_CAR_3];const colorIndex = this.fastRandom(0,colors.length);const color = colors[colorIndex] || CAR_RACING_COLORS.OBSTACLE_CAR_1;const obstacle ={id:`obstacle-${this.obstacleIdCounter++}`,x:x,y:-CAR_RACING_GAME_CONFIG.OBSTACLE_HEIGHT,lane,width:CAR_RACING_GAME_CONFIG.OBSTACLE_WIDTH,height:CAR_RACING_GAME_CONFIG.OBSTACLE_HEIGHT,color,passed:false};store.addObstacle(obstacle);}fastRandom(min,max){return Math.floor(Math.random()*(max - min))+ min;}movePlayerToLane(lane){const store = useCarRacingStore.getState();if(!store.isPlaying)return;store.movePlayerCar(lane);}cleanup(){if(this.obstacleSpawnTimer){clearInterval(this.obstacleSpawnTimer);this.obstacleSpawnTimer = null;}if(this.gameLoopTimer){clearInterval(this.gameLoopTimer);this.gameLoopTimer = null;}this.collisionCooldown.clear();}}
1
+ "use strict";import{Dimensions as t}from"react-native";import{useCarRacingStore as s}from"./CarRacingStore.js";import{CAR_RACING_GAME_CONFIG as i,CAR_RACING_COLORS as e,getLanePosition as a}from"./CarRacingConstants.js";const{width:n,height:o}=t.get("window");export class CarRacingService{obstacleSpawnTimer=null;gameLoopTimer=null;obstacleIdCounter=0;roadSpeed=i.ROAD_SPEED;obstacleSpawnInterval=i.OBSTACLE_SPAWN_INTERVAL;collisionCooldown=new Map;constructor(t,s){t&&(this.roadSpeed=t),s&&(this.obstacleSpawnInterval=s)}setCallbacks(t,s){this.onCollision=t,this.onPass=s}startGame(){this.cleanup(),this.obstacleIdCounter=0,this.collisionCooldown.clear(),this.startObstacleSpawning(),this.gameLoopTimer=setInterval(()=>{this.updateGameState()},16)}stopGame(){this.cleanup()}updateGameState(){const t=s.getState(),{obstacles:i,playerCar:e,isPlaying:a}=t;if(!a)return;const n=(t.roadOffset+this.roadSpeed)%100;t.updateRoadOffset(n);for(let s=0;s<i.length;s++){const a=i[s];if(!a)continue;const n=a.y+this.roadSpeed;n>o+50?t.removeObstacle(a.id):(!a.passed&&n>e.y+e.height&&(t.markObstaclePassed(a.id),this.onPass&&this.onPass()),t.updateObstacle(a.id,{y:n}),this.checkCollision(a,e))}}checkCollision(t,e){const a=s.getState(),n=this.collisionCooldown.get(t.id);if(n&&1e3>Date.now()-n)return;const o=i.COLLISION_TOLERANCE;if(e.x<t.x+t.width-o&&e.x+e.width>t.x+o&&e.y<t.y+t.height-o&&e.y+e.height>t.y+o){this.collisionCooldown.set(t.id,Date.now());const s=(e.x+e.width/2+t.x+t.width/2)/2,i=(e.y+e.height/2+t.y+t.height/2)/2;a.addParticleEffect(s,i),a.loseLife(),a.removeObstacle(t.id),this.onCollision&&this.onCollision()}}startObstacleSpawning(){this.obstacleSpawnTimer=setInterval(()=>{this.spawnObstacle()},this.obstacleSpawnInterval),this.spawnObstacle()}spawnObstacle(){const t=s.getState();if(!t.isPlaying)return;const o=this.fastRandom(0,i.ROAD_LANES),h=a(o,n),r=[e.OBSTACLE_CAR_1,e.OBSTACLE_CAR_2,e.OBSTACLE_CAR_3],l=r[this.fastRandom(0,r.length)]||e.OBSTACLE_CAR_1,c={id:"obstacle-"+this.obstacleIdCounter++,x:h,y:-i.OBSTACLE_HEIGHT,lane:o,width:i.OBSTACLE_WIDTH,height:i.OBSTACLE_HEIGHT,color:l,passed:!1};t.addObstacle(c)}fastRandom(t,s){return Math.floor(Math.random()*(s-t))+t}movePlayerToLane(t){const i=s.getState();i.isPlaying&&i.movePlayerCar(t)}cleanup(){this.obstacleSpawnTimer&&(clearInterval(this.obstacleSpawnTimer),this.obstacleSpawnTimer=null),this.gameLoopTimer&&(clearInterval(this.gameLoopTimer),this.gameLoopTimer=null),this.collisionCooldown.clear()}}
@@ -1 +1 @@
1
- "use strict";import{create}from 'zustand';import{subscribeWithSelector}from 'zustand/middleware';import{Dimensions}from 'react-native';import{immerMiddleware}from "../../services/UtilsService.js";import{CAR_RACING_GAME_CONFIG,getLanePosition}from "./CarRacingConstants.js";const{width,height}= Dimensions.get('window');export const useCarRacingStore = create()(subscribeWithSelector(immerMiddleware((set,_get)=>({score:0,timeLeft:CAR_RACING_GAME_CONFIG.GAME_DURATION,isPlaying:false,gameOver:false,lives:3,obstacles:[],playerCar:{x:getLanePosition(1,width),y:height * 0.65,lane:1,width:CAR_RACING_GAME_CONFIG.CAR_WIDTH,height:CAR_RACING_GAME_CONFIG.CAR_HEIGHT},roadOffset:0,particleEffects:[],offset:0,gameDuration:CAR_RACING_GAME_CONFIG.GAME_DURATION,setOffset:offset =>{set(draft =>{draft.offset = offset;const yPosition = offset > 0 ? height * 0.75:height * 0.62;draft.playerCar.y = yPosition;});},startGame:(gameDuration,offset)=>{const duration = gameDuration || CAR_RACING_GAME_CONFIG.GAME_DURATION;set(draft =>{draft.score = 0;draft.timeLeft = duration;draft.gameDuration = duration;draft.isPlaying = true;draft.gameOver = false;draft.lives = 3;draft.obstacles = [];draft.roadOffset = 0;if(offset !== undefined){draft.offset = offset;}const yPosition =(offset !== undefined ? offset:draft.offset)> 0 ? height * 0.75:height * 0.62;draft.playerCar ={x:getLanePosition(1,width),y:yPosition,lane:1,width:CAR_RACING_GAME_CONFIG.CAR_WIDTH,height:CAR_RACING_GAME_CONFIG.CAR_HEIGHT};});},stopGame:()=>{set(draft =>{draft.score = 0;draft.timeLeft = draft.gameDuration;draft.isPlaying = false;draft.gameOver = false;draft.lives = 3;draft.obstacles = [];draft.roadOffset = 0;const yPosition = draft.offset > 0 ? height * 0.75:height * 0.62;draft.playerCar ={x:getLanePosition(1,width),y:yPosition,lane:1,width:CAR_RACING_GAME_CONFIG.CAR_WIDTH,height:CAR_RACING_GAME_CONFIG.CAR_HEIGHT};});},resetGame:()=>{set(draft =>{draft.score = 0;draft.timeLeft = draft.gameDuration;draft.isPlaying = false;draft.gameOver = false;draft.lives = 3;draft.obstacles = [];draft.roadOffset = 0;const yPosition = draft.offset > 0 ? height * 0.75:height * 0.62;draft.playerCar ={x:getLanePosition(1,width),y:yPosition,lane:1,width:CAR_RACING_GAME_CONFIG.CAR_WIDTH,height:CAR_RACING_GAME_CONFIG.CAR_HEIGHT};});},updateScore:points =>{set(draft =>{draft.score = draft.score + points;});},decrementTime:()=>{set(draft =>{const newTimeLeft = draft.timeLeft - 1;if(newTimeLeft <= 0){draft.timeLeft = 0;draft.isPlaying = false;draft.gameOver = true;}else{draft.timeLeft = newTimeLeft;}});},addObstacle:obstacle =>{set(draft =>{draft.obstacles.push(obstacle);});},removeObstacle:obstacleId =>{set(draft =>{draft.obstacles = draft.obstacles.filter(o => o.id !== obstacleId);});},updateObstacle:(obstacleId,updates)=>{set(draft =>{for(let i = 0;i < draft.obstacles.length;i++){if(draft.obstacles[i].id === obstacleId){Object.assign(draft.obstacles[i],updates);break;}}});},movePlayerCar:lane =>{set(draft =>{const validLane = Math.max(0,Math.min(CAR_RACING_GAME_CONFIG.ROAD_LANES - 1,lane));draft.playerCar.lane = validLane;draft.playerCar.x = getLanePosition(validLane,width);});},updateRoadOffset:offset =>{set(draft =>{draft.roadOffset = offset;});},markObstaclePassed:obstacleId =>{set(draft =>{for(let i = 0;i < draft.obstacles.length;i++){if(draft.obstacles[i].id === obstacleId && !draft.obstacles[i].passed){draft.obstacles[i].passed = true;draft.score = draft.score + CAR_RACING_GAME_CONFIG.POINTS_PER_OBSTACLE_PASSED;break;}}});},loseLife:()=>{set(draft =>{const newLives = draft.lives - 1;if(newLives <= 0){draft.lives = 0;draft.isPlaying = false;draft.gameOver = true;}else{draft.lives = newLives;}});},clearObstacles:()=>{set(draft =>{draft.obstacles = [];});},addParticleEffect:(x,y)=>{set(draft =>{draft.particleEffects.push({id:`particle-${Date.now()}-${Math.random()}`,x,y});});},removeParticleEffect:effectId =>{set(draft =>{draft.particleEffects = draft.particleEffects.filter(e => e.id !== effectId);});}}))));export const useScore =()=> useCarRacingStore(state => state.score);export const useTimeLeft =()=> useCarRacingStore(state => state.timeLeft);export const useLives =()=> useCarRacingStore(state => state.lives);export const useIsPlaying =()=> useCarRacingStore(state => state.isPlaying);export const useGameOver =()=> useCarRacingStore(state => state.gameOver);export const useObstacles =()=> useCarRacingStore(state => state.obstacles);export const usePlayerCar =()=> useCarRacingStore(state => state.playerCar);export const useRoadOffset =()=> useCarRacingStore(state => state.roadOffset);export const useParticleEffects =()=> useCarRacingStore(state => state.particleEffects);
1
+ "use strict";import{create as e}from"zustand";import{subscribeWithSelector as t}from"zustand/middleware";import{Dimensions as s}from"react-native";import{immerMiddleware as a}from"../../services/UtilsService.js";import{CAR_RACING_GAME_CONFIG as r,getLanePosition as o}from"./CarRacingConstants.js";const{width:c,height:i}=s.get("window");export const useCarRacingStore=e()(t(a((e,t)=>({score:0,timeLeft:r.GAME_DURATION,isPlaying:!1,gameOver:!1,lives:3,obstacles:[],playerCar:{x:o(1,c),y:.65*i,lane:1,width:r.CAR_WIDTH,height:r.CAR_HEIGHT},roadOffset:0,particleEffects:[],offset:0,gameDuration:r.GAME_DURATION,setOffset:t=>{e(e=>{e.offset=t;const s=t>0?.75*i:.62*i;e.playerCar.y=s})},startGame:(t,s)=>{const a=t||r.GAME_DURATION;e(e=>{e.score=0,e.timeLeft=a,e.gameDuration=a,e.isPlaying=!0,e.gameOver=!1,e.lives=3,e.obstacles=[],e.roadOffset=0,void 0!==s&&(e.offset=s);const t=(void 0!==s?s:e.offset)>0?.75*i:.62*i;e.playerCar={x:o(1,c),y:t,lane:1,width:r.CAR_WIDTH,height:r.CAR_HEIGHT}})},stopGame:()=>{e(e=>{e.score=0,e.timeLeft=e.gameDuration,e.isPlaying=!1,e.gameOver=!1,e.lives=3,e.obstacles=[],e.roadOffset=0;const t=e.offset>0?.75*i:.62*i;e.playerCar={x:o(1,c),y:t,lane:1,width:r.CAR_WIDTH,height:r.CAR_HEIGHT}})},resetGame:()=>{e(e=>{e.score=0,e.timeLeft=e.gameDuration,e.isPlaying=!1,e.gameOver=!1,e.lives=3,e.obstacles=[],e.roadOffset=0;const t=e.offset>0?.75*i:.62*i;e.playerCar={x:o(1,c),y:t,lane:1,width:r.CAR_WIDTH,height:r.CAR_HEIGHT}})},updateScore:t=>{e(e=>{e.score=e.score+t})},decrementTime:()=>{e(e=>{const t=e.timeLeft-1;t>0?e.timeLeft=t:(e.timeLeft=0,e.isPlaying=!1,e.gameOver=!0)})},addObstacle:t=>{e(e=>{e.obstacles.push(t)})},removeObstacle:t=>{e(e=>{e.obstacles=e.obstacles.filter(e=>e.id!==t)})},updateObstacle:(t,s)=>{e(e=>{for(let a=0;a<e.obstacles.length;a++)if(e.obstacles[a].id===t){Object.assign(e.obstacles[a],s);break}})},movePlayerCar:t=>{e(e=>{const s=Math.max(0,Math.min(r.ROAD_LANES-1,t));e.playerCar.lane=s,e.playerCar.x=o(s,c)})},updateRoadOffset:t=>{e(e=>{e.roadOffset=t})},markObstaclePassed:t=>{e(e=>{for(let s=0;s<e.obstacles.length;s++)if(e.obstacles[s].id===t&&!e.obstacles[s].passed){e.obstacles[s].passed=!0,e.score=e.score+r.POINTS_PER_OBSTACLE_PASSED;break}})},loseLife:()=>{e(e=>{const t=e.lives-1;t>0?e.lives=t:(e.lives=0,e.isPlaying=!1,e.gameOver=!0)})},clearObstacles:()=>{e(e=>{e.obstacles=[]})},addParticleEffect:(t,s)=>{e(e=>{e.particleEffects.push({id:`particle-${Date.now()}-${Math.random()}`,x:t,y:s})})},removeParticleEffect:t=>{e(e=>{e.particleEffects=e.particleEffects.filter(e=>e.id!==t)})}}))));export const useScore=()=>useCarRacingStore(e=>e.score);export const useTimeLeft=()=>useCarRacingStore(e=>e.timeLeft);export const useLives=()=>useCarRacingStore(e=>e.lives);export const useIsPlaying=()=>useCarRacingStore(e=>e.isPlaying);export const useGameOver=()=>useCarRacingStore(e=>e.gameOver);export const useObstacles=()=>useCarRacingStore(e=>e.obstacles);export const usePlayerCar=()=>useCarRacingStore(e=>e.playerCar);export const useRoadOffset=()=>useCarRacingStore(e=>e.roadOffset);export const useParticleEffects=()=>useCarRacingStore(e=>e.particleEffects);
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{Canvas,RoundedRect,Rect,Circle,LinearGradient,vec}from '@shopify/react-native-skia';import Animated,{useAnimatedStyle,withSpring}from 'react-native-reanimated';import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";export const CarComponent = React.memo(({x,y,width,height,color,isPlayer = false})=>{const animatedStyle = useAnimatedStyle(()=>{if(isPlayer){return{transform:[{translateX:withSpring(x,{damping:25,stiffness:150,mass:0.8})},{translateY:y}]};}return{transform:[{translateX:x},{translateY:y}]};},[x,y,isPlayer]);return _jsx(Animated.View,{style:[{position:'absolute',width,height},animatedStyle],children:_jsxs(Canvas,{style:{width,height},children:[_jsx(RoundedRect,{x:width * 0.05,y:0,width:width * 0.9,height:height * 0.12,r:4,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width,0),colors:[adjustBrightness(color,-30),adjustBrightness(color,-40)]})}),_jsx(RoundedRect,{x:0,y:height * 0.1,width:width,height:height * 0.25,r:6,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width,0),colors:[color,adjustBrightness(color,-15),color]})}),_jsx(RoundedRect,{x:width * 0.12,y:height * 0.32,width:width * 0.76,height:height * 0.12,r:4,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(0,height * 0.12),colors:['rgba(100,150,200,0.7)','rgba(50,100,150,0.8)']})}),_jsx(RoundedRect,{x:width * 0.08,y:height * 0.42,width:width * 0.84,height:height * 0.22,r:5,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width,0),colors:[adjustBrightness(color,10),color,adjustBrightness(color,10)]})}),_jsx(Rect,{x:width * 0.12,y:height * 0.45,width:width * 0.25,height:height * 0.16,color:"rgba(50,100,150,0.75)"}),_jsx(Rect,{x:width * 0.63,y:height * 0.45,width:width * 0.25,height:height * 0.16,color:"rgba(50,100,150,0.75)"}),_jsx(RoundedRect,{x:width * 0.12,y:height * 0.62,width:width * 0.76,height:height * 0.1,r:4,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(0,height * 0.1),colors:['rgba(50,100,150,0.8)','rgba(100,150,200,0.7)']})}),_jsx(RoundedRect,{x:0,y:height * 0.7,width:width,height:height * 0.2,r:6,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width,0),colors:[color,adjustBrightness(color,-15),color]})}),_jsx(RoundedRect,{x:width * 0.05,y:height * 0.88,width:width * 0.9,height:height * 0.12,r:4,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width,0),colors:[adjustBrightness(color,-30),adjustBrightness(color,-40)]})}),_jsx(RoundedRect,{x:-width * 0.09,y:height * 0.17,width:width * 0.2,height:height * 0.22,r:3,color:"#ffffff"}),_jsx(RoundedRect,{x:-width * 0.08,y:height * 0.18,width:width * 0.18,height:height * 0.2,r:3,color:"#000000"}),_jsx(RoundedRect,{x:-width * 0.06,y:height * 0.2,width:width * 0.14,height:height * 0.16,r:2,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width * 0.14,0),colors:['#8a8a8a','#c0c0c0','#8a8a8a']})}),_jsx(RoundedRect,{x:-width * 0.04,y:height * 0.24,width:width * 0.08,height:height * 0.08,r:1,color:"#4a4a4a"}),_jsx(RoundedRect,{x:width * 0.89,y:height * 0.17,width:width * 0.2,height:height * 0.22,r:3,color:"#ffffff"}),_jsx(RoundedRect,{x:width * 0.9,y:height * 0.18,width:width * 0.18,height:height * 0.2,r:3,color:"#000000"}),_jsx(RoundedRect,{x:width * 0.92,y:height * 0.2,width:width * 0.14,height:height * 0.16,r:2,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width * 0.14,0),colors:['#8a8a8a','#c0c0c0','#8a8a8a']})}),_jsx(RoundedRect,{x:width * 0.96,y:height * 0.24,width:width * 0.08,height:height * 0.08,r:1,color:"#4a4a4a"}),_jsx(RoundedRect,{x:-width * 0.09,y:height * 0.61,width:width * 0.2,height:height * 0.22,r:3,color:"#ffffff"}),_jsx(RoundedRect,{x:-width * 0.08,y:height * 0.62,width:width * 0.18,height:height * 0.2,r:3,color:"#000000"}),_jsx(RoundedRect,{x:-width * 0.06,y:height * 0.64,width:width * 0.14,height:height * 0.16,r:2,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width * 0.14,0),colors:['#8a8a8a','#c0c0c0','#8a8a8a']})}),_jsx(RoundedRect,{x:-width * 0.04,y:height * 0.68,width:width * 0.08,height:height * 0.08,r:1,color:"#4a4a4a"}),_jsx(RoundedRect,{x:width * 0.89,y:height * 0.61,width:width * 0.2,height:height * 0.22,r:3,color:"#ffffff"}),_jsx(RoundedRect,{x:width * 0.9,y:height * 0.62,width:width * 0.18,height:height * 0.2,r:3,color:"#000000"}),_jsx(RoundedRect,{x:width * 0.92,y:height * 0.64,width:width * 0.14,height:height * 0.16,r:2,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width * 0.14,0),colors:['#8a8a8a','#c0c0c0','#8a8a8a']})}),_jsx(RoundedRect,{x:width * 0.96,y:height * 0.68,width:width * 0.08,height:height * 0.08,r:1,color:"#4a4a4a"}),_jsx(RoundedRect,{x:-width * 0.05,y:height * 0.4,width:width * 0.12,height:height * 0.08,r:2,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width * 0.12,0),colors:[adjustBrightness(color,-20),color]})}),_jsx(RoundedRect,{x:width * 0.93,y:height * 0.4,width:width * 0.12,height:height * 0.08,r:2,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(width * 0.12,0),colors:[color,adjustBrightness(color,-20)]})}),_jsx(Circle,{cx:width * 0.2,cy:height * 0.06,r:width * 0.1,color:isPlayer ? '#ffff99':'#ffffcc'}),_jsx(Circle,{cx:width * 0.8,cy:height * 0.06,r:width * 0.1,color:isPlayer ? '#ffff99':'#ffffcc'}),_jsx(Circle,{cx:width * 0.2,cy:height * 0.06,r:width * 0.06,color:isPlayer ? '#ffffff':'#ffffe0'}),_jsx(Circle,{cx:width * 0.8,cy:height * 0.06,r:width * 0.06,color:isPlayer ? '#ffffff':'#ffffe0'}),_jsx(RoundedRect,{x:width * 0.12,y:height * 0.94,width:width * 0.15,height:height * 0.05,r:2,color:"#ff3333"}),_jsx(RoundedRect,{x:width * 0.73,y:height * 0.94,width:width * 0.15,height:height * 0.05,r:2,color:"#ff3333"}),_jsx(Rect,{x:width * 0.45,y:height * 0.12,width:width * 0.1,height:height * 0.22,color:"rgba(255,255,255,0.15)"}),_jsx(RoundedRect,{x:width * 0.2,y:height * 0.46,width:width * 0.6,height:height * 0.06,r:3,color:"rgba(255,255,255,0.25)"}),_jsx(Rect,{x:width * 0.38,y:height * 0.42,width:width * 0.02,height:height * 0.22,color:"rgba(0,0,0,0.3)"}),_jsx(Rect,{x:width * 0.6,y:height * 0.42,width:width * 0.02,height:height * 0.22,color:"rgba(0,0,0,0.3)"})]})});});CarComponent.displayName = 'CarComponent';const arePropsEqual =(prevProps,nextProps)=>{return prevProps.x === nextProps.x && prevProps.y === nextProps.y && prevProps.width === nextProps.width && prevProps.height === nextProps.height && prevProps.color === nextProps.color && prevProps.isPlayer === nextProps.isPlayer;};export const MemoizedCarComponent = React.memo(CarComponent,arePropsEqual);function adjustBrightness(color,amount){const hex = color.replace('#','');const r = Math.max(0,Math.min(255,parseInt(hex.substring(0,2),16)+ amount));const g = Math.max(0,Math.min(255,parseInt(hex.substring(2,4),16)+ amount));const b = Math.max(0,Math.min(255,parseInt(hex.substring(4,6),16)+ amount));return `#${r.toString(16).padStart(2,'0')}${g.toString(16).padStart(2,'0')}${b.toString(16).padStart(2,'0')}`;}
1
+ "use strict";import t from"react";import{Canvas as r,RoundedRect as h,Rect as o,Circle as i,LinearGradient as e,vec as a}from"@shopify/react-native-skia";import c,{useAnimatedStyle as f,withSpring as d}from"react-native-reanimated";import{jsx as n,jsxs as l}from"react/jsx-runtime";export const CarComponent=t.memo(({x:t,y:s,width:x,height:y,color:w,isPlayer:m=!1})=>{const p=f(()=>m?{transform:[{translateX:d(t,{damping:25,stiffness:150,mass:.8})},{translateY:s}]}:{transform:[{translateX:t},{translateY:s}]},[t,s,m]);return n(c.View,{style:[{position:"absolute",width:x,height:y},p],children:l(r,{style:{width:x,height:y},children:[n(h,{x:.05*x,y:0,width:.9*x,height:.12*y,r:4,children:n(e,{start:a(0,0),end:a(x,0),colors:[g(w,-30),g(w,-40)]})}),n(h,{x:0,y:.1*y,width:x,height:.25*y,r:6,children:n(e,{start:a(0,0),end:a(x,0),colors:[w,g(w,-15),w]})}),n(h,{x:.12*x,y:.32*y,width:.76*x,height:.12*y,r:4,children:n(e,{start:a(0,0),end:a(0,.12*y),colors:["rgba(100, 150, 200, 0.7)","rgba(50, 100, 150, 0.8)"]})}),n(h,{x:.08*x,y:.42*y,width:.84*x,height:.22*y,r:5,children:n(e,{start:a(0,0),end:a(x,0),colors:[g(w,10),w,g(w,10)]})}),n(o,{x:.12*x,y:.45*y,width:.25*x,height:.16*y,color:"rgba(50, 100, 150, 0.75)"}),n(o,{x:.63*x,y:.45*y,width:.25*x,height:.16*y,color:"rgba(50, 100, 150, 0.75)"}),n(h,{x:.12*x,y:.62*y,width:.76*x,height:.1*y,r:4,children:n(e,{start:a(0,0),end:a(0,.1*y),colors:["rgba(50, 100, 150, 0.8)","rgba(100, 150, 200, 0.7)"]})}),n(h,{x:0,y:.7*y,width:x,height:.2*y,r:6,children:n(e,{start:a(0,0),end:a(x,0),colors:[w,g(w,-15),w]})}),n(h,{x:.05*x,y:.88*y,width:.9*x,height:.12*y,r:4,children:n(e,{start:a(0,0),end:a(x,0),colors:[g(w,-30),g(w,-40)]})}),n(h,{x:.09*-x,y:.17*y,width:.2*x,height:.22*y,r:3,color:"#ffffff"}),n(h,{x:.08*-x,y:.18*y,width:.18*x,height:.2*y,r:3,color:"#000000"}),n(h,{x:.06*-x,y:.2*y,width:.14*x,height:.16*y,r:2,children:n(e,{start:a(0,0),end:a(.14*x,0),colors:["#8a8a8a","#c0c0c0","#8a8a8a"]})}),n(h,{x:.04*-x,y:.24*y,width:.08*x,height:.08*y,r:1,color:"#4a4a4a"}),n(h,{x:.89*x,y:.17*y,width:.2*x,height:.22*y,r:3,color:"#ffffff"}),n(h,{x:.9*x,y:.18*y,width:.18*x,height:.2*y,r:3,color:"#000000"}),n(h,{x:.92*x,y:.2*y,width:.14*x,height:.16*y,r:2,children:n(e,{start:a(0,0),end:a(.14*x,0),colors:["#8a8a8a","#c0c0c0","#8a8a8a"]})}),n(h,{x:.96*x,y:.24*y,width:.08*x,height:.08*y,r:1,color:"#4a4a4a"}),n(h,{x:.09*-x,y:.61*y,width:.2*x,height:.22*y,r:3,color:"#ffffff"}),n(h,{x:.08*-x,y:.62*y,width:.18*x,height:.2*y,r:3,color:"#000000"}),n(h,{x:.06*-x,y:.64*y,width:.14*x,height:.16*y,r:2,children:n(e,{start:a(0,0),end:a(.14*x,0),colors:["#8a8a8a","#c0c0c0","#8a8a8a"]})}),n(h,{x:.04*-x,y:.68*y,width:.08*x,height:.08*y,r:1,color:"#4a4a4a"}),n(h,{x:.89*x,y:.61*y,width:.2*x,height:.22*y,r:3,color:"#ffffff"}),n(h,{x:.9*x,y:.62*y,width:.18*x,height:.2*y,r:3,color:"#000000"}),n(h,{x:.92*x,y:.64*y,width:.14*x,height:.16*y,r:2,children:n(e,{start:a(0,0),end:a(.14*x,0),colors:["#8a8a8a","#c0c0c0","#8a8a8a"]})}),n(h,{x:.96*x,y:.68*y,width:.08*x,height:.08*y,r:1,color:"#4a4a4a"}),n(h,{x:.05*-x,y:.4*y,width:.12*x,height:.08*y,r:2,children:n(e,{start:a(0,0),end:a(.12*x,0),colors:[g(w,-20),w]})}),n(h,{x:.93*x,y:.4*y,width:.12*x,height:.08*y,r:2,children:n(e,{start:a(0,0),end:a(.12*x,0),colors:[w,g(w,-20)]})}),n(i,{cx:.2*x,cy:.06*y,r:.1*x,color:m?"#ffff99":"#ffffcc"}),n(i,{cx:.8*x,cy:.06*y,r:.1*x,color:m?"#ffff99":"#ffffcc"}),n(i,{cx:.2*x,cy:.06*y,r:.06*x,color:m?"#ffffff":"#ffffe0"}),n(i,{cx:.8*x,cy:.06*y,r:.06*x,color:m?"#ffffff":"#ffffe0"}),n(h,{x:.12*x,y:.94*y,width:.15*x,height:.05*y,r:2,color:"#ff3333"}),n(h,{x:.73*x,y:.94*y,width:.15*x,height:.05*y,r:2,color:"#ff3333"}),n(o,{x:.45*x,y:.12*y,width:.1*x,height:.22*y,color:"rgba(255, 255, 255, 0.15)"}),n(h,{x:.2*x,y:.46*y,width:.6*x,height:.06*y,r:3,color:"rgba(255, 255, 255, 0.25)"}),n(o,{x:.38*x,y:.42*y,width:.02*x,height:.22*y,color:"rgba(0, 0, 0, 0.3)"}),n(o,{x:.6*x,y:.42*y,width:.02*x,height:.22*y,color:"rgba(0, 0, 0, 0.3)"})]})})});CarComponent.displayName="CarComponent";const s=(t,r)=>t.x===r.x&&t.y===r.y&&t.width===r.width&&t.height===r.height&&t.color===r.color&&t.isPlayer===r.isPlayer;export const MemoizedCarComponent=t.memo(CarComponent,s);function g(t,r){const h=t.replace("#",""),o=Math.max(0,Math.min(255,parseInt(h.substring(0,2),16)+r)),i=Math.max(0,Math.min(255,parseInt(h.substring(2,4),16)+r)),e=Math.max(0,Math.min(255,parseInt(h.substring(4,6),16)+r));return`#${o.toString(16).padStart(2,"0")}${i.toString(16).padStart(2,"0")}${e.toString(16).padStart(2,"0")}`}
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{Canvas,Rect,LinearGradient,vec,Line}from '@shopify/react-native-skia';import{CAR_RACING_COLORS,CAR_RACING_GAME_CONFIG}from "../CarRacingConstants.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";const GameBackgroundComponent =({width,height,roadOffset})=>{const roadWidth = CAR_RACING_GAME_CONFIG.LANE_WIDTH * CAR_RACING_GAME_CONFIG.ROAD_LANES;const roadStartX =(width - roadWidth)/ 2;const grassWidth = roadStartX;const lineSpacing = 40;const lineHeight = 30;const lineOffset = roadOffset % lineSpacing;return _jsxs(Canvas,{style:{width,height},children:[_jsx(Rect,{x:0,y:0,width:width,height:height,children:_jsx(LinearGradient,{start:vec(width / 2,0),end:vec(width / 2,height),colors:[CAR_RACING_COLORS.SKY_BLUE,'#b0e0e6']})}),_jsx(Rect,{x:0,y:0,width:grassWidth,height:height,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(grassWidth,0),colors:[CAR_RACING_COLORS.GRASS_DARK,CAR_RACING_COLORS.GRASS_GREEN]})}),_jsx(Rect,{x:roadStartX + roadWidth,y:0,width:grassWidth,height:height,children:_jsx(LinearGradient,{start:vec(0,0),end:vec(grassWidth,0),colors:[CAR_RACING_COLORS.GRASS_GREEN,CAR_RACING_COLORS.GRASS_DARK]})}),_jsx(Rect,{x:roadStartX,y:0,width:roadWidth,height:height,color:CAR_RACING_COLORS.ROAD_DARK}),[1,2].map(laneIndex =>{const lineX = roadStartX + laneIndex * CAR_RACING_GAME_CONFIG.LANE_WIDTH;const numLines = Math.ceil(height / lineSpacing)+ 1;return _jsx(React.Fragment,{children:Array.from({length:numLines}).map((_,i)=>{const y = i * lineSpacing - lineOffset;return _jsx(Line,{p1:vec(lineX,y),p2:vec(lineX,y + lineHeight),color:CAR_RACING_COLORS.ROAD_LINE,strokeWidth:3},`line-${laneIndex}-${i}`);})},`lane-${laneIndex}`);}),_jsx(Line,{p1:vec(roadStartX,0),p2:vec(roadStartX,height),color:CAR_RACING_COLORS.ROAD_LINE,strokeWidth:4}),_jsx(Line,{p1:vec(roadStartX + roadWidth,0),p2:vec(roadStartX + roadWidth,height),color:CAR_RACING_COLORS.ROAD_LINE,strokeWidth:4})]});};const arePropsEqual =(prevProps,nextProps)=>{return prevProps.width === nextProps.width && prevProps.height === nextProps.height && Math.floor(prevProps.roadOffset / 5)=== Math.floor(nextProps.roadOffset / 5);};export const GameBackground = React.memo(GameBackgroundComponent,arePropsEqual);GameBackground.displayName = 'GameBackground';
1
+ "use strict";import t from"react";import{Canvas as r,Rect as e,LinearGradient as o,vec as h,Line as i}from"@shopify/react-native-skia";import{CAR_RACING_COLORS as s,CAR_RACING_GAME_CONFIG as n}from"../CarRacingConstants.js";import{jsx as a,jsxs as c}from"react/jsx-runtime";const d=({width:d,height:l,roadOffset:m})=>{const p=n.LANE_WIDTH*n.ROAD_LANES,g=(d-p)/2,u=g,x=m%40;return c(r,{style:{width:d,height:l},children:[a(e,{x:0,y:0,width:d,height:l,children:a(o,{start:h(d/2,0),end:h(d/2,l),colors:[s.SKY_BLUE,"#b0e0e6"]})}),a(e,{x:0,y:0,width:u,height:l,children:a(o,{start:h(0,0),end:h(u,0),colors:[s.GRASS_DARK,s.GRASS_GREEN]})}),a(e,{x:g+p,y:0,width:u,height:l,children:a(o,{start:h(0,0),end:h(u,0),colors:[s.GRASS_GREEN,s.GRASS_DARK]})}),a(e,{x:g,y:0,width:p,height:l,color:s.ROAD_DARK}),[1,2].map(r=>{const e=g+r*n.LANE_WIDTH,o=Math.ceil(l/40)+1;return a(t.Fragment,{children:Array.from({length:o}).map((t,o)=>{const n=40*o-x;return a(i,{p1:h(e,n),p2:h(e,n+30),color:s.ROAD_LINE,strokeWidth:3},`line-${r}-${o}`)})},"lane-"+r)}),a(i,{p1:h(g,0),p2:h(g,l),color:s.ROAD_LINE,strokeWidth:4}),a(i,{p1:h(g+p,0),p2:h(g+p,l),color:s.ROAD_LINE,strokeWidth:4})]})},l=(t,r)=>t.width===r.width&&t.height===r.height&&Math.floor(t.roadOffset/5)===Math.floor(r.roadOffset/5);export const GameBackground=t.memo(d,l);GameBackground.displayName="GameBackground";
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{View,Text,StyleSheet}from 'react-native';import{ScoreBoardContainer}from "../../../helpers/index.js";import{CAR_RACING_COLORS}from "../CarRacingConstants.js";import{useScore,useTimeLeft,useLives}from "../CarRacingStore.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";export const ScoreBoard = React.memo(({offset = 0})=>{const score = useScore();const timeLeft = useTimeLeft();const lives = useLives();const formattedTime = React.useMemo(()=>{const mins = Math.floor(timeLeft / 60);const secs = timeLeft % 60;return `${mins.toString().padStart(2,'0')}:${secs.toString().padStart(2,'0')}`;},[timeLeft]);return _jsx(ScoreBoardContainer,{offset:offset,backgroundColor:"rgba(255,68,68,0.4)",borderColor:"rgba(255,68,68,0.4)",children:_jsxs(View,{style:styles.rowContainer,children:[_jsxs(View,{style:styles.scoreSection,children:[_jsx(Text,{style:styles.label,children:"SCORE"}),_jsx(Text,{style:styles.value,children:score})]}),_jsxs(View,{style:styles.timeSection,children:[_jsx(Text,{style:styles.label,children:"TIME"}),_jsx(Text,{style:[styles.value,timeLeft <= 10 && styles.timeWarning],children:formattedTime})]}),_jsxs(View,{style:styles.livesSection,children:[_jsx(Text,{style:styles.label,children:"LIVES"}),_jsx(View,{style:styles.heartsContainer,children:Array.from({length:3}).map((_,index)=> _jsx(Text,{style:styles.heartIcon,children:index < lives ? '❤️':'🖤'},index))})]})]})});});ScoreBoard.displayName = 'ScoreBoard';const styles = StyleSheet.create({rowContainer:{flexDirection:'row',justifyContent:'space-between',alignItems:'center',width:'100%'},scoreSection:{flex:1,alignItems:'center'},timeSection:{flex:1,alignItems:'center'},livesSection:{flex:1,alignItems:'center'},label:{fontSize:16,fontWeight:'bold',color:'#ffffff',marginBottom:4,letterSpacing:0.5},value:{fontSize:25,fontWeight:'bold',color:'#ffffff'},timeWarning:{color:CAR_RACING_COLORS.UI},heartsContainer:{flexDirection:'row',gap:4},heartIcon:{fontSize:22}});
1
+ "use strict";import e from"react";import{View as r,Text as t,StyleSheet as o}from"react-native";import{ScoreBoardContainer as n}from"../../../helpers/index.js";import{CAR_RACING_COLORS as i}from"../CarRacingConstants.js";import{useScore as l,useTimeLeft as c,useLives as s}from"../CarRacingStore.js";import{jsx as a,jsxs as f}from"react/jsx-runtime";export const ScoreBoard=e.memo(({offset:o=0})=>{const i=l(),m=c(),h=s(),g=e.useMemo(()=>{const e=m%60;return`${Math.floor(m/60).toString().padStart(2,"0")}:${e.toString().padStart(2,"0")}`},[m]);return a(n,{offset:o,backgroundColor:"rgba(255, 68, 68, 0.4)",borderColor:"rgba(255, 68, 68, 0.4)",children:f(r,{style:d.rowContainer,children:[f(r,{style:d.scoreSection,children:[a(t,{style:d.label,children:"SCORE"}),a(t,{style:d.value,children:i})]}),f(r,{style:d.timeSection,children:[a(t,{style:d.label,children:"TIME"}),a(t,{style:[d.value,10>=m&&d.timeWarning],children:g})]}),f(r,{style:d.livesSection,children:[a(t,{style:d.label,children:"LIVES"}),a(r,{style:d.heartsContainer,children:Array.from({length:3}).map((e,r)=>a(t,{style:d.heartIcon,children:h>r?"\u2764\ufe0f":"\ud83d\udda4"},r))})]})]})})});ScoreBoard.displayName="ScoreBoard";const d=o.create({rowContainer:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",width:"100%"},scoreSection:{flex:1,alignItems:"center"},timeSection:{flex:1,alignItems:"center"},livesSection:{flex:1,alignItems:"center"},label:{fontSize:16,fontWeight:"bold",color:"#ffffff",marginBottom:4,letterSpacing:.5},value:{fontSize:25,fontWeight:"bold",color:"#ffffff"},timeWarning:{color:i.UI},heartsContainer:{flexDirection:"row",gap:4},heartIcon:{fontSize:22}});
@@ -1 +1 @@
1
- "use strict";export{GameBackground}from "./GameBackground.js";export{CarComponent}from "./CarComponent.js";export{ScoreBoard}from "./ScoreBoard.js";
1
+ "use strict";export{GameBackground}from"./GameBackground.js";export{CarComponent}from"./CarComponent.js";export{ScoreBoard}from"./ScoreBoard.js";
@@ -1 +1 @@
1
- "use strict";import React,{useEffect,useCallback,useMemo}from 'react';import{View,StyleSheet}from 'react-native';import{useColorsSortStore,useIsPlaying,useIsGameOver,useTime,useContainers,useSelectedContainerId}from "./ColorsSortStore.js";import{ColorContainer,ScoreBoard,GameBackground}from "./components/index.js";import{GameControlButton,GameOverModal}from "../../helpers/index.js";import{GameSettingsModal}from "../../helpers/index.js";import{COLORS_SORT_COLORS}from "./ColorsSortConstants.js";import{GAME_IDS,DEFAULT_GAME_SETTINGS}from "../../services/UtilsService.js";import{playSound,GAME_SOUNDS}from "../../services/SoundsService.js";import{playHaptic,HapticType}from "../../services/HapticsService.js";import{formatTime,getGridLayout}from "./ColorsSortService.js";import{calculateTimeBasedScore}from "../../services/ScoringService.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";export const ColorsSort = React.memo(({settings = DEFAULT_GAME_SETTINGS,onSettingsChange,onEndGame})=>{const isPlaying = useIsPlaying();const isGameOver = useIsGameOver();const time = useTime();const containers = useContainers();const selectedContainerId = useSelectedContainerId();const gameReportedRef = React.useRef(false);const reportGameEnd = React.useCallback(status =>{if(onEndGame && !gameReportedRef.current){const expectedTimes ={easy:60,medium:120,hard:180};const expectedTime = expectedTimes[settings.difficulty];const calculatedScore = status === 'win' ? calculateTimeBasedScore(time,expectedTime):0;onEndGame({status,score:calculatedScore.toString()});gameReportedRef.current = true;}},[onEndGame,time,settings.difficulty]);const initializeGame = useColorsSortStore(state => state.initializeGame);const startGame = useColorsSortStore(state => state.startGame);const stopGame = useColorsSortStore(state => state.stopGame);const resetGame = useColorsSortStore(state => state.resetGame);const selectContainer = useColorsSortStore(state => state.selectContainer);const difficulty = settings.difficulty;const gridStyle = useMemo(()=> getGridLayout(difficulty),[difficulty]);useEffect(()=>{initializeGame(difficulty);},[difficulty,initializeGame]);useEffect(()=>{if(isGameOver && !gameReportedRef.current){reportGameEnd('win');}if(!isGameOver){gameReportedRef.current = false;}},[isGameOver,reportGameEnd]);const handleStartGame = useCallback(()=>{gameReportedRef.current = false;initializeGame(difficulty);startGame();playSound(GAME_SOUNDS.COLORS_SORT.START,settings.enableSounds);playHaptic(HapticType.MEDIUM,settings.enableHaptics);},[difficulty,initializeGame,startGame,settings.enableSounds,settings.enableHaptics]);const handleStopGame = useCallback(()=>{reportGameEnd('cancel');stopGame();},[stopGame,reportGameEnd]);const handleResetGame = useCallback(()=>{resetGame();initializeGame(difficulty);},[resetGame,initializeGame,difficulty]);const handleContainerPress = useCallback(containerId =>{if(!isPlaying || isGameOver)return;selectContainer(containerId,settings);},[isPlaying,isGameOver,selectContainer,settings]);const gameControlButtonProps = useMemo(()=>({isPlaying,gameOver:isGameOver,onStartGame:handleStartGame,onStopGame:handleStopGame,startButtonText:"START SORTING",stopButtonText:"STOP GAME",startButtonSubtext:"Sort colors!",startButtonColor:COLORS_SORT_COLORS.BUTTON_PRIMARY,startButtonBorderColor:COLORS_SORT_COLORS.BUTTON_SECONDARY}),[isPlaying,isGameOver,handleStartGame,handleStopGame]);const gameOverModalProps = useMemo(()=>({isVisible:isGameOver,score:time,onPlayAgain:handleResetGame,buttonText:"Sort Again!",primaryColor:"rgba(255,107,53,0.5)",borderColor:"rgba(255,107,53,0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:"#FF6B35",scoreLabel:"Completion Time",scoreFormatter:formatTime}),[isGameOver,time,handleResetGame]);const gameSettingsModalProps = useMemo(()=>({gameId:GAME_IDS.COLORS_SORT,settings,onSettingsChange}),[settings,onSettingsChange]);const offset = settings?.offset ?? 0;const dynamicStyles = useMemo(()=>({gameArea:{...styles.gameArea,paddingTop:100 + offset}}),[offset]);return _jsx(GameBackground,{children:_jsxs(View,{style:styles.container,children:[_jsx(ScoreBoard,{offset:offset}),_jsx(View,{style:dynamicStyles.gameArea,children:_jsx(View,{style:[styles.containersGrid,gridStyle],children:containers.map(container => _jsx(ColorContainer,{container:container,isSelected:selectedContainerId === container.id,onPress:()=> handleContainerPress(container.id),difficulty:difficulty},container.id))})}),_jsx(GameControlButton,{...gameControlButtonProps}),_jsx(GameOverModal,{...gameOverModalProps}),_jsx(GameSettingsModal,{...gameSettingsModalProps})]})});});const styles = StyleSheet.create({container:{flex:1},gameArea:{flex:1,justifyContent:'center',alignItems:'center',paddingTop:100,paddingBottom:120},containersGrid:{flexDirection:'row',flexWrap:'wrap',justifyContent:'center',alignItems:'flex-end',gap:15,paddingHorizontal:10}});ColorsSort.displayName = 'ColorsSort';
1
+ "use strict";import o,{useEffect as t,useCallback as r,useMemo as e}from"react";import{View as s,StyleSheet as n}from"react-native";import{useColorsSortStore as i,useIsPlaying as a,useIsGameOver as m,useTime as c,useContainers as l,useSelectedContainerId as f}from"./ColorsSortStore.js";import{ColorContainer as p,ScoreBoard as d,GameBackground as S}from"./components/index.js";import{GameControlButton as g,GameOverModal as u}from"../../helpers/index.js";import{GameSettingsModal as C}from"../../helpers/index.js";import{COLORS_SORT_COLORS as x}from"./ColorsSortConstants.js";import{GAME_IDS as j,DEFAULT_GAME_SETTINGS as v}from"../../services/UtilsService.js";import{playSound as T,GAME_SOUNDS as b}from"../../services/SoundsService.js";import{playHaptic as y,HapticType as h}from"../../services/HapticsService.js";import{formatTime as B,getGridLayout as A}from"./ColorsSortService.js";import{calculateTimeBasedScore as G}from"../../services/ScoringService.js";import{jsx as w,jsxs as I}from"react/jsx-runtime";export const ColorsSort=o.memo(({settings:n=v,onSettingsChange:F,onEndGame:O})=>{const E=a(),H=m(),R=c(),z=l(),D=f(),L=o.useRef(!1),M=o.useCallback(o=>{if(O&&!L.current){const t={easy:60,medium:120,hard:180}[n.difficulty],r="win"===o?G(R,t):0;O({status:o,score:r.toString()}),L.current=!0}},[O,R,n.difficulty]),N=i(o=>o.initializeGame),U=i(o=>o.startGame),V=i(o=>o.stopGame),W=i(o=>o.resetGame),k=i(o=>o.selectContainer),q=n.difficulty,J=e(()=>A(q),[q]);t(()=>{N(q)},[q,N]),t(()=>{H&&!L.current&&M("win"),H||(L.current=!1)},[H,M]);const K=r(()=>{L.current=!1,N(q),U(),T(b.COLORS_SORT.START,n.enableSounds),y(h.MEDIUM,n.enableHaptics)},[q,N,U,n.enableSounds,n.enableHaptics]),Q=r(()=>{M("cancel"),V()},[V,M]),X=r(()=>{W(),N(q)},[W,N,q]),Y=r(o=>{E&&!H&&k(o,n)},[E,H,k,n]),Z=e(()=>({isPlaying:E,gameOver:H,onStartGame:K,onStopGame:Q,startButtonText:"START SORTING",stopButtonText:"STOP GAME",startButtonSubtext:"Sort colors!",startButtonColor:x.BUTTON_PRIMARY,startButtonBorderColor:x.BUTTON_SECONDARY}),[E,H,K,Q]),$=e(()=>({isVisible:H,score:R,onPlayAgain:X,buttonText:"Sort Again!",primaryColor:"rgba(255, 107, 53, 0.5)",borderColor:"rgba(255, 107, 53, 0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:"#FF6B35",scoreLabel:"Completion Time",scoreFormatter:B}),[H,R,X]),_=e(()=>({gameId:j.COLORS_SORT,settings:n,onSettingsChange:F}),[n,F]),oo=n?.offset??0,to=e(()=>({gameArea:{...P.gameArea,paddingTop:100+oo}}),[oo]);return w(S,{children:I(s,{style:P.container,children:[w(d,{offset:oo}),w(s,{style:to.gameArea,children:w(s,{style:[P.containersGrid,J],children:z.map(o=>w(p,{container:o,isSelected:D===o.id,onPress:()=>Y(o.id),difficulty:q},o.id))})}),w(g,{...Z}),w(u,{...$}),w(C,{..._})]})})});const P=n.create({container:{flex:1},gameArea:{flex:1,justifyContent:"center",alignItems:"center",paddingTop:100,paddingBottom:120},containersGrid:{flexDirection:"row",flexWrap:"wrap",justifyContent:"center",alignItems:"flex-end",gap:15,paddingHorizontal:10}});ColorsSort.displayName="ColorsSort";
@@ -1 +1 @@
1
- "use strict";import{Dimensions}from 'react-native';const{width,height}= Dimensions.get('window');export const COLORS_SORT_COLORS ={BACKGROUND:'#FFF5E6',PIECE_ORANGE:'#FF6B35',PIECE_PINK:'#FF1493',PIECE_GREEN:'#32CD32',PIECE_RED:'#FF4444',PIECE_YELLOW:'#FFD700',PIECE_BLUE:'#4169E1',PIECE_PURPLE:'#9370DB',BASE_SILVER:'#C0C0C0',BASE_DARK:'#A8A8A8',SCREW_WHITE:'#F5F5F5',BUTTON_PRIMARY:'#FF6B35',BUTTON_SECONDARY:'#FF8C42',SCORE_TEXT:'#FFFFFF',SCORE_BACKGROUND:'rgba(255,107,53,0.4)',SCORE_BORDER:'rgba(255,107,53,0.8)',SELECTED_GLOW:'#FFD700'};export const COLORS_SORT_GAME_CONFIG ={SCREEN_WIDTH:width,SCREEN_HEIGHT:height,PIECE_SIZE:50,CONTAINER_SIZE:60,CONTAINER_SPACING:20,PIECE_SPACING:5};export const COLORS_SORT_CONSTANTS ={baseScore:10,moveScore:10,perfectBonus:100};export const PIECE_COLORS = [COLORS_SORT_COLORS.PIECE_RED,COLORS_SORT_COLORS.PIECE_GREEN,COLORS_SORT_COLORS.PIECE_BLUE,COLORS_SORT_COLORS.PIECE_YELLOW,COLORS_SORT_COLORS.PIECE_PURPLE,COLORS_SORT_COLORS.PIECE_ORANGE,COLORS_SORT_COLORS.PIECE_PINK];export const COLORS_SORT_THEME ={backgroundColor:'rgba(0,0,0,0.7)',headerBackgroundColor:'#FF6B35',headerTextColor:'#ffffff',sectionBackgroundColor:'rgba(255,107,53,0.15)',sectionTitleColor:'#FF6B35',buttonSelectedColor:'#FF6B35',buttonUnselectedColor:'rgba(255,255,255,0.2)',buttonSelectedTextColor:'#ffffff',buttonUnselectedTextColor:'rgba(255,255,255,0.7)',switchTrackColorFalse:'rgba(255,107,53,0.3)',switchTrackColorTrue:'#FF6B35',switchThumbColor:'#ffffff',infoTextColor:'rgba(255,255,255,0.9)'};export const COLORS_SORT_DIFFICULTY_DESCRIPTIONS ={easy:'4 containers,3 colors,3 pieces each - Perfect for beginners',medium:'5 containers,4 colors,3 pieces each - Standard challenge',hard:'6 containers,5 colors,4 pieces each - Expert level!'};
1
+ "use strict";import{Dimensions as o}from"react-native";const{width:e,height:E}=o.get("window");export const COLORS_SORT_COLORS={BACKGROUND:"#FFF5E6",PIECE_ORANGE:"#FF6B35",PIECE_PINK:"#FF1493",PIECE_GREEN:"#32CD32",PIECE_RED:"#FF4444",PIECE_YELLOW:"#FFD700",PIECE_BLUE:"#4169E1",PIECE_PURPLE:"#9370DB",BASE_SILVER:"#C0C0C0",BASE_DARK:"#A8A8A8",SCREW_WHITE:"#F5F5F5",BUTTON_PRIMARY:"#FF6B35",BUTTON_SECONDARY:"#FF8C42",SCORE_TEXT:"#FFFFFF",SCORE_BACKGROUND:"rgba(255, 107, 53, 0.4)",SCORE_BORDER:"rgba(255, 107, 53, 0.8)",SELECTED_GLOW:"#FFD700"};export const COLORS_SORT_GAME_CONFIG={SCREEN_WIDTH:e,SCREEN_HEIGHT:E,PIECE_SIZE:50,CONTAINER_SIZE:60,CONTAINER_SPACING:20,PIECE_SPACING:5};export const COLORS_SORT_CONSTANTS={baseScore:10,moveScore:10,perfectBonus:100};export const PIECE_COLORS=["#FF4444","#32CD32","#4169E1","#FFD700","#9370DB","#FF6B35","#FF1493"];export const COLORS_SORT_THEME={backgroundColor:"rgba(0, 0, 0, 0.7)",headerBackgroundColor:"#FF6B35",headerTextColor:"#ffffff",sectionBackgroundColor:"rgba(255, 107, 53, 0.15)",sectionTitleColor:"#FF6B35",buttonSelectedColor:"#FF6B35",buttonUnselectedColor:"rgba(255, 255, 255, 0.2)",buttonSelectedTextColor:"#ffffff",buttonUnselectedTextColor:"rgba(255, 255, 255, 0.7)",switchTrackColorFalse:"rgba(255, 107, 53, 0.3)",switchTrackColorTrue:"#FF6B35",switchThumbColor:"#ffffff",infoTextColor:"rgba(255, 255, 255, 0.9)"};export const COLORS_SORT_DIFFICULTY_DESCRIPTIONS={easy:"4 containers, 3 colors, 3 pieces each - Perfect for beginners",medium:"5 containers, 4 colors, 3 pieces each - Standard challenge",hard:"6 containers, 5 colors, 4 pieces each - Expert level!"};
@@ -1 +1 @@
1
- "use strict";import{Dimensions}from 'react-native';const{width,height}= Dimensions.get('window');export const SORT_COLORS = ['#FF6B35','#FF4444','#FF8C42','#FFD700','#32CD32','#4169E1','#FF1493','#9370DB','#00BCD4','#FFA366','#CDDC39','#E91E63' ];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 const getGridLayout = difficulty =>{switch(difficulty){case 'easy':return{maxWidth:400};case 'medium':return{maxWidth:300};case 'hard':return{maxWidth:300};default:return{maxWidth:400};}};export const getPieceHeight =(difficulty,baseSize)=>{switch(difficulty){case 'easy':return baseSize - 8;case 'medium':return baseSize - 10;case 'hard':return baseSize - 18;default:return baseSize - 10;}};export const generateFloatingBlocks =()=>{const elements = [];const blockCount = 25;for(let i = 0;i < blockCount;i++){const baseX = width / blockCount * i;const baseY = height / blockCount * i;const x = baseX + Math.sin(i * 0.5)* 50 + Math.random()* 100;const y = baseY + Math.cos(i * 0.7)* 60 + Math.random()* 120;const blockSize = 20 + Math.random()* 20;const colorIndex = i % SORT_COLORS.length;const opacity = 0.3 + Math.sin(i)* 0.15;const blockX = Math.max(blockSize / 2,Math.min(width - blockSize,x));const blockY = Math.max(blockSize / 2,Math.min(height - blockSize,y));const color = `${SORT_COLORS[colorIndex]}${Math.floor(opacity * 255).toString(16).padStart(2,'0')}`;let type;if(i % 4 === 0)type = 'square';else if(i % 4 === 1)type = 'rect';else if(i % 4 === 2)type = 'wide';else type = 'circle';elements.push({key:`${type}-${i}`,type,x:blockX,y:blockY,size:blockSize,color});}return elements;};export const getDecorativeBlocks =()=> [{key:'top-left',x:width * 0.08,y:height * 0.12,size:50,r:8,color:`${SORT_COLORS[0]}50`},{key:'bottom-right',x:width * 0.85,y:height * 0.82,size:45,r:7,color:`${SORT_COLORS[3]}50`},{key:'top-right',x:width * 0.82,y:height * 0.18,size:40,r:6,color:`${SORT_COLORS[4]}50`},{key:'bottom-left',x:width * 0.12,y:height * 0.75,size:55,r:9,color:`${SORT_COLORS[5]}50`},{key:'top-center',x:width * 0.47,y:height * 0.08,size:35,r:5,color:`${SORT_COLORS[7]}50`},{key:'middle-left',x:width * 0.15,y:height * 0.47,size:42,r:6,color:`${SORT_COLORS[6]}50`},{key:'middle-right',x:width * 0.75,y:height * 0.57,size:38,r:6,color:`${SORT_COLORS[8]}50`},{key:'bottom-center',x:width * 0.57,y:height * 0.87,size:32,r:5,color:`${SORT_COLORS[1]}50`}];export const getDecorativeCircles =()=> [{key:'circle-1',cx:width * 0.25,cy:height * 0.25,r:18,color:`${SORT_COLORS[10]}45`},{key:'circle-2',cx:width * 0.65,cy:height * 0.35,r:22,color:`${SORT_COLORS[11]}45`},{key:'circle-3',cx:width * 0.35,cy:height * 0.65,r:16,color:`${SORT_COLORS[9]}45`}];export const getGradientColors =()=>({main:[`${SORT_COLORS[0]}30`,`${SORT_COLORS[3]}25`,`${SORT_COLORS[4]}30`,`${SORT_COLORS[5]}25`,`${SORT_COLORS[7]}30` ],overlay:[`${SORT_COLORS[1]}20`,'transparent',`${SORT_COLORS[6]}20`,'transparent',`${SORT_COLORS[8]}20`,'transparent'],diagonal:[`${SORT_COLORS[2]}15`,'transparent',`${SORT_COLORS[10]}15`,'transparent',`${SORT_COLORS[9]}15`,'transparent']});export class ColorSortService{cleanup(){}}
1
+ "use strict";import{Dimensions as e}from"react-native";const{width:t,height:r}=e.get("window");export const SORT_COLORS=["#FF6B35","#FF4444","#FF8C42","#FFD700","#32CD32","#4169E1","#FF1493","#9370DB","#00BCD4","#FFA366","#CDDC39","#E91E63"];export const formatTime=e=>{const t=e%60;return`${Math.floor(e/60).toString().padStart(2,"0")}:${t.toString().padStart(2,"0")}`};export const getGridLayout=e=>{switch(e){case"easy":default:return{maxWidth:400};case"medium":case"hard":return{maxWidth:300}}};export const getPieceHeight=(e,t)=>{switch(e){case"easy":return t-8;case"medium":default:return t-10;case"hard":return t-18}};export const generateFloatingBlocks=()=>{const e=[];for(let o=0;25>o;o++){const c=r/25*o,a=t/25*o+50*Math.sin(.5*o)+100*Math.random(),s=c+60*Math.cos(.7*o)+120*Math.random(),i=20+20*Math.random(),n=o%12,l=.3+.15*Math.sin(o),F=Math.max(i/2,Math.min(t-i,a)),y=Math.max(i/2,Math.min(r-i,s)),h=`${SORT_COLORS[n]}${Math.floor(255*l).toString(16).padStart(2,"0")}`;let x;x=o%4==0?"square":o%4==1?"rect":o%4==2?"wide":"circle",e.push({key:`${x}-${o}`,type:x,x:F,y:y,size:i,color:h})}return e};export const getDecorativeBlocks=()=>[{key:"top-left",x:.08*t,y:.12*r,size:50,r:8,color:"#FF6B3550"},{key:"bottom-right",x:.85*t,y:.82*r,size:45,r:7,color:"#FFD70050"},{key:"top-right",x:.82*t,y:.18*r,size:40,r:6,color:"#32CD3250"},{key:"bottom-left",x:.12*t,y:.75*r,size:55,r:9,color:"#4169E150"},{key:"top-center",x:.47*t,y:.08*r,size:35,r:5,color:"#9370DB50"},{key:"middle-left",x:.15*t,y:.47*r,size:42,r:6,color:"#FF149350"},{key:"middle-right",x:.75*t,y:.57*r,size:38,r:6,color:"#00BCD450"},{key:"bottom-center",x:.57*t,y:.87*r,size:32,r:5,color:"#FF444450"}];export const getDecorativeCircles=()=>[{key:"circle-1",cx:.25*t,cy:.25*r,r:18,color:"#CDDC3945"},{key:"circle-2",cx:.65*t,cy:.35*r,r:22,color:"#E91E6345"},{key:"circle-3",cx:.35*t,cy:.65*r,r:16,color:"#FFA36645"}];export const getGradientColors=()=>({main:["#FF6B3530","#FFD70025","#32CD3230","#4169E125","#9370DB30"],overlay:["#FF444420","transparent","#FF149320","transparent","#00BCD420","transparent"],diagonal:["#FF8C4215","transparent","#CDDC3915","transparent","#FFA36615","transparent"]});export class ColorSortService{cleanup(){}}