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";import React,{useEffect,useMemo,useCallback}from 'react';import{View,StyleSheet}from 'react-native';import{GestureHandlerRootView}from 'react-native-gesture-handler';import{useBalloonBlasterStore}from "./BalloonBlasterStore.js";import{createBalloonBlasterService}from "./BalloonBlasterService.js";import{ScoreBoard,GameArea,GameBackground}from "./components/index.js";import{GameControlButton,GameOverModal,useAnimationTrackers,useGameErrorHandler,GameErrorType}from "../../helpers/index.js";import{GameSettingsModal}from "../../helpers/index.js";import{GAME_IDS,DEFAULT_GAME_SETTINGS}from "../../services/UtilsService.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";export const BalloonBlaster = React.memo(({settings,onSettingsChange,onEndGame})=>{const isPlaying = useBalloonBlasterStore(state => state.isPlaying);const gameOver = useBalloonBlasterStore(state => state.gameOver);const score = useBalloonBlasterStore(state => state.score);const gameReportedRef = React.useRef(false);const reportGameEnd = React.useCallback(status =>{if(onEndGame && !gameReportedRef.current){const currentState = useBalloonBlasterStore.getState();onEndGame({status,score:currentState.score.toString()});gameReportedRef.current = true;}},[onEndGame]);const startGame = useBalloonBlasterStore(state => state.startGame);const stopGame = useBalloonBlasterStore(state => state.stopGame);const resetGame = useBalloonBlasterStore(state => state.resetGame);const decrementTime = useBalloonBlasterStore(state => state.decrementTime);const addBalloon = useBalloonBlasterStore(state => state.addBalloon);const removeBalloon = useBalloonBlasterStore(state => state.removeBalloon);const updateBalloon = useBalloonBlasterStore(state => state.updateBalloon);const{balloonAnimations,particleAnimations}= useAnimationTrackers(['balloonAnimations','particleAnimations']);const{wrapFunction,safeExecute}= useGameErrorHandler(GAME_IDS.BALLOON_BLASTER);const spawnBalloon = useCallback(balloon =>{addBalloon(balloon);},[addBalloon]);const handleResetGame = useCallback(wrapFunction(()=>{resetGame();},GameErrorType.UNKNOWN_ERROR),[wrapFunction,resetGame]);const gameService = useMemo(()=>{return safeExecute(()=> createBalloonBlasterService(balloonAnimations,particleAnimations),createBalloonBlasterService(balloonAnimations,particleAnimations),GameErrorType.INITIALIZATION_ERROR);},[balloonAnimations,particleAnimations,safeExecute]);const handleStartGame = useCallback(wrapFunction(()=>{gameReportedRef.current = false;resetGame();const currentBalloons = useBalloonBlasterStore.getState().balloons;currentBalloons.forEach(balloon => removeBalloon(balloon.id));if(gameService){gameService.cleanup();gameService.resetAnimations();}setTimeout(()=>{startGame();if(gameService){gameService.startGameTimer(decrementTime);gameService.startBalloonSpawning(spawnBalloon,600);gameService.startPhysicsLoop(updateBalloon,removeBalloon,()=> useBalloonBlasterStore.getState().balloons);}},50);},GameErrorType.INITIALIZATION_ERROR),[wrapFunction,resetGame,removeBalloon,gameService,startGame,decrementTime,spawnBalloon,updateBalloon]);const handleStopGame = useCallback(wrapFunction(()=>{reportGameEnd('cancel');stopGame();if(gameService){gameService.cleanup();gameService.resetAnimations();}},GameErrorType.UNKNOWN_ERROR),[wrapFunction,stopGame,gameService,reportGameEnd]);useEffect(()=>{return()=>{handleResetGame();};},[handleResetGame]);useEffect(()=>{if(gameOver && !gameReportedRef.current){const currentState = useBalloonBlasterStore.getState();const status = currentState.lives <= 0 ? 'lose':'win';reportGameEnd(status);}if(!gameOver){gameReportedRef.current = false;}},[gameOver,reportGameEnd]);useEffect(()=>{if(gameOver && gameService){gameService.cleanup();}},[gameOver,gameService]);const gameControlButtonProps = useMemo(()=>({isPlaying,gameOver,onStartGame:handleStartGame,onStopGame:handleStopGame,startButtonText:"START POPPING",stopButtonText:"STOP GAME",startButtonSubtext:"Pop balloons to score!",stopButtonSubtext:"End current game",startButtonColor:"#3b82f6",stopButtonColor:"#dc2626",startButtonBorderColor:"#60a5fa",stopButtonBorderColor:"#f87171"}),[isPlaying,gameOver,handleStartGame,handleStopGame]);const gameOverModalProps = useMemo(()=>({isVisible:gameOver,score,onPlayAgain:handleResetGame,buttonText:"Pop Again!",primaryColor:"rgba(59,130,246,0.5)",borderColor:"rgba(59,130,246,0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:"#3b82f6"}),[gameOver,score,handleResetGame]);const gameSettingsModalProps = useMemo(()=>({gameId:GAME_IDS.BALLOON_BLASTER,settings:settings || DEFAULT_GAME_SETTINGS,onSettingsChange}),[settings,onSettingsChange]);const offset = settings?.offset ?? 0;return _jsx(View,{style:styles.container,children:_jsx(GestureHandlerRootView,{children:_jsxs(GameBackground,{offset:offset,children:[_jsx(GameArea,{}),_jsx(ScoreBoard,{offset:offset}),_jsx(GameControlButton,{...gameControlButtonProps}),_jsx(GameOverModal,{...gameOverModalProps}),_jsx(GameSettingsModal,{...gameSettingsModalProps})]})})});});const styles = StyleSheet.create({container:{flex:1}});
1
+ "use strict";import t,{useEffect as o,useMemo as r,useCallback as e}from"react";import{View as n,StyleSheet as s}from"react-native";import{GestureHandlerRootView as i}from"react-native-gesture-handler";import{useBalloonBlasterStore as a}from"./BalloonBlasterStore.js";import{createBalloonBlasterService as l}from"./BalloonBlasterService.js";import{ScoreBoard as f,GameArea as m,GameBackground as c}from"./components/index.js";import{GameControlButton as p,GameOverModal as u,useAnimationTrackers as B,useGameErrorHandler as b,GameErrorType as d}from"../../helpers/index.js";import{GameSettingsModal as g}from"../../helpers/index.js";import{GAME_IDS as x,DEFAULT_GAME_SETTINGS as C}from"../../services/UtilsService.js";import{jsx as S,jsxs as j}from"react/jsx-runtime";export const BalloonBlaster=t.memo(({settings:s,onSettingsChange:A,onEndGame:P})=>{const T=a(t=>t.isPlaying),v=a(t=>t.gameOver),G=a(t=>t.score),y=t.useRef(!1),E=t.useCallback(t=>{if(P&&!y.current){const o=a.getState();P({status:t,score:o.score.toString()}),y.current=!0}},[P]),O=a(t=>t.startGame),w=a(t=>t.stopGame),I=a(t=>t.resetGame),F=a(t=>t.decrementTime),M=a(t=>t.addBalloon),N=a(t=>t.removeBalloon),R=a(t=>t.updateBalloon),{balloonAnimations:U,particleAnimations:V}=B(["balloonAnimations","particleAnimations"]),{wrapFunction:k,safeExecute:q}=b(x.BALLOON_BLASTER),z=e(t=>{M(t)},[M]),D=e(k(()=>{I()},d.UNKNOWN_ERROR),[k,I]),H=r(()=>q(()=>l(U,V),l(U,V),d.INITIALIZATION_ERROR),[U,V,q]),J=e(k(()=>{y.current=!1,I(),a.getState().balloons.forEach(t=>N(t.id)),H&&(H.cleanup(),H.resetAnimations()),setTimeout(()=>{O(),H&&(H.startGameTimer(F),H.startBalloonSpawning(z,600),H.startPhysicsLoop(R,N,()=>a.getState().balloons))},50)},d.INITIALIZATION_ERROR),[k,I,N,H,O,F,z,R]),K=e(k(()=>{E("cancel"),w(),H&&(H.cleanup(),H.resetAnimations())},d.UNKNOWN_ERROR),[k,w,H,E]);o(()=>()=>{D()},[D]),o(()=>{if(v&&!y.current){const t=a.getState().lives>0?"win":"lose";E(t)}v||(y.current=!1)},[v,E]),o(()=>{v&&H&&H.cleanup()},[v,H]);const L=r(()=>({isPlaying:T,gameOver:v,onStartGame:J,onStopGame:K,startButtonText:"START POPPING",stopButtonText:"STOP GAME",startButtonSubtext:"Pop balloons to score!",stopButtonSubtext:"End current game",startButtonColor:"#3b82f6",stopButtonColor:"#dc2626",startButtonBorderColor:"#60a5fa",stopButtonBorderColor:"#f87171"}),[T,v,J,K]),Q=r(()=>({isVisible:v,score:G,onPlayAgain:D,buttonText:"Pop Again!",primaryColor:"rgba(59, 130, 246, 0.5)",borderColor:"rgba(59, 130, 246, 0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:"#3b82f6"}),[v,G,D]),W=r(()=>({gameId:x.BALLOON_BLASTER,settings:s||C,onSettingsChange:A}),[s,A]),X=s?.offset??0;return S(n,{style:h.container,children:S(i,{children:j(c,{offset:X,children:[S(m,{}),S(f,{offset:X}),S(p,{...L}),S(u,{...Q}),S(g,{...W})]})})})});const h=s.create({container:{flex:1}});
@@ -1 +1 @@
1
- "use strict";export const BALLOON_BLASTER_GAME_CONFIG ={GAME_DURATION:120,MAX_LIVES:3,BALLOON_SPAWN_INTERVAL:800,BALLOON_RISE_SPEED:0.08,GRAVITY:-0.003,INITIAL_VELOCITY_Y:-0.2,INITIAL_VELOCITY_X_RANGE:0.3,ROTATION_SPEED_RANGE:0.02,BALLOON_SIZE:60,SLICE_TRAIL_LENGTH:10,COMBO_TIMEOUT:2000,PARTICLE_COUNT:4,PARTICLE_LIFETIME:600};export const BALLOON_BLASTER_ANIMATION_CONFIG ={BALLOON_SPRING:{damping:30,stiffness:50},POP_SPRING:{damping:20,stiffness:300},PARTICLE_SPRING:{damping:25,stiffness:400},SLICE_TIMING:{duration:200}};export const BALLOON_BLASTER_COLORS ={BACKGROUND:'#87CEEB',SCORE_BOARD:'#4169E1',SLICE_TRAIL:'#FFD700',PARTICLE_COLORS:['#FF6B6B','#4ECDC4','#45B7D1','#96CEB4','#FFEAA7','#DDA0DD'],COMBO_TEXT:'#FF4757',LIVES_COLOR:'#FF6B6B',PARTICLE_GLOW:'rgba(255,255,255,0.9)',SCORE:'#FFFFFF',UI:'#FF6347',BUTTON_ACTIVE:'#FF7F50',BUTTON_INACTIVE:'#FFA07A',TEXT_PRIMARY:'#FFFFFF',TEXT_SECONDARY:'#F0F8FF',WHITE:'#FFFFFF',START_BUTTON:'#4CAF50',GAME_OVER_OVERLAY:'rgba(0,0,0,0.85)'};export const BALLOON_TYPES = [{emoji:'🎈',points:10,name:'red balloon',color:'#FF0040',gradient:['#FF0040','#FF4080']},{emoji:'🎈',points:10,name:'blue balloon',color:'#0080FF',gradient:['#0080FF','#40A0FF']},{emoji:'🎈',points:15,name:'yellow balloon',color:'#FFD700',gradient:['#FFD700','#FFEB3B']},{emoji:'🎈',points:20,name:'green balloon',color:'#00FF80',gradient:['#00FF80','#40FFA0']},{emoji:'🎈',points:25,name:'purple balloon',color:'#8000FF',gradient:['#8000FF','#A040FF']},{emoji:'🎈',points:15,name:'pink balloon',color:'#FF0080',gradient:['#FF0080','#FF40A0']},{emoji:'🎈',points:30,name:'orange balloon',color:'#FF4000',gradient:['#FF4000','#FF8040']},{emoji:'🎈',points:25,name:'cyan balloon',color:'#00FFFF',gradient:['#00FFFF','#40FFFF']},{emoji:'🎈',points:35,name:'magenta balloon',color:'#FF00FF',gradient:['#FF00FF','#FF40FF']},{emoji:'🎈',points:40,name:'gold balloon',color:'#FFB000',gradient:['#FFB000','#FFD700']},{emoji:'🎈',points:45,name:'rainbow balloon',color:'#FF0080',gradient:['#FF0080','#8000FF','#0080FF','#00FF80']},{emoji:'🎈',points:50,name:'neon balloon',color:'#00FF00',gradient:['#00FF00','#FFFF00']}];export const BALLOON_SPECIAL_ITEMS = [{emoji:'💣',points:-50,name:'bomb',isBomb:true,color:'#FF4444'},{emoji:'⭐',points:50,name:'star',isBonus:true,color:'#FFD700'}];export const BALLOON_BLASTER_THEME ={backgroundColor:'rgba(0,0,0,0.7)',headerBackgroundColor:'#3b82f6',headerTextColor:'#ffffff',sectionBackgroundColor:'rgba(59,130,246,0.15)',sectionTitleColor:'#3b82f6',buttonSelectedColor:'#3b82f6',buttonUnselectedColor:'rgba(255,255,255,0.2)',buttonSelectedTextColor:'#ffffff',buttonUnselectedTextColor:'rgba(255,255,255,0.7)',switchTrackColorFalse:'rgba(59,130,246,0.3)',switchTrackColorTrue:'#3b82f6',switchThumbColor:'#ffffff',infoTextColor:'rgba(255,255,255,0.9)'};export const BALLOON_BLASTER_DIFFICULTY_DESCRIPTIONS ={easy:'Balloons spawn slower,more forgiving',medium:'Balanced gameplay and balloon speed',hard:'Fast balloons,quick reflexes needed!'};
1
+ "use strict";export const BALLOON_BLASTER_GAME_CONFIG={GAME_DURATION:120,MAX_LIVES:3,BALLOON_SPAWN_INTERVAL:800,BALLOON_RISE_SPEED:.08,GRAVITY:-.003,INITIAL_VELOCITY_Y:-.2,INITIAL_VELOCITY_X_RANGE:.3,ROTATION_SPEED_RANGE:.02,BALLOON_SIZE:60,SLICE_TRAIL_LENGTH:10,COMBO_TIMEOUT:2e3,PARTICLE_COUNT:4,PARTICLE_LIFETIME:600};export const BALLOON_BLASTER_ANIMATION_CONFIG={BALLOON_SPRING:{damping:30,stiffness:50},POP_SPRING:{damping:20,stiffness:300},PARTICLE_SPRING:{damping:25,stiffness:400},SLICE_TIMING:{duration:200}};export const BALLOON_BLASTER_COLORS={BACKGROUND:"#87CEEB",SCORE_BOARD:"#4169E1",SLICE_TRAIL:"#FFD700",PARTICLE_COLORS:["#FF6B6B","#4ECDC4","#45B7D1","#96CEB4","#FFEAA7","#DDA0DD"],COMBO_TEXT:"#FF4757",LIVES_COLOR:"#FF6B6B",PARTICLE_GLOW:"rgba(255,255,255,0.9)",SCORE:"#FFFFFF",UI:"#FF6347",BUTTON_ACTIVE:"#FF7F50",BUTTON_INACTIVE:"#FFA07A",TEXT_PRIMARY:"#FFFFFF",TEXT_SECONDARY:"#F0F8FF",WHITE:"#FFFFFF",START_BUTTON:"#4CAF50",GAME_OVER_OVERLAY:"rgba(0, 0, 0, 0.85)"};export const BALLOON_TYPES=[{emoji:"\ud83c\udf88",points:10,name:"red balloon",color:"#FF0040",gradient:["#FF0040","#FF4080"]},{emoji:"\ud83c\udf88",points:10,name:"blue balloon",color:"#0080FF",gradient:["#0080FF","#40A0FF"]},{emoji:"\ud83c\udf88",points:15,name:"yellow balloon",color:"#FFD700",gradient:["#FFD700","#FFEB3B"]},{emoji:"\ud83c\udf88",points:20,name:"green balloon",color:"#00FF80",gradient:["#00FF80","#40FFA0"]},{emoji:"\ud83c\udf88",points:25,name:"purple balloon",color:"#8000FF",gradient:["#8000FF","#A040FF"]},{emoji:"\ud83c\udf88",points:15,name:"pink balloon",color:"#FF0080",gradient:["#FF0080","#FF40A0"]},{emoji:"\ud83c\udf88",points:30,name:"orange balloon",color:"#FF4000",gradient:["#FF4000","#FF8040"]},{emoji:"\ud83c\udf88",points:25,name:"cyan balloon",color:"#00FFFF",gradient:["#00FFFF","#40FFFF"]},{emoji:"\ud83c\udf88",points:35,name:"magenta balloon",color:"#FF00FF",gradient:["#FF00FF","#FF40FF"]},{emoji:"\ud83c\udf88",points:40,name:"gold balloon",color:"#FFB000",gradient:["#FFB000","#FFD700"]},{emoji:"\ud83c\udf88",points:45,name:"rainbow balloon",color:"#FF0080",gradient:["#FF0080","#8000FF","#0080FF","#00FF80"]},{emoji:"\ud83c\udf88",points:50,name:"neon balloon",color:"#00FF00",gradient:["#00FF00","#FFFF00"]}];export const BALLOON_SPECIAL_ITEMS=[{emoji:"\ud83d\udca3",points:-50,name:"bomb",isBomb:!0,color:"#FF4444"},{emoji:"\u2b50",points:50,name:"star",isBonus:!0,color:"#FFD700"}];export const BALLOON_BLASTER_THEME={backgroundColor:"rgba(0, 0, 0, 0.7)",headerBackgroundColor:"#3b82f6",headerTextColor:"#ffffff",sectionBackgroundColor:"rgba(59, 130, 246, 0.15)",sectionTitleColor:"#3b82f6",buttonSelectedColor:"#3b82f6",buttonUnselectedColor:"rgba(255, 255, 255, 0.2)",buttonSelectedTextColor:"#ffffff",buttonUnselectedTextColor:"rgba(255, 255, 255, 0.7)",switchTrackColorFalse:"rgba(59, 130, 246, 0.3)",switchTrackColorTrue:"#3b82f6",switchThumbColor:"#ffffff",infoTextColor:"rgba(255, 255, 255, 0.9)"};export const BALLOON_BLASTER_DIFFICULTY_DESCRIPTIONS={easy:"Balloons spawn slower, more forgiving",medium:"Balanced gameplay and balloon speed",hard:"Fast balloons, quick reflexes needed!"};
@@ -1 +1 @@
1
- "use strict";import{Dimensions}from 'react-native';import{BALLOON_BLASTER_GAME_CONFIG as GAME_CONFIG,BALLOON_BLASTER_ANIMATION_CONFIG as ANIMATION_CONFIG,BALLOON_BLASTER_COLORS as COLORS,BALLOON_TYPES,BALLOON_SPECIAL_ITEMS as SPECIAL_ITEMS}from "./BalloonBlasterConstants.js";const{width,height}= Dimensions.get('window');export{GAME_CONFIG,ANIMATION_CONFIG,COLORS,BALLOON_TYPES,SPECIAL_ITEMS};export class BalloonBlasterService{gameTimerRef = null;balloonSpawnRef = null;animationRef = null;comboTimeoutRef = null;particles = [];constructor(balloonAnimations,particleAnimations){this.balloonAnimations = balloonAnimations;this.particleAnimations = particleAnimations;}startGameTimer(onTick){this.clearGameTimer();this.gameTimerRef = setInterval(onTick,1000);}startBalloonSpawning(spawnBalloon,customSpawnInterval){this.clearBalloonSpawn();const spawnInterval = customSpawnInterval || GAME_CONFIG.BALLOON_SPAWN_INTERVAL;const spawnLoop =()=>{const balloon = this.createRandomBalloon();spawnBalloon(balloon);const randomVariation =(Math.random()- 0.5)* 150;const nextSpawnTime = spawnInterval + randomVariation;this.balloonSpawnRef = setTimeout(spawnLoop,Math.max(200,nextSpawnTime));};for(let i = 0;i < 3;i++){setTimeout(()=>{const initialBalloon = this.createRandomBalloon();spawnBalloon(initialBalloon);},i * 50);}this.balloonSpawnRef = setTimeout(spawnLoop,100);}startPhysicsLoop(updateBalloon,removeBalloon,getBalloons){let lastTime = performance.now();const targetFPS = 60;const targetFrameTime = 1000 / targetFPS;const updateLoop = currentTime =>{const deltaTime = currentTime - lastTime;if(deltaTime < targetFrameTime){this.animationRef = requestAnimationFrame(updateLoop);return;}lastTime = currentTime;const deltaMultiplier = deltaTime / 16.67;this.updateParticles(deltaMultiplier);const balloons = getBalloons();for(let i = 0;i < balloons.length;i++){const balloon = balloons[i];if(!balloon || balloon.isPopped)continue;const newVelocityY = balloon.velocity.y + GAME_CONFIG.GRAVITY * deltaMultiplier;let newX = balloon.position.x + balloon.velocity.x * deltaMultiplier;const newY = balloon.position.y + newVelocityY * deltaMultiplier;const newRotation = balloon.rotation + balloon.rotationSpeed * deltaMultiplier;if(newY < -100){removeBalloon(balloon.id);continue;}if(newY > height + 100){removeBalloon(balloon.id);continue;}let newVelocityX = balloon.velocity.x;if(newX <= 0){newX = 0;newVelocityX = Math.abs(newVelocityX)* 0.8;}else if(newX >= width - GAME_CONFIG.BALLOON_SIZE){newX = width - GAME_CONFIG.BALLOON_SIZE;newVelocityX = -Math.abs(newVelocityX)* 0.8;}updateBalloon(balloon.id,{position:{x:newX,y:newY},velocity:{x:newVelocityX,y:newVelocityY},rotation:newRotation});}this.animationRef = requestAnimationFrame(updateLoop);};this.animationRef = requestAnimationFrame(updateLoop);}createRandomBalloon(){const isSpecial = Math.random()< 0.1;const type = isSpecial ? SPECIAL_ITEMS[Math.floor(Math.random()* SPECIAL_ITEMS.length)]:BALLOON_TYPES[Math.floor(Math.random()* BALLOON_TYPES.length)];const balloonType = type || BALLOON_TYPES[0];const balloonSize = GAME_CONFIG.BALLOON_SIZE;const margin = balloonSize / 2;const availableWidth = width - margin * 2 - balloonSize;const spawnX = margin + Math.random()* availableWidth;const spawnY = height - 30;const velocityX =(Math.random()- 0.5)* GAME_CONFIG.INITIAL_VELOCITY_X_RANGE;const velocityY = GAME_CONFIG.INITIAL_VELOCITY_Y;return{id:`balloon_${Date.now()}_${Math.random()}`,type:balloonType,position:{x:spawnX,y:spawnY},velocity:{x:velocityX,y:velocityY},rotation:0,rotationSpeed:(Math.random()- 0.5)* GAME_CONFIG.ROTATION_SPEED_RANGE,isPopped:false,spawnTime:Date.now(),isBomb:'isBomb' in balloonType && balloonType.isBomb,isBonus:'isBonus' in balloonType && balloonType.isBonus};}createPopParticles(balloon){const maxTotalParticles = 15;if(this.particles.length >= maxTotalParticles){this.particles.splice(0,Math.floor(this.particles.length / 2));}const particles = [];const particleCount = Math.min(GAME_CONFIG.PARTICLE_COUNT,6);const balloonCenterX = balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2;const balloonCenterY = balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2;for(let i = 0;i < particleCount;i++){const angle = i / particleCount * Math.PI * 2;const speed = 5 + Math.random()* 4;particles.push({id:`particle_${balloon.id}_${i}_${Date.now()}_${Math.random()}`,position:{x:balloonCenterX,y:balloonCenterY},velocity:{x:Math.cos(angle)* speed,y:Math.sin(angle)* speed - 3},color:COLORS.PARTICLE_COLORS[i % COLORS.PARTICLE_COLORS.length] || '#FF6B6B',size:4 + Math.random()* 3,lifetime:0,maxLifetime:Math.min(GAME_CONFIG.PARTICLE_LIFETIME,800)});}this.particles = [...this.particles,...particles];return particles;}updateParticles(deltaMultiplier = 1){const deltaTime = 16 * deltaMultiplier;const gravity = 0.08 * deltaMultiplier;const updatedParticles = [];for(let i = 0;i < this.particles.length;i++){const particle = this.particles[i];if(!particle)continue;const updatedParticle ={...particle};updatedParticle.lifetime += deltaTime;if(updatedParticle.lifetime >= updatedParticle.maxLifetime){continue;}updatedParticle.position ={x:updatedParticle.position.x + updatedParticle.velocity.x * deltaMultiplier,y:updatedParticle.position.y + updatedParticle.velocity.y * deltaMultiplier};updatedParticle.velocity ={x:updatedParticle.velocity.x * Math.pow(0.99,deltaMultiplier),y:(updatedParticle.velocity.y + gravity)* Math.pow(0.99,deltaMultiplier)};updatedParticles.push(updatedParticle);}this.particles = updatedParticles;}getParticles(){return this.particles;}checkBalloonPop(balloon,slicePath){if(balloon.isPopped || slicePath.length < 2)return false;const balloonCenter ={x:balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2,y:balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2};const balloonRadius = GAME_CONFIG.BALLOON_SIZE / 2;for(let i = 0;i < slicePath.length - 1;i++){const p1 = slicePath[i];const p2 = slicePath[i + 1];if(!p1 || !p2)continue;const distance = this.distanceFromPointToLine(balloonCenter,p1,p2);if(distance <= balloonRadius){return true;}}return false;}distanceFromPointToLine(point,lineStart,lineEnd){const A = point.x - lineStart.x;const B = point.y - lineStart.y;const C = lineEnd.x - lineStart.x;const D = lineEnd.y - lineStart.y;const dot = A * C + B * D;const lenSq = C * C + D * D;if(lenSq === 0)return Math.sqrt(A * A + B * B);let param = dot / lenSq;param = Math.max(0,Math.min(1,param));const xx = lineStart.x + param * C;const yy = lineStart.y + param * D;const dx = point.x - xx;const dy = point.y - yy;return Math.sqrt(dx * dx + dy * dy);}resetAnimations(){this.balloonAnimations.clear();this.particleAnimations.clear();this.particles = [];}cleanup(){this.clearGameTimer();this.clearBalloonSpawn();this.clearAnimationLoop();this.clearComboTimeout();this.particles = [];}clearGameTimer(){if(this.gameTimerRef){clearInterval(this.gameTimerRef);this.gameTimerRef = null;}}clearBalloonSpawn(){if(this.balloonSpawnRef){clearTimeout(this.balloonSpawnRef);this.balloonSpawnRef = null;}}clearAnimationLoop(){if(this.animationRef){cancelAnimationFrame(this.animationRef);this.animationRef = null;}}clearComboTimeout(){if(this.comboTimeoutRef){clearTimeout(this.comboTimeoutRef);this.comboTimeoutRef = null;}}}export const createBalloonBlasterService =(balloonAnimations,particleAnimations)=>{return new BalloonBlasterService(balloonAnimations,particleAnimations);};
1
+ "use strict";import{Dimensions as t}from"react-native";import{BALLOON_BLASTER_GAME_CONFIG as i,BALLOON_BLASTER_ANIMATION_CONFIG as e,BALLOON_BLASTER_COLORS as o,BALLOON_TYPES as s,BALLOON_SPECIAL_ITEMS as a}from"./BalloonBlasterConstants.js";const{width:n,height:r}=t.get("window");export{i as GAME_CONFIG,e as ANIMATION_CONFIG,o as COLORS,s as BALLOON_TYPES,a as SPECIAL_ITEMS};export class BalloonBlasterService{gameTimerRef=null;balloonSpawnRef=null;animationRef=null;comboTimeoutRef=null;particles=[];constructor(t,i){this.balloonAnimations=t,this.particleAnimations=i}startGameTimer(t){this.clearGameTimer(),this.gameTimerRef=setInterval(t,1e3)}startBalloonSpawning(t,e){this.clearBalloonSpawn();const o=e||i.BALLOON_SPAWN_INTERVAL,s=()=>{const i=this.createRandomBalloon();t(i);const e=150*(Math.random()-.5),a=o+e;this.balloonSpawnRef=setTimeout(s,Math.max(200,a))};for(let i=0;3>i;i++)setTimeout(()=>{const i=this.createRandomBalloon();t(i)},50*i);this.balloonSpawnRef=setTimeout(s,100)}startPhysicsLoop(t,e,o){let s=performance.now();const a=1e3/60,h=l=>{const c=l-s;if(a>c)return void(this.animationRef=requestAnimationFrame(h));s=l;const m=c/16.67;this.updateParticles(m);const u=o();for(let o=0;o<u.length;o++){const s=u[o];if(!s||s.isPopped)continue;const a=s.velocity.y+i.GRAVITY*m;let h=s.position.x+s.velocity.x*m;const l=s.position.y+a*m,c=s.rotation+s.rotationSpeed*m;if(-100>l){e(s.id);continue}if(l>r+100){e(s.id);continue}let M=s.velocity.x;h>0?h<n-i.BALLOON_SIZE||(h=n-i.BALLOON_SIZE,M=.8*-Math.abs(M)):(h=0,M=.8*Math.abs(M)),t(s.id,{position:{x:h,y:l},velocity:{x:M,y:a},rotation:c})}this.animationRef=requestAnimationFrame(h)};this.animationRef=requestAnimationFrame(h)}createRandomBalloon(){const t=(.1>Math.random()?a[Math.floor(Math.random()*a.length)]:s[Math.floor(Math.random()*s.length)])||s[0],e=i.BALLOON_SIZE,o=e/2,h=n-2*o-e,l=o+Math.random()*h,c=r-30,m=(Math.random()-.5)*i.INITIAL_VELOCITY_X_RANGE,u=i.INITIAL_VELOCITY_Y;return{id:`balloon_${Date.now()}_${Math.random()}`,type:t,position:{x:l,y:c},velocity:{x:m,y:u},rotation:0,rotationSpeed:(Math.random()-.5)*i.ROTATION_SPEED_RANGE,isPopped:!1,spawnTime:Date.now(),isBomb:"isBomb"in t&&t.isBomb,isBonus:"isBonus"in t&&t.isBonus}}createPopParticles(t){15>this.particles.length||this.particles.splice(0,Math.floor(this.particles.length/2));const e=[],s=Math.min(i.PARTICLE_COUNT,6),a=t.position.x+i.BALLOON_SIZE/2,n=t.position.y+i.BALLOON_SIZE/2;for(let r=0;s>r;r++){const h=r/s*Math.PI*2,l=5+4*Math.random();e.push({id:`particle_${t.id}_${r}_${Date.now()}_${Math.random()}`,position:{x:a,y:n},velocity:{x:Math.cos(h)*l,y:Math.sin(h)*l-3},color:o.PARTICLE_COLORS[r%o.PARTICLE_COLORS.length]||"#FF6B6B",size:4+3*Math.random(),lifetime:0,maxLifetime:Math.min(i.PARTICLE_LIFETIME,800)})}return this.particles=[...this.particles,...e],e}updateParticles(t=1){const i=16*t,e=.08*t,o=[];for(let s=0;s<this.particles.length;s++){const a=this.particles[s];if(!a)continue;const n={...a};n.lifetime+=i,n.lifetime<n.maxLifetime&&(n.position={x:n.position.x+n.velocity.x*t,y:n.position.y+n.velocity.y*t},n.velocity={x:n.velocity.x*Math.pow(.99,t),y:(n.velocity.y+e)*Math.pow(.99,t)},o.push(n))}this.particles=o}getParticles(){return this.particles}checkBalloonPop(t,e){if(t.isPopped||2>e.length)return!1;const o={x:t.position.x+i.BALLOON_SIZE/2,y:t.position.y+i.BALLOON_SIZE/2},s=i.BALLOON_SIZE/2;for(let t=0;t<e.length-1;t++){const i=e[t],a=e[t+1];if(i&&a&&s>=this.distanceFromPointToLine(o,i,a))return!0}return!1}distanceFromPointToLine(t,i,e){const o=t.x-i.x,s=t.y-i.y,a=e.x-i.x,n=e.y-i.y,r=o*a+s*n,h=a*a+n*n;if(0===h)return Math.sqrt(o*o+s*s);let l=r/h;l=Math.max(0,Math.min(1,l));const c=i.x+l*a,m=i.y+l*n,u=t.x-c,M=t.y-m;return Math.sqrt(u*u+M*M)}resetAnimations(){this.balloonAnimations.clear(),this.particleAnimations.clear(),this.particles=[]}cleanup(){this.clearGameTimer(),this.clearBalloonSpawn(),this.clearAnimationLoop(),this.clearComboTimeout(),this.particles=[]}clearGameTimer(){this.gameTimerRef&&(clearInterval(this.gameTimerRef),this.gameTimerRef=null)}clearBalloonSpawn(){this.balloonSpawnRef&&(clearTimeout(this.balloonSpawnRef),this.balloonSpawnRef=null)}clearAnimationLoop(){this.animationRef&&(cancelAnimationFrame(this.animationRef),this.animationRef=null)}clearComboTimeout(){this.comboTimeoutRef&&(clearTimeout(this.comboTimeoutRef),this.comboTimeoutRef=null)}}export const createBalloonBlasterService=(t,i)=>new BalloonBlasterService(t,i);
@@ -1 +1 @@
1
- "use strict";import{create}from 'zustand';import{subscribeWithSelector}from 'zustand/middleware';import{GAME_CONFIG}from "./BalloonBlasterService.js";import{immerMiddleware}from "../../services/UtilsService.js";export const useBalloonBlasterStore = create()(subscribeWithSelector(immerMiddleware((set,get)=>({score:0,timeLeft:60,isPlaying:false,gameOver:false,combo:0,lives:GAME_CONFIG.MAX_LIVES,balloons:[],particles:[],slicePath:[],isSlicing:false,startGame:_gameDuration =>{const duration = 60;set(draft =>{draft.score = 0;draft.timeLeft = duration;draft.isPlaying = true;draft.gameOver = false;draft.combo = 0;draft.lives = GAME_CONFIG.MAX_LIVES;draft.balloons = [];draft.slicePath = [];draft.isSlicing = false;});},stopGame:()=>{set(draft =>{draft.score = 0;draft.timeLeft = 60;draft.isPlaying = false;draft.gameOver = false;draft.combo = 0;draft.lives = GAME_CONFIG.MAX_LIVES;draft.balloons = [];draft.slicePath = [];draft.isSlicing = false;});},resetGame:()=>{set(draft =>{draft.score = 0;draft.timeLeft = 60;draft.isPlaying = false;draft.gameOver = false;draft.combo = 0;draft.lives = GAME_CONFIG.MAX_LIVES;draft.balloons = [];draft.slicePath = [];draft.isSlicing = false;});},popBalloon:balloonId =>{const{balloons,isPlaying}= get();if(!isPlaying)return;let balloonIndex = -1;for(let i = 0;i < balloons.length;i++){if(balloons[i].id === balloonId){balloonIndex = i;break;}}if(balloonIndex === -1 || balloons[balloonIndex].isPopped)return;const points = 10;set(draft =>{draft.score = draft.score + points;if(draft.balloons[balloonIndex]){draft.balloons[balloonIndex].isPopped = true;draft.balloons[balloonIndex].popTime = Date.now();}});},updateScore:points =>{set(draft =>{draft.score = draft.score + points;});},decrementTime:()=>{set(draft =>{const newTimeLeft = draft.timeLeft - 1;if(newTimeLeft <= 0){draft.timeLeft = 0;draft.isPlaying = false;draft.gameOver = true;}else{draft.timeLeft = newTimeLeft;}});},addBalloon:balloon =>{set(draft =>{const{height}= require('react-native').Dimensions.get('window');const correctedBalloon ={...balloon,position:{x:balloon.position.x,y:height + 20}};draft.balloons.push(correctedBalloon);});},removeBalloon:balloonId =>{set(draft =>{draft.balloons = draft.balloons.filter(b => b.id !== balloonId);});},updateBalloon:(balloonId,updates)=>{set(draft =>{for(let i = 0;i < draft.balloons.length;i++){if(draft.balloons[i].id === balloonId){Object.assign(draft.balloons[i],updates);break;}}});},setParticles:particles =>{set(draft =>{draft.particles = particles;});},setSlicePath:path =>{set(draft =>{draft.slicePath = path;});},setIsSlicing:isSlicing =>{set(draft =>{draft.isSlicing = isSlicing;});},incrementCombo:()=>{set(draft =>{draft.combo = draft.combo + 1;});},resetCombo:()=>{set(draft =>{draft.combo = 0;});},loseLife:()=>{set(draft =>{const newLives = draft.lives - 1;if(newLives <= 0){draft.lives = 0;draft.isPlaying = false;draft.gameOver = true;}else{draft.lives = newLives;}});},addLife:()=>{set(draft =>{draft.lives = Math.min(draft.lives + 1,GAME_CONFIG.MAX_LIVES);});}}))));
1
+ "use strict";import{create as e}from"zustand";import{subscribeWithSelector as o}from"zustand/middleware";import{GAME_CONFIG as t}from"./BalloonBlasterService.js";import{immerMiddleware as i}from"../../services/UtilsService.js";export const useBalloonBlasterStore=e()(o(i((e,o)=>({score:0,timeLeft:60,isPlaying:!1,gameOver:!1,combo:0,lives:t.MAX_LIVES,balloons:[],particles:[],slicePath:[],isSlicing:!1,startGame:o=>{e(e=>{e.score=0,e.timeLeft=60,e.isPlaying=!0,e.gameOver=!1,e.combo=0,e.lives=t.MAX_LIVES,e.balloons=[],e.slicePath=[],e.isSlicing=!1})},stopGame:()=>{e(e=>{e.score=0,e.timeLeft=60,e.isPlaying=!1,e.gameOver=!1,e.combo=0,e.lives=t.MAX_LIVES,e.balloons=[],e.slicePath=[],e.isSlicing=!1})},resetGame:()=>{e(e=>{e.score=0,e.timeLeft=60,e.isPlaying=!1,e.gameOver=!1,e.combo=0,e.lives=t.MAX_LIVES,e.balloons=[],e.slicePath=[],e.isSlicing=!1})},popBalloon:t=>{const{balloons:i,isPlaying:r}=o();if(!r)return;let s=-1;for(let e=0;e<i.length;e++)if(i[e].id===t){s=e;break}-1===s||i[s].isPopped||e(e=>{e.score=e.score+10,e.balloons[s]&&(e.balloons[s].isPopped=!0,e.balloons[s].popTime=Date.now())})},updateScore:o=>{e(e=>{e.score=e.score+o})},decrementTime:()=>{e(e=>{const o=e.timeLeft-1;o>0?e.timeLeft=o:(e.timeLeft=0,e.isPlaying=!1,e.gameOver=!0)})},addBalloon:o=>{e(e=>{const{height:t}=require("react-native").Dimensions.get("window"),i={...o,position:{x:o.position.x,y:t+20}};e.balloons.push(i)})},removeBalloon:o=>{e(e=>{e.balloons=e.balloons.filter(e=>e.id!==o)})},updateBalloon:(o,t)=>{e(e=>{for(let i=0;i<e.balloons.length;i++)if(e.balloons[i].id===o){Object.assign(e.balloons[i],t);break}})},setParticles:o=>{e(e=>{e.particles=o})},setSlicePath:o=>{e(e=>{e.slicePath=o})},setIsSlicing:o=>{e(e=>{e.isSlicing=o})},incrementCombo:()=>{e(e=>{e.combo=e.combo+1})},resetCombo:()=>{e(e=>{e.combo=0})},loseLife:()=>{e(e=>{const o=e.lives-1;o>0?e.lives=o:(e.lives=0,e.isPlaying=!1,e.gameOver=!0)})},addLife:()=>{e(e=>{e.lives=Math.min(e.lives+1,t.MAX_LIVES)})}}))));
@@ -1 +1 @@
1
- "use strict";import React,{useEffect,useMemo,useCallback}from 'react';import{TouchableOpacity,Dimensions}from 'react-native';import{Canvas,vec,Path,Skia,Oval,Circle}from '@shopify/react-native-skia';import Animated,{useSharedValue,useAnimatedStyle,withSpring,withTiming}from 'react-native-reanimated';import{GAME_CONFIG,ANIMATION_CONFIG}from "../BalloonBlasterService.js";import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from "react/jsx-runtime";const BALLOON_HEIGHT_MULTIPLIER = 1.2;const STRING_LENGTH = 25;const HIGHLIGHT_OPACITY = 0.5;const BALLOON_OPACITY = 0.8;const DANGER_CIRCLE_RADIUS = 8;const GLOW_RADIUS_MULTIPLIER = 0.6;const GLOW_OPACITY = 0.3;export const BalloonComponent = React.memo(({balloon,onPop})=>{const{height}= Dimensions.get('window');const initialY = balloon.position.y > height ? balloon.position.y:height - 30;const translateX = useSharedValue(balloon.position.x);const translateY = useSharedValue(initialY);const rotation = useSharedValue(balloon.rotation);const scale = useSharedValue(balloon.isPopped ? 0:1);const opacity = useSharedValue(balloon.isPopped ? 0:1);useEffect(()=>{translateX.value = withSpring(balloon.position.x,ANIMATION_CONFIG.BALLOON_SPRING);translateY.value = withSpring(balloon.position.y,ANIMATION_CONFIG.BALLOON_SPRING);rotation.value = withSpring(balloon.rotation,ANIMATION_CONFIG.BALLOON_SPRING);},[balloon.position.x,balloon.position.y,balloon.rotation]);useEffect(()=>{if(balloon.isPopped){scale.value = withTiming(0,ANIMATION_CONFIG.SLICE_TIMING);opacity.value = withTiming(0,ANIMATION_CONFIG.SLICE_TIMING);}else{scale.value = withSpring(1,ANIMATION_CONFIG.BALLOON_SPRING);opacity.value = withSpring(1,ANIMATION_CONFIG.BALLOON_SPRING);}},[balloon.isPopped]);const animatedStyle = useAnimatedStyle(()=>{return{transform:[{translateX:translateX.value},{translateY:translateY.value},{rotate:`${rotation.value}rad`},{scale:scale.value}],opacity:opacity.value};});const containerStyle ={position:'absolute',width:GAME_CONFIG.BALLOON_SIZE,height:GAME_CONFIG.BALLOON_SIZE,zIndex:balloon.isBomb ? 10:5};const lightenColor = useCallback((color,amount)=>{const hex = color.replace('#','');const r = Math.min(255,parseInt(hex.substring(0,2),16)+ Math.round(255 * amount));const g = Math.min(255,parseInt(hex.substring(2,4),16)+ Math.round(255 * amount));const b = Math.min(255,parseInt(hex.substring(4,6),16)+ Math.round(255 * amount));return `#${r.toString(16).padStart(2,'0')}${g.toString(16).padStart(2,'0')}${b.toString(16).padStart(2,'0')}`;},[]);const darkenColor = useCallback((color,amount)=>{const hex = color.replace('#','');const r = Math.max(0,parseInt(hex.substring(0,2),16)- Math.round(255 * amount));const g = Math.max(0,parseInt(hex.substring(2,4),16)- Math.round(255 * amount));const b = Math.max(0,parseInt(hex.substring(4,6),16)- Math.round(255 * amount));return `#${r.toString(16).padStart(2,'0')}${g.toString(16).padStart(2,'0')}${b.toString(16).padStart(2,'0')}`;},[]);const colors = useMemo(()=>{if(balloon.isBomb){return{primary:'#1a1a1a',secondary:'#333333',highlight:'#555555',shadow:'#000000'};}if(balloon.isBonus){return{primary:'#FFD700',secondary:'#FFEB3B',highlight:'#FFF59D',shadow:'#CC8800'};}const baseColor = balloon.type.color || '#FF0080';return{primary:baseColor,secondary:lightenColor(baseColor,0.3),highlight:lightenColor(baseColor,0.5),shadow:darkenColor(baseColor,0.3)};},[balloon.isBomb,balloon.isBonus,balloon.type.color,lightenColor,darkenColor]);const dimensions = useMemo(()=>{const balloonWidth = GAME_CONFIG.BALLOON_SIZE;const balloonHeight = GAME_CONFIG.BALLOON_SIZE * BALLOON_HEIGHT_MULTIPLIER;const totalHeight = balloonHeight + STRING_LENGTH;const center = vec(balloonWidth / 2,balloonHeight / 2);return{balloonWidth,balloonHeight,totalHeight,center};},[]);const curvedStringPath = useMemo(()=>{const path = Skia.Path.Make();const startX = dimensions.center.x;const startY = dimensions.balloonHeight - 2;const seed = balloon.id.split('').reduce((acc,char)=> acc + char.charCodeAt(0),0);const random = index =>(seed + index * 17)% 100 / 100;path.moveTo(startX,startY);const segments = 2;const segmentHeight = STRING_LENGTH / segments;for(let i = 1;i <= segments;i++){const y = startY + segmentHeight * i;const waveAmplitude = 2 + random(i)* 2;const waveOffset =(random(i + 10)- 0.5)* waveAmplitude;const x = startX + waveOffset;const controlX1 = startX +(random(i + 20)- 0.5)* waveAmplitude * 0.5;const controlY1 = y - segmentHeight * 0.5;path.quadTo(controlX1,controlY1,x,y);}return path;},[balloon.id,dimensions.center.x,dimensions.balloonHeight]);const handleTap = useCallback(()=>{onPop?.(balloon.id);},[onPop,balloon.id]);return _jsx(Animated.View,{style:[containerStyle,animatedStyle],children:_jsx(TouchableOpacity,{onPress:handleTap,activeOpacity:0.8,style:{width:dimensions.balloonWidth,height:dimensions.totalHeight},children:_jsxs(Canvas,{style:{width:dimensions.balloonWidth,height:dimensions.totalHeight},pointerEvents:"none",children:[_jsx(Oval,{x:0,y:0,width:dimensions.balloonWidth,height:dimensions.balloonHeight,color:colors.primary,opacity:BALLOON_OPACITY}),_jsx(Oval,{x:dimensions.balloonWidth * 0.2,y:dimensions.balloonHeight * 0.15,width:dimensions.balloonWidth * 0.3,height:dimensions.balloonHeight * 0.2,color:colors.highlight,opacity:HIGHLIGHT_OPACITY}),balloon.isBomb && _jsxs(_Fragment,{children:[_jsx(Circle,{cx:dimensions.center.x,cy:dimensions.center.y,r:DANGER_CIRCLE_RADIUS,color:"#FF0000",opacity:0.9}),_jsx(Path,{path:Skia.Path.Make().moveTo(dimensions.center.x,dimensions.center.y - 4).lineTo(dimensions.center.x,dimensions.center.y + 1),color:"#FFFFFF",style:"stroke",strokeWidth:2,strokeCap:"round"}),_jsx(Circle,{cx:dimensions.center.x,cy:dimensions.center.y + 3,r:1,color:"#FFFFFF"})]}),!balloon.isBonus && _jsx(Path,{path:curvedStringPath,color:"#8B4513",style:"stroke",strokeWidth:1.5,strokeCap:"round"}),balloon.isBonus && _jsx(Circle,{cx:dimensions.center.x,cy:dimensions.center.y,r:dimensions.balloonWidth * GLOW_RADIUS_MULTIPLIER,color:"#FFD700",opacity:GLOW_OPACITY})]})})});},(prevProps,nextProps)=>{return prevProps.balloon.id === nextProps.balloon.id && prevProps.balloon.position.x === nextProps.balloon.position.x && prevProps.balloon.position.y === nextProps.balloon.position.y && prevProps.balloon.rotation === nextProps.balloon.rotation && prevProps.balloon.isPopped === nextProps.balloon.isPopped && prevProps.balloon.isBomb === nextProps.balloon.isBomb && prevProps.balloon.isBonus === nextProps.balloon.isBonus;});
1
+ "use strict";import t,{useEffect as r,useMemo as o,useCallback as a}from"react";import{TouchableOpacity as e,Dimensions as n}from"react-native";import{Canvas as i,vec as s,Path as h,Skia as c,Oval as l,Circle as p}from"@shopify/react-native-skia";import F,{useSharedValue as d,useAnimatedStyle as y,withSpring as m,withTiming as g}from"react-native-reanimated";import{GAME_CONFIG as u,ANIMATION_CONFIG as M}from"../BalloonBlasterService.js";import{jsx as f,Fragment as w,jsxs as x}from"react/jsx-runtime";const k=1.2,I=25,v=.5,B=.8,$=8,C=.6,b=.3;export const BalloonComponent=t.memo(({balloon:t,onPop:$})=>{const{height:j}=n.get("window"),D=t.position.y>j?t.position.y:j-30,W=d(t.position.x),E=d(D),H=d(t.rotation),P=d(t.isPopped?0:1),z=d(t.isPopped?0:1);r(()=>{W.value=m(t.position.x,M.BALLOON_SPRING),E.value=m(t.position.y,M.BALLOON_SPRING),H.value=m(t.rotation,M.BALLOON_SPRING)},[t.position.x,t.position.y,t.rotation]),r(()=>{t.isPopped?(P.value=g(0,M.SLICE_TIMING),z.value=g(0,M.SLICE_TIMING)):(P.value=m(1,M.BALLOON_SPRING),z.value=m(1,M.BALLOON_SPRING))},[t.isPopped]);const O=y(()=>({transform:[{translateX:W.value},{translateY:E.value},{rotate:H.value+"rad"},{scale:P.value}],opacity:z.value})),S={position:"absolute",width:u.BALLOON_SIZE,height:u.BALLOON_SIZE,zIndex:t.isBomb?10:5},X=a((t,r)=>{const o=t.replace("#",""),a=Math.min(255,parseInt(o.substring(0,2),16)+Math.round(255*r)),e=Math.min(255,parseInt(o.substring(2,4),16)+Math.round(255*r)),n=Math.min(255,parseInt(o.substring(4,6),16)+Math.round(255*r));return`#${a.toString(16).padStart(2,"0")}${e.toString(16).padStart(2,"0")}${n.toString(16).padStart(2,"0")}`},[]),Y=a((t,r)=>{const o=t.replace("#",""),a=Math.max(0,parseInt(o.substring(0,2),16)-Math.round(255*r)),e=Math.max(0,parseInt(o.substring(2,4),16)-Math.round(255*r)),n=Math.max(0,parseInt(o.substring(4,6),16)-Math.round(255*r));return`#${a.toString(16).padStart(2,"0")}${e.toString(16).padStart(2,"0")}${n.toString(16).padStart(2,"0")}`},[]),q=o(()=>{if(t.isBomb)return{primary:"#1a1a1a",secondary:"#333333",highlight:"#555555",shadow:"#000000"};if(t.isBonus)return{primary:"#FFD700",secondary:"#FFEB3B",highlight:"#FFF59D",shadow:"#CC8800"};const r=t.type.color||"#FF0080";return{primary:r,secondary:X(r,.3),highlight:X(r,.5),shadow:Y(r,.3)}},[t.isBomb,t.isBonus,t.type.color,X,Y]),A=o(()=>{const t=u.BALLOON_SIZE,r=u.BALLOON_SIZE*k;return{balloonWidth:t,balloonHeight:r,totalHeight:r+I,center:s(t/2,r/2)}},[]),G=o(()=>{const r=c.Path.Make(),o=A.center.x,a=A.balloonHeight-2,e=t.id.split("").reduce((t,r)=>t+r.charCodeAt(0),0),n=t=>(e+17*t)%100/100;r.moveTo(o,a);for(let t=1;2>=t;t++){const e=a+12.5*t,i=2+2*n(t),s=o+(n(t+10)-.5)*i,h=o+(n(t+20)-.5)*i*.5,c=e-6.25;r.quadTo(h,c,s,e)}return r},[t.id,A.center.x,A.balloonHeight]),J=a(()=>{$?.(t.id)},[$,t.id]);return f(F.View,{style:[S,O],children:f(e,{onPress:J,activeOpacity:.8,style:{width:A.balloonWidth,height:A.totalHeight},children:x(i,{style:{width:A.balloonWidth,height:A.totalHeight},pointerEvents:"none",children:[f(l,{x:0,y:0,width:A.balloonWidth,height:A.balloonHeight,color:q.primary,opacity:B}),f(l,{x:.2*A.balloonWidth,y:.15*A.balloonHeight,width:.3*A.balloonWidth,height:.2*A.balloonHeight,color:q.highlight,opacity:v}),t.isBomb&&x(w,{children:[f(p,{cx:A.center.x,cy:A.center.y,r:8,color:"#FF0000",opacity:.9}),f(h,{path:c.Path.Make().moveTo(A.center.x,A.center.y-4).lineTo(A.center.x,A.center.y+1),color:"#FFFFFF",style:"stroke",strokeWidth:2,strokeCap:"round"}),f(p,{cx:A.center.x,cy:A.center.y+3,r:1,color:"#FFFFFF"})]}),!t.isBonus&&f(h,{path:G,color:"#8B4513",style:"stroke",strokeWidth:1.5,strokeCap:"round"}),t.isBonus&&f(p,{cx:A.center.x,cy:A.center.y,r:A.balloonWidth*C,color:"#FFD700",opacity:b})]})})})},(t,r)=>t.balloon.id===r.balloon.id&&t.balloon.position.x===r.balloon.position.x&&t.balloon.position.y===r.balloon.position.y&&t.balloon.rotation===r.balloon.rotation&&t.balloon.isPopped===r.balloon.isPopped&&t.balloon.isBomb===r.balloon.isBomb&&t.balloon.isBonus===r.balloon.isBonus);
@@ -1 +1 @@
1
- "use strict";import React,{useEffect,useState,useCallback,useMemo}from 'react';import{View,StyleSheet}from 'react-native';import{useBalloonBlasterStore}from "../BalloonBlasterStore.js";import{GAME_CONFIG}from "../BalloonBlasterService.js";import{playSound,GAME_SOUNDS}from "../../../services/SoundsService.js";import{playHaptic,HapticType}from "../../../services/HapticsService.js";import{ParticleBlast,useAnimationTracker}from "../../../helpers/index.js";import{BalloonComponent}from "./BalloonComponent.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";const BALLOON_REMOVAL_DELAY = 500;const PARTICLE_COUNT = 8;const PARTICLE_DURATION = 1000;export const GameArea = React.memo(()=>{const balloons = useBalloonBlasterStore(state => state.balloons);const isPlaying = useBalloonBlasterStore(state => state.isPlaying);const gameOver = useBalloonBlasterStore(state => state.gameOver);const{popBalloon,removeBalloon,updateBalloon,resetCombo,loseLife,addLife}= useBalloonBlasterStore();const balloonAnimations = useAnimationTracker();const [activeBlasts,setActiveBlasts] = useState([]);const playPopSound = useCallback(()=>{playSound(GAME_SOUNDS.BALLOON_BLASTER.POP,true);playHaptic(HapticType.LIGHT,true);},[]);const playBombSound = useCallback(()=>{playSound(GAME_SOUNDS.BALLOON_BLASTER.BOMB,true);playHaptic(HapticType.HEAVY,true);},[]);const createBlastParticles = useCallback(balloon =>{const blastX = balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2;const blastY = balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2;const blastId = `blast_${Date.now()}_${Math.random()}`;setActiveBlasts(prev => [...prev,{id:blastId,x:blastX,y:blastY}]);},[]);const handleBlastComplete = useCallback(blastId =>{setActiveBlasts(prev => prev.filter(blast => blast.id !== blastId));},[]);const handleBalloonPop = useCallback(balloonId =>{if(!isPlaying || gameOver)return;const currentBalloons = useBalloonBlasterStore.getState().balloons;const balloon = currentBalloons.find(b => b.id === balloonId);if(!balloon || balloon.isPopped)return;if(balloon.isBomb){playBombSound();loseLife();resetCombo();updateBalloon(balloonId,{isPopped:true});}else if(balloon.isBonus){playPopSound();addLife();updateBalloon(balloonId,{isPopped:true});}else{playPopSound();popBalloon(balloonId);}createBlastParticles(balloon);setTimeout(()=>{removeBalloon(balloonId);balloonAnimations.delete(balloonId);},BALLOON_REMOVAL_DELAY);},[isPlaying,gameOver,playBombSound,playPopSound,loseLife,resetCombo,addLife,popBalloon,updateBalloon,createBlastParticles,removeBalloon,balloonAnimations]);useEffect(()=>{balloons.forEach(balloon =>{if(!balloonAnimations.has(balloon.id)){balloonAnimations.initialize(balloon.id);}});},[balloons,balloonAnimations]);const balloonComponents = useMemo(()=>{return balloons.map(balloon =>{const animation = balloonAnimations.get(balloon.id);return _jsx(BalloonComponent,{balloon:balloon,animation:animation,onPop:handleBalloonPop},balloon.id);});},[balloons,balloonAnimations,handleBalloonPop]);const blastComponents = useMemo(()=>{return activeBlasts.map(blast => _jsx(ParticleBlast,{x:blast.x,y:blast.y,particleCount:PARTICLE_COUNT,duration:PARTICLE_DURATION,onComplete:()=> handleBlastComplete(blast.id)},blast.id));},[activeBlasts,handleBlastComplete]);return _jsxs(View,{style:styles.gameArea,children:[balloonComponents,blastComponents]});});const styles = StyleSheet.create({gameArea:{flex:1,position:'relative',overflow:'hidden'}});
1
+ "use strict";import o,{useEffect as e,useState as r,useCallback as t,useMemo as s}from"react";import{View as i,StyleSheet as n}from"react-native";import{useBalloonBlasterStore as a}from"../BalloonBlasterStore.js";import{GAME_CONFIG as m}from"../BalloonBlasterService.js";import{playSound as l,GAME_SOUNDS as p}from"../../../services/SoundsService.js";import{playHaptic as c,HapticType as f}from"../../../services/HapticsService.js";import{ParticleBlast as d,useAnimationTracker as u}from"../../../helpers/index.js";import{BalloonComponent as j}from"./BalloonComponent.js";import{jsx as v,jsxs as x}from"react/jsx-runtime";const B=500,S=8,h=1e3;export const GameArea=o.memo(()=>{const o=a(o=>o.balloons),n=a(o=>o.isPlaying),S=a(o=>o.gameOver),{popBalloon:b,removeBalloon:y,updateBalloon:P,resetCombo:A,loseLife:L,addLife:$}=a(),_=u(),[g,w]=r([]),D=t(()=>{l(p.BALLOON_BLASTER.POP,!0),c(f.LIGHT,!0)},[]),G=t(()=>{l(p.BALLOON_BLASTER.BOMB,!0),c(f.HEAVY,!0)},[]),H=t(o=>{const e=o.position.x+m.BALLOON_SIZE/2,r=o.position.y+m.BALLOON_SIZE/2,t=`blast_${Date.now()}_${Math.random()}`;w(o=>[...o,{id:t,x:e,y:r}])},[]),M=t(o=>{w(e=>e.filter(e=>e.id!==o))},[]),T=t(o=>{if(!n||S)return;const e=a.getState().balloons.find(e=>e.id===o);e&&!e.isPopped&&(e.isBomb?(G(),L(),A(),P(o,{isPopped:!0})):e.isBonus?(D(),$(),P(o,{isPopped:!0})):(D(),b(o)),H(e),setTimeout(()=>{y(o),_.delete(o)},B))},[n,S,G,D,L,A,$,b,P,H,y,_]);e(()=>{o.forEach(o=>{_.has(o.id)||_.initialize(o.id)})},[o,_]);const k=s(()=>o.map(o=>{const e=_.get(o.id);return v(j,{balloon:o,animation:e,onPop:T},o.id)}),[o,_,T]),q=s(()=>g.map(o=>v(d,{x:o.x,y:o.y,particleCount:8,duration:h,onComplete:()=>M(o.id)},o.id)),[g,M]);return x(i,{style:C.gameArea,children:[k,q]})});const C=n.create({gameArea:{flex:1,position:"relative",overflow:"hidden"}});
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{Dimensions,View}from 'react-native';import{Canvas,LinearGradient,Rect,Circle,Path,Skia,vec,Group,Shadow}from '@shopify/react-native-skia';import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";const{width,height}= Dimensions.get('window');export const GameBackground = React.memo(({children,offset = 0})=>{const sunY = height * 0.18 + offset * 0.9;const cloud1Y = height * 0.29 + offset * 0.9;const cloud2Y = height * 0.3 + offset * 0.9;const cloud3Y = height * 0.23 + offset * 0.9;return _jsxs(View,{style:{flex:1},children:[_jsxs(Canvas,{style:{position:'absolute',top:0,left:0,right:0,bottom:0,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:['#87CEEB','#B0E0E6','#E0F6FF','#F0F8FF','#FFF8DC']})}),_jsxs(Group,{children:[_jsxs(Circle,{cx:width * 0.8,cy:sunY,r:40,children:[_jsx(LinearGradient,{start:vec(-40,-40),end:vec(40,40),colors:['#FFFF99','#FFD700','#FFA500','#FF8C00']}),_jsx(Shadow,{dx:0,dy:0,blur:30,color:"#FFD700"})]}),_jsx(Circle,{cx:width * 0.8 - 8,cy:sunY - 8,r:15,children:_jsx(LinearGradient,{start:vec(-15,-15),end:vec(15,15),colors:['#FFFFFF','#FFFF99']})}),Array.from({length:16},(_,index)=>{const angle = 360 / 16 * index;const radian = angle * Math.PI / 180;const isLongRay = index % 2 === 0;const rayLength = isLongRay ? 25:15;const rayWidth = isLongRay ? 4:2;const startDistance = 45;const startX = width * 0.8 + Math.cos(radian)* startDistance;const startY = sunY + Math.sin(radian)* startDistance;const endX = width * 0.8 + Math.cos(radian)*(startDistance + rayLength);const endY = sunY + Math.sin(radian)*(startDistance + rayLength);const rayPath = Skia.Path.Make();rayPath.moveTo(startX,startY);rayPath.lineTo(endX,endY);return _jsx(Path,{path:rayPath,style:"stroke",strokeWidth:rayWidth,color:"#FFD700",opacity:0.75},index);}),_jsx(Circle,{cx:width * 0.8,cy:sunY,r:60,opacity:0.1,children:_jsx(LinearGradient,{start:vec(-60,-60),end:vec(60,60),colors:['#FFD700','transparent']})})]}),_jsxs(Group,{children:[_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.12,cy:cloud1Y,r:16,color:"#F0F8FF",opacity:0.35,children:_jsx(Shadow,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.05)"})}),_jsx(Circle,{cx:width * 0.18,cy:cloud1Y -(height * 0.24 - height * 0.21),r:22,color:"#FFFFFF",opacity:0.45,children:_jsx(Shadow,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.05)"})}),_jsx(Circle,{cx:width * 0.25,cy:cloud1Y -(height * 0.24 - height * 0.19),r:26,color:"#F8F8FF",opacity:0.55,children:_jsx(Shadow,{dx:2,dy:3,blur:12,color:"rgba(0,0,0,0.06)"})}),_jsx(Circle,{cx:width * 0.32,cy:cloud1Y -(height * 0.24 - height * 0.21),r:20,color:"#FFFFFF",opacity:0.50,children:_jsx(Shadow,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.05)"})}),_jsx(Circle,{cx:width * 0.37,cy:cloud1Y,r:14,color:"#F0F8FF",opacity:0.40,children:_jsx(Shadow,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.04)"})})]}),_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.62,cy:cloud2Y,r:15,color:"#F0F8FF",opacity:0.40,children:_jsx(Shadow,{dx:1,dy:2,blur:10,color:"rgba(0,0,0,0.04)"})}),_jsx(Circle,{cx:width * 0.69,cy:cloud2Y -(height * 0.27 - height * 0.24),r:19,color:"#FFFFFF",opacity:0.50,children:_jsx(Shadow,{dx:1,dy:2,blur:10,color:"rgba(0,0,0,0.05)"})}),_jsx(Circle,{cx:width * 0.76,cy:cloud2Y -(height * 0.27 - height * 0.26),r:13,color:"#F8F8FF",opacity:0.45,children:_jsx(Shadow,{dx:1,dy:2,blur:10,color:"rgba(0,0,0,0.04)"})})]}),_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.84,cy:cloud3Y,r:10,color:"#F0F8FF",opacity:0.35,children:_jsx(Shadow,{dx:0,dy:1,blur:6,color:"rgba(0,0,0,0.03)"})}),_jsx(Circle,{cx:width * 0.89,cy:cloud3Y -(height * 0.19 - height * 0.17),r:12,color:"#FFFFFF",opacity:0.40,children:_jsx(Shadow,{dx:0,dy:1,blur:6,color:"rgba(0,0,0,0.03)"})}),_jsx(Circle,{cx:width * 0.93,cy:cloud3Y,r:8,color:"#F8F8FF",opacity:0.30,children:_jsx(Shadow,{dx:0,dy:1,blur:6,color:"rgba(0,0,0,0.02)"})})]})]}),_jsxs(Group,{children:[_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.15,cy:height * 0.35,r:12,color:"#FF6B6B",opacity:0.3,children:_jsx(Shadow,{dx:2,dy:2,blur:8,color:"rgba(0,0,0,0.1)"})}),_jsx(Rect,{x:width * 0.15 - 0.5,y:height * 0.35 + 12,width:1,height:15,color:"#8B4513",opacity:0.4}),_jsx(Circle,{cx:width * 0.20,cy:height * 0.32,r:10,color:"#4ECDC4",opacity:0.3,children:_jsx(Shadow,{dx:2,dy:2,blur:6,color:"rgba(0,0,0,0.1)"})}),_jsx(Rect,{x:width * 0.20 - 0.5,y:height * 0.32 + 10,width:1,height:12,color:"#8B4513",opacity:0.4}),_jsx(Circle,{cx:width * 0.12,cy:height * 0.38,r:11,color:"#FFEAA7",opacity:0.3,children:_jsx(Shadow,{dx:2,dy:2,blur:7,color:"rgba(0,0,0,0.1)"})}),_jsx(Rect,{x:width * 0.12 - 0.5,y:height * 0.38 + 11,width:1,height:13,color:"#8B4513",opacity:0.4})]}),_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.45,cy:height * 0.28,r:9,color:"#DDA0DD",opacity:0.25,children:_jsx(Shadow,{dx:1,dy:2,blur:5,color:"rgba(0,0,0,0.08)"})}),_jsx(Rect,{x:width * 0.45 - 0.5,y:height * 0.28 + 9,width:1,height:10,color:"#8B4513",opacity:0.3}),_jsx(Circle,{cx:width * 0.50,cy:height * 0.31,r:8,color:"#96CEB4",opacity:0.25,children:_jsx(Shadow,{dx:1,dy:2,blur:4,color:"rgba(0,0,0,0.08)"})}),_jsx(Rect,{x:width * 0.50 - 0.5,y:height * 0.31 + 8,width:1,height:9,color:"#8B4513",opacity:0.3})]}),_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.75,cy:height * 0.33,r:7,color:"#FFB6C1",opacity:0.2,children:_jsx(Shadow,{dx:1,dy:1,blur:3,color:"rgba(0,0,0,0.06)"})}),_jsx(Rect,{x:width * 0.75 - 0.5,y:height * 0.33 + 7,width:1,height:8,color:"#8B4513",opacity:0.25}),_jsx(Circle,{cx:width * 0.80,cy:height * 0.30,r:6,color:"#FFA500",opacity:0.2,children:_jsx(Shadow,{dx:1,dy:1,blur:3,color:"rgba(0,0,0,0.06)"})}),_jsx(Rect,{x:width * 0.80 - 0.5,y:height * 0.30 + 6,width:1,height:7,color:"#8B4513",opacity:0.25})]}),_jsxs(Group,{children:[_jsx(Circle,{cx:width * 0.85,cy:height * 0.20,r:4,color:"#FF1493",opacity:0.15}),_jsx(Rect,{x:width * 0.85 - 0.25,y:height * 0.20 + 4,width:0.5,height:5,color:"#8B4513",opacity:0.2}),_jsx(Circle,{cx:width * 0.25,cy:height * 0.25,r:3,color:"#00CED1",opacity:0.15}),_jsx(Rect,{x:width * 0.25 - 0.25,y:height * 0.25 + 3,width:0.5,height:4,color:"#8B4513",opacity:0.2}),_jsx(Circle,{cx:width * 0.65,cy:height * 0.22,r:3.5,color:"#FFD700",opacity:0.15}),_jsx(Rect,{x:width * 0.65 - 0.25,y:height * 0.22 + 3.5,width:0.5,height:4.5,color:"#8B4513",opacity:0.2})]})]}),_jsxs(Group,{children:[Array.from({length:15},(_,i)=>{const x = width / 15 * i + i % 3 * 20;const y = height * 0.15 + i % 5 *(height * 0.1);const colors = ['#FF6B6B','#4ECDC4','#FFEAA7','#DDA0DD','#96CEB4','#FFB6C1'];const color = colors[i % colors.length];const size = 2 + i % 3;return _jsx(Circle,{cx:x,cy:y,r:size,color:color,opacity:0.3},`confetti-${i}`);}),Array.from({length:8},(_,i)=>{const startX = width / 8 * i;const startY = height * 0.05;const endX = startX + 30 + i % 2 * 20;const endY = height * 0.15;const colors = ['#FF6B6B','#4ECDC4','#FFEAA7','#DDA0DD'];const color = colors[i % colors.length];const streamerPath = Skia.Path.Make();streamerPath.moveTo(startX,startY);streamerPath.quadTo(startX + 15,startY + 20,endX,endY);return _jsx(Path,{path:streamerPath,style:"stroke",strokeWidth:3,color:color,opacity:0.4},`streamer-${i}`);})]}),_jsx(Rect,{x:0,y:height * 0.85,width:width,height:height * 0.15,children:_jsx(LinearGradient,{start:vec(0,height * 0.85),end:vec(0,height),colors:['#F0F8FF','#E6F3FF','#DDE9FF']})})]}),children]});});
1
+ "use strict";import r from"react";import{Dimensions as c,View as o}from"react-native";import{Canvas as t,LinearGradient as l,Rect as F,Circle as i,Path as y,Skia as d,vec as h,Group as e,Shadow as a}from"@shopify/react-native-skia";import{jsx as n,jsxs as x}from"react/jsx-runtime";const{width:p,height:b}=c.get("window");export const GameBackground=r.memo(({children:r,offset:c=0})=>{const s=.18*b+.9*c,g=.29*b+.9*c,u=.3*b+.9*c,D=.23*b+.9*c;return x(o,{style:{flex:1},children:[x(t,{style:{position:"absolute",top:0,left:0,right:0,bottom:0,width:p,height:b},children:[n(F,{x:0,y:0,width:p,height:b,children:n(l,{start:h(0,0),end:h(0,b),colors:["#87CEEB","#B0E0E6","#E0F6FF","#F0F8FF","#FFF8DC"]})}),x(e,{children:[x(i,{cx:.8*p,cy:s,r:40,children:[n(l,{start:h(-40,-40),end:h(40,40),colors:["#FFFF99","#FFD700","#FFA500","#FF8C00"]}),n(a,{dx:0,dy:0,blur:30,color:"#FFD700"})]}),n(i,{cx:.8*p-8,cy:s-8,r:15,children:n(l,{start:h(-15,-15),end:h(15,15),colors:["#FFFFFF","#FFFF99"]})}),Array.from({length:16},(r,c)=>{const o=22.5*c*Math.PI/180,t=c%2==0,l=t?25:15,F=t?4:2,i=.8*p+45*Math.cos(o),h=s+45*Math.sin(o),e=.8*p+Math.cos(o)*(45+l),a=s+Math.sin(o)*(45+l),x=d.Path.Make();return x.moveTo(i,h),x.lineTo(e,a),n(y,{path:x,style:"stroke",strokeWidth:F,color:"#FFD700",opacity:.75},c)}),n(i,{cx:.8*p,cy:s,r:60,opacity:.1,children:n(l,{start:h(-60,-60),end:h(60,60),colors:["#FFD700","transparent"]})})]}),x(e,{children:[x(e,{children:[n(i,{cx:.12*p,cy:g,r:16,color:"#F0F8FF",opacity:.35,children:n(a,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.05)"})}),n(i,{cx:.18*p,cy:g-(.24*b-.21*b),r:22,color:"#FFFFFF",opacity:.45,children:n(a,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.05)"})}),n(i,{cx:.25*p,cy:g-(.24*b-.19*b),r:26,color:"#F8F8FF",opacity:.55,children:n(a,{dx:2,dy:3,blur:12,color:"rgba(0,0,0,0.06)"})}),n(i,{cx:.32*p,cy:g-(.24*b-.21*b),r:20,color:"#FFFFFF",opacity:.5,children:n(a,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.05)"})}),n(i,{cx:.37*p,cy:g,r:14,color:"#F0F8FF",opacity:.4,children:n(a,{dx:1,dy:2,blur:12,color:"rgba(0,0,0,0.04)"})})]}),x(e,{children:[n(i,{cx:.62*p,cy:u,r:15,color:"#F0F8FF",opacity:.4,children:n(a,{dx:1,dy:2,blur:10,color:"rgba(0,0,0,0.04)"})}),n(i,{cx:.69*p,cy:u-(.27*b-.24*b),r:19,color:"#FFFFFF",opacity:.5,children:n(a,{dx:1,dy:2,blur:10,color:"rgba(0,0,0,0.05)"})}),n(i,{cx:.76*p,cy:u-(.27*b-.26*b),r:13,color:"#F8F8FF",opacity:.45,children:n(a,{dx:1,dy:2,blur:10,color:"rgba(0,0,0,0.04)"})})]}),x(e,{children:[n(i,{cx:.84*p,cy:D,r:10,color:"#F0F8FF",opacity:.35,children:n(a,{dx:0,dy:1,blur:6,color:"rgba(0,0,0,0.03)"})}),n(i,{cx:.89*p,cy:D-(.19*b-.17*b),r:12,color:"#FFFFFF",opacity:.4,children:n(a,{dx:0,dy:1,blur:6,color:"rgba(0,0,0,0.03)"})}),n(i,{cx:.93*p,cy:D,r:8,color:"#F8F8FF",opacity:.3,children:n(a,{dx:0,dy:1,blur:6,color:"rgba(0,0,0,0.02)"})})]})]}),x(e,{children:[x(e,{children:[n(i,{cx:.15*p,cy:.35*b,r:12,color:"#FF6B6B",opacity:.3,children:n(a,{dx:2,dy:2,blur:8,color:"rgba(0,0,0,0.1)"})}),n(F,{x:.15*p-.5,y:.35*b+12,width:1,height:15,color:"#8B4513",opacity:.4}),n(i,{cx:.2*p,cy:.32*b,r:10,color:"#4ECDC4",opacity:.3,children:n(a,{dx:2,dy:2,blur:6,color:"rgba(0,0,0,0.1)"})}),n(F,{x:.2*p-.5,y:.32*b+10,width:1,height:12,color:"#8B4513",opacity:.4}),n(i,{cx:.12*p,cy:.38*b,r:11,color:"#FFEAA7",opacity:.3,children:n(a,{dx:2,dy:2,blur:7,color:"rgba(0,0,0,0.1)"})}),n(F,{x:.12*p-.5,y:.38*b+11,width:1,height:13,color:"#8B4513",opacity:.4})]}),x(e,{children:[n(i,{cx:.45*p,cy:.28*b,r:9,color:"#DDA0DD",opacity:.25,children:n(a,{dx:1,dy:2,blur:5,color:"rgba(0,0,0,0.08)"})}),n(F,{x:.45*p-.5,y:.28*b+9,width:1,height:10,color:"#8B4513",opacity:.3}),n(i,{cx:.5*p,cy:.31*b,r:8,color:"#96CEB4",opacity:.25,children:n(a,{dx:1,dy:2,blur:4,color:"rgba(0,0,0,0.08)"})}),n(F,{x:.5*p-.5,y:.31*b+8,width:1,height:9,color:"#8B4513",opacity:.3})]}),x(e,{children:[n(i,{cx:.75*p,cy:.33*b,r:7,color:"#FFB6C1",opacity:.2,children:n(a,{dx:1,dy:1,blur:3,color:"rgba(0,0,0,0.06)"})}),n(F,{x:.75*p-.5,y:.33*b+7,width:1,height:8,color:"#8B4513",opacity:.25}),n(i,{cx:.8*p,cy:.3*b,r:6,color:"#FFA500",opacity:.2,children:n(a,{dx:1,dy:1,blur:3,color:"rgba(0,0,0,0.06)"})}),n(F,{x:.8*p-.5,y:.3*b+6,width:1,height:7,color:"#8B4513",opacity:.25})]}),x(e,{children:[n(i,{cx:.85*p,cy:.2*b,r:4,color:"#FF1493",opacity:.15}),n(F,{x:.85*p-.25,y:.2*b+4,width:.5,height:5,color:"#8B4513",opacity:.2}),n(i,{cx:.25*p,cy:.25*b,r:3,color:"#00CED1",opacity:.15}),n(F,{x:.25*p-.25,y:.25*b+3,width:.5,height:4,color:"#8B4513",opacity:.2}),n(i,{cx:.65*p,cy:.22*b,r:3.5,color:"#FFD700",opacity:.15}),n(F,{x:.65*p-.25,y:.22*b+3.5,width:.5,height:4.5,color:"#8B4513",opacity:.2})]})]}),x(e,{children:[Array.from({length:15},(r,c)=>{const o=["#FF6B6B","#4ECDC4","#FFEAA7","#DDA0DD","#96CEB4","#FFB6C1"];return n(i,{cx:p/15*c+c%3*20,cy:.15*b+c%5*.1*b,r:2+c%3,color:o[c%o.length],opacity:.3},"confetti-"+c)}),Array.from({length:8},(r,c)=>{const o=p/8*c,t=.05*b,l=o+30+c%2*20,F=.15*b,i=["#FF6B6B","#4ECDC4","#FFEAA7","#DDA0DD"],h=i[c%i.length],e=d.Path.Make();return e.moveTo(o,t),e.quadTo(o+15,t+20,l,F),n(y,{path:e,style:"stroke",strokeWidth:3,color:h,opacity:.4},"streamer-"+c)})]}),n(F,{x:0,y:.85*b,width:p,height:.15*b,children:n(l,{start:h(0,.85*b),end:h(0,b),colors:["#F0F8FF","#E6F3FF","#DDE9FF"]})})]}),r]})});
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{View,Text,StyleSheet}from 'react-native';import{useBalloonBlasterStore}from "../BalloonBlasterStore.js";import{GAME_CONFIG}from "../BalloonBlasterService.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 = useBalloonBlasterStore(state => state.score);const timeLeft = useBalloonBlasterStore(state => state.timeLeft);const lives = useBalloonBlasterStore(state => state.lives);const formatTime = seconds =>{const mins = Math.floor(seconds / 60);const secs = seconds % 60;return `${mins.toString().padStart(2,'0')}:${secs.toString().padStart(2,'0')}`;};return _jsx(ScoreBoardContainer,{offset:offset,backgroundColor:"rgba(59,130,246,0.4)",borderColor:"rgba(255,255,255,0.6)",children:_jsxs(View,{style:styles.scoreBoard,children:[_jsxs(View,{style:styles.scoreSection,children:[_jsx(Text,{style:styles.scoreLabel,children:"Score"}),_jsx(Text,{style:styles.scoreValue,children:score})]}),_jsxs(View,{style:styles.scoreSection,children:[_jsx(Text,{style:styles.scoreLabel,children:"Time"}),_jsx(Text,{style:styles.timeValue,children:formatTime(timeLeft)})]}),_jsxs(View,{style:styles.scoreSection,children:[_jsx(Text,{style:styles.scoreLabel,children:"Lives"}),_jsx(View,{style:styles.livesRow,children:Array.from({length:GAME_CONFIG.MAX_LIVES}).map((_,index)=> _jsx(Text,{style:[styles.heartIcon,index < lives ? styles.heartActive:styles.heartInactive],children:"\uD83C\uDF88"},index))})]})]})});});const styles = StyleSheet.create({scoreBoard:{flexDirection:'row',justifyContent:'space-between',alignItems:'center'},scoreSection:{alignItems:'center',flex:1},scoreLabel:{fontSize:16,fontWeight:'bold',color:'#ffffff',marginBottom:4},scoreValue:{fontSize:25,fontWeight:'bold',color:'#1e40af'},timeValue:{fontSize:25,fontWeight:'bold',color:'#1e40af'},livesRow:{flexDirection:'row',justifyContent:'center'},heartIcon:{fontSize:24,marginHorizontal:3,fontWeight:'bold'},heartActive:{opacity:1,textShadowColor:'rgba(0,0,0,0.5)',textShadowOffset:{width:1,height:1},textShadowRadius:2},heartInactive:{opacity:0.3,textShadowColor:'rgba(255,255,255,0.3)',textShadowOffset:{width:1,height:1},textShadowRadius:1}});
1
+ "use strict";import e from"react";import{View as t,Text as o,StyleSheet as r}from"react-native";import{useBalloonBlasterStore as i}from"../BalloonBlasterStore.js";import{GAME_CONFIG as l}from"../BalloonBlasterService.js";import{ScoreBoardContainer as n}from"../../../helpers/index.js";import{jsx as s,jsxs as a}from"react/jsx-runtime";export const ScoreBoard=e.memo(({offset:e=0})=>{const r=i(e=>e.score),f=i(e=>e.timeLeft),h=i(e=>e.lives);return s(n,{offset:e,backgroundColor:"rgba(59, 130, 246, 0.4)",borderColor:"rgba(255, 255, 255, 0.6)",children:a(t,{style:c.scoreBoard,children:[a(t,{style:c.scoreSection,children:[s(o,{style:c.scoreLabel,children:"Score"}),s(o,{style:c.scoreValue,children:r})]}),a(t,{style:c.scoreSection,children:[s(o,{style:c.scoreLabel,children:"Time"}),s(o,{style:c.timeValue,children:(e=>{const t=e%60;return`${Math.floor(e/60).toString().padStart(2,"0")}:${t.toString().padStart(2,"0")}`})(f)})]}),a(t,{style:c.scoreSection,children:[s(o,{style:c.scoreLabel,children:"Lives"}),s(t,{style:c.livesRow,children:Array.from({length:l.MAX_LIVES}).map((e,t)=>s(o,{style:[c.heartIcon,h>t?c.heartActive:c.heartInactive],children:"\ud83c\udf88"},t))})]})]})})});const c=r.create({scoreBoard:{flexDirection:"row",justifyContent:"space-between",alignItems:"center"},scoreSection:{alignItems:"center",flex:1},scoreLabel:{fontSize:16,fontWeight:"bold",color:"#ffffff",marginBottom:4},scoreValue:{fontSize:25,fontWeight:"bold",color:"#1e40af"},timeValue:{fontSize:25,fontWeight:"bold",color:"#1e40af"},livesRow:{flexDirection:"row",justifyContent:"center"},heartIcon:{fontSize:24,marginHorizontal:3,fontWeight:"bold"},heartActive:{opacity:1,textShadowColor:"rgba(0, 0, 0, 0.5)",textShadowOffset:{width:1,height:1},textShadowRadius:2},heartInactive:{opacity:.3,textShadowColor:"rgba(255, 255, 255, 0.3)",textShadowOffset:{width:1,height:1},textShadowRadius:1}});
@@ -1 +1 @@
1
- "use strict";export{BalloonComponent}from "./BalloonComponent.js";export{GameArea}from "./GameArea.js";export{GameBackground}from "./GameBackground.js";export{ScoreBoard}from "./ScoreBoard.js";
1
+ "use strict";export{BalloonComponent}from"./BalloonComponent.js";export{GameArea}from"./GameArea.js";export{GameBackground}from"./GameBackground.js";export{ScoreBoard}from"./ScoreBoard.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{useBikeRacingStore,useScore,useIsPlaying,useGameOver,useObstacles,usePlayerBike,useRoadOffset,useParticleEffects,useLives}from "./BikeRacingStore.js";import{BikeRacingService}from "./BikeRacingService.js";import{GameBackground,BikeComponent,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,BIKE_RACING_COLORS,BIKE_RACING_GAME_CONFIG}from "./BikeRacingConstants.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 BikeRacing =({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 playerBike = usePlayerBike();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)=> useBikeRacingStore.getState().startGame(duration,offset),[]);const stopGame = React.useCallback(()=> useBikeRacingStore.getState().stopGame(),[]);const resetGame = React.useCallback(()=> useBikeRacingStore.getState().resetGame(),[]);const handleParticleComplete = React.useCallback(effectId =>{useBikeRacingStore.getState().removeParticleEffect(effectId);},[]);const difficultySettings = React.useMemo(()=> getDifficultySettings(difficulty),[difficulty]);const gameService = React.useMemo(()=> new BikeRacingService(difficultySettings.roadSpeed,difficultySettings.obstacleSpawnInterval),[difficultySettings.roadSpeed,difficultySettings.obstacleSpawnInterval]);React.useEffect(()=>{useBikeRacingStore.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(()=>{useBikeRacingStore.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 = BIKE_RACING_GAME_CONFIG.LANE_WIDTH * BIKE_RACING_GAME_CONFIG.ROAD_LANES;const roadStartX =(width - roadWidth)/ 2;const relativeX = event.absoluteX - roadStartX;const lane = Math.floor(relativeX / BIKE_RACING_GAME_CONFIG.LANE_WIDTH);const clampedLane = Math.max(0,Math.min(BIKE_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:BIKE_RACING_COLORS.UI,stopButtonColor:BIKE_RACING_COLORS.UI,startButtonBorderColor:BIKE_RACING_COLORS.UI,stopButtonBorderColor:BIKE_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,102,0,0.5)",borderColor:"rgba(255,102,0,0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:BIKE_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(BikeComponent,{x:obstacle.x,y:obstacle.y,width:obstacle.width,height:obstacle.height,color:obstacle.color,isPlayer:false},obstacle.id)),_jsx(BikeComponent,{x:playerBike.x,y:playerBike.y,width:playerBike.width,height:playerBike.height,color:BIKE_RACING_COLORS.PLAYER_BIKE,isPlayer:true})]})}),particleEffects.map(effect => _jsx(ParticleBlast,{x:effect.x,y:effect.y,particleCount:12,colors:['#ff6600','#ff8833','#ffaa66','#ffcc00','#ffff00','#ffffff'],duration:800,onComplete:()=> handleParticleComplete(effect.id)},effect.id)),_jsx(GameControlButton,{...gameControlButtonProps}),_jsx(GameOverModal,{...gameOverModalProps}),_jsx(GameSettingsModal,{gameId:GAME_IDS.BIKE_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 e,StyleSheet as o,Dimensions as r}from"react-native";import{GestureDetector as i,Gesture as n,GestureHandlerRootView as s}from"react-native-gesture-handler";import{useBikeRacingStore as a,useScore as f,useIsPlaying as c,useGameOver as l,useObstacles as m,usePlayerBike as g,useRoadOffset as u,useParticleEffects as d,useLives as h}from"./BikeRacingStore.js";import{BikeRacingService as p}from"./BikeRacingService.js";import{GameBackground as x,BikeComponent as C,ScoreBoard as B}from"./components/index.js";import{GameControlButton as S,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,BIKE_RACING_COLORS as T,BIKE_RACING_GAME_CONFIG as A}from"./BikeRacingConstants.js";import{playSound as k,GAME_SOUNDS as G}from"../../services/SoundsService.js";import{playHaptic as P,HapticType as I}from"../../services/HapticsService.js";import{jsx as M,jsxs as O}from"react/jsx-runtime";const{width:E,height:D}=r.get("window");export const BikeRacing=({settings:r=w,onSettingsChange:N,onEndGame:U})=>{const V=r?.difficulty||"medium",q=r?.enableSounds??!0,z=r?.enableHaptics??!0,F=r?.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,e)=>a.getState().startGame(t,e),[]),et=t.useCallback(()=>a.getState().stopGame(),[]),ot=t.useCallback(()=>a.getState().resetGame(),[]),rt=t.useCallback(t=>{a.getState().removeParticleEffect(t)},[]),it=t.useMemo(()=>R(V),[V]),nt=t.useMemo(()=>new p(it.roadSpeed,it.obstacleSpawnInterval),[it.roadSpeed,it.obstacleSpawnInterval]);t.useEffect(()=>{a.getState().setOffset(F)},[F]),t.useEffect(()=>{nt.setCallbacks(()=>{k(G.CAR_RACING.CRASH,q),P(I.ERROR,z)},()=>{k(G.CAR_RACING.PASS,q),P(I.LIGHT,z)})},[nt,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(()=>()=>{nt.cleanup(),et()},[nt]);const st=t.useCallback(()=>{$.current=!1,tt(it.gameDuration,F),nt.startGame(),k(G.CAR_RACING.START,q),P(I.SUCCESS,z)},[tt,nt,it.gameDuration,F,q,z]),at=t.useCallback(()=>{_("cancel"),et(),nt.stopGame()},[et,nt,_]),ft=t.useCallback(()=>{ot(),nt.cleanup()},[ot,nt]),ct=t.useCallback(()=>{ft()},[ft]),lt=t.useRef(1),mt=n.Pan().onUpdate(t=>{if(!K)return;const e=A.LANE_WIDTH*A.ROAD_LANES,o=(E-e)/2,r=t.absoluteX-o,i=Math.floor(r/A.LANE_WIDTH),n=Math.max(0,Math.min(A.ROAD_LANES-1,i));n!==lt.current&&(lt.current=n,k(G.CAR_RACING.LANE_SWITCH,q),P(I.SELECTION,z)),nt.movePlayerToLane(n)}).runOnJS(!0),gt=t.useMemo(()=>({isPlaying:K,gameOver:L,onStartGame:st,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,st,at]),ut=t.useMemo(()=>({isVisible:L,score:J,onPlayAgain:ct,buttonText:"Race Again!",primaryColor:"rgba(255, 102, 0, 0.5)",borderColor:"rgba(255, 102, 0, 0.5)",buttonColor:"#ffffff",buttonBorderColor:"#ffffff",buttonTextColor:T.UI}),[L,J,ct]);return M(s,{style:H.container,children:O(e,{style:H.container,children:[M(e,{style:o.absoluteFillObject,children:M(x,{width:E,height:D,roadOffset:Y})}),M(B,{offset:F}),M(i,{gesture:mt,children:O(e,{style:H.gameArea,children:[W.map(t=>M(C,{x:t.x,y:t.y,width:t.width,height:t.height,color:t.color,isPlayer:!1},t.id)),M(C,{x:X.x,y:X.y,width:X.width,height:X.height,color:T.PLAYER_BIKE,isPlayer:!0})]})}),Z.map(t=>M(j,{x:t.x,y:t.y,particleCount:12,colors:["#ff6600","#ff8833","#ffaa66","#ffcc00","#ffff00","#ffffff"],duration:800,onComplete:()=>rt(t.id)},t.id)),M(S,{...gt}),M(v,{...ut}),M(y,{gameId:b.BIKE_RACING,settings:r||w,onSettingsChange:N})]})})};const H=o.create({container:{flex:1,backgroundColor:"#000"},gameArea:{flex:1}});
@@ -1 +1 @@
1
- "use strict";export const BIKE_RACING_DIFFICULTY_CONFIG ={easy:{gameDuration:60,obstacleSpawnInterval:2500,roadSpeed:5},medium:{gameDuration:120,obstacleSpawnInterval:2000,roadSpeed:7},hard:{gameDuration:180,obstacleSpawnInterval:1500,roadSpeed:9}};export const getDifficultySettings = difficulty =>{return BIKE_RACING_DIFFICULTY_CONFIG[difficulty];};export const DEFAULT_BIKE_RACING_SETTINGS ={difficulty:'medium',soundEnabled:true,hapticEnabled:true,gameDuration:BIKE_RACING_DIFFICULTY_CONFIG.medium.gameDuration,obstacleSpawnInterval:BIKE_RACING_DIFFICULTY_CONFIG.medium.obstacleSpawnInterval,roadSpeed:BIKE_RACING_DIFFICULTY_CONFIG.medium.roadSpeed};export const BIKE_RACING_GAME_CONFIG ={GAME_DURATION:120,BIKE_WIDTH:40,BIKE_HEIGHT:70,OBSTACLE_WIDTH:40,OBSTACLE_HEIGHT:70,ROAD_LANES:3,LANE_WIDTH:90,ROAD_SPEED:7,OBSTACLE_SPAWN_INTERVAL:2000,COLLISION_TOLERANCE:5,POINTS_PER_OBSTACLE_PASSED:15,LANE_SWITCH_DURATION:150};export const BIKE_RACING_COLORS ={ROAD_DARK:'#1a1a1a',ROAD_LIGHT:'#2a2a2a',ROAD_LINE:'#ffff00',GRASS_GREEN:'#2d5016',GRASS_DARK:'#1a3009',SKY_BLUE:'#87ceeb',PLAYER_BIKE:'#ff6600',OBSTACLE_BIKE_1:'#0066ff',OBSTACLE_BIKE_2:'#00ff66',OBSTACLE_BIKE_3:'#ff00ff',SCORE:'#ffff00',UI:'#ff6600'};export const BIKE_RACING_THEME ={backgroundColor:'rgba(0,0,0,0.7)',headerBackgroundColor:'#ff6600',headerTextColor:'#ffffff',sectionBackgroundColor:'rgba(255,102,0,0.15)',sectionTitleColor:'#ff6600',buttonSelectedColor:'#ff6600',buttonUnselectedColor:'rgba(255,255,255,0.2)',buttonSelectedTextColor:'#ffffff',buttonUnselectedTextColor:'rgba(255,255,255,0.7)',switchTrackColorFalse:'rgba(255,102,0,0.3)',switchTrackColorTrue:'#ff6600',switchThumbColor:'#ffffff',infoTextColor:'rgba(255,255,255,0.9)'};export const BIKE_RACING_DIFFICULTY_DESCRIPTIONS ={easy:'1 min,slower traffic,casual ride',medium:'2 mins,normal traffic speed,balanced challenge',hard:'3 mins,fast traffic,expert riding skills!'};export const getLanePosition =(laneIndex,screenWidth)=>{const roadWidth = BIKE_RACING_GAME_CONFIG.LANE_WIDTH * BIKE_RACING_GAME_CONFIG.ROAD_LANES;const roadStartX =(screenWidth - roadWidth)/ 2;const laneCenterX = roadStartX + laneIndex * BIKE_RACING_GAME_CONFIG.LANE_WIDTH + BIKE_RACING_GAME_CONFIG.LANE_WIDTH / 2;return laneCenterX - BIKE_RACING_GAME_CONFIG.BIKE_WIDTH / 2;};
1
+ "use strict";export const BIKE_RACING_DIFFICULTY_CONFIG={easy:{gameDuration:60,obstacleSpawnInterval:2500,roadSpeed:5},medium:{gameDuration:120,obstacleSpawnInterval:2e3,roadSpeed:7},hard:{gameDuration:180,obstacleSpawnInterval:1500,roadSpeed:9}};export const getDifficultySettings=e=>BIKE_RACING_DIFFICULTY_CONFIG[e];export const DEFAULT_BIKE_RACING_SETTINGS={difficulty:"medium",soundEnabled:!0,hapticEnabled:!0,gameDuration:BIKE_RACING_DIFFICULTY_CONFIG.medium.gameDuration,obstacleSpawnInterval:BIKE_RACING_DIFFICULTY_CONFIG.medium.obstacleSpawnInterval,roadSpeed:BIKE_RACING_DIFFICULTY_CONFIG.medium.roadSpeed};export const BIKE_RACING_GAME_CONFIG={GAME_DURATION:120,BIKE_WIDTH:40,BIKE_HEIGHT:70,OBSTACLE_WIDTH:40,OBSTACLE_HEIGHT:70,ROAD_LANES:3,LANE_WIDTH:90,ROAD_SPEED:7,OBSTACLE_SPAWN_INTERVAL:2e3,COLLISION_TOLERANCE:5,POINTS_PER_OBSTACLE_PASSED:15,LANE_SWITCH_DURATION:150};export const BIKE_RACING_COLORS={ROAD_DARK:"#1a1a1a",ROAD_LIGHT:"#2a2a2a",ROAD_LINE:"#ffff00",GRASS_GREEN:"#2d5016",GRASS_DARK:"#1a3009",SKY_BLUE:"#87ceeb",PLAYER_BIKE:"#ff6600",OBSTACLE_BIKE_1:"#0066ff",OBSTACLE_BIKE_2:"#00ff66",OBSTACLE_BIKE_3:"#ff00ff",SCORE:"#ffff00",UI:"#ff6600"};export const BIKE_RACING_THEME={backgroundColor:"rgba(0, 0, 0, 0.7)",headerBackgroundColor:"#ff6600",headerTextColor:"#ffffff",sectionBackgroundColor:"rgba(255, 102, 0, 0.15)",sectionTitleColor:"#ff6600",buttonSelectedColor:"#ff6600",buttonUnselectedColor:"rgba(255, 255, 255, 0.2)",buttonSelectedTextColor:"#ffffff",buttonUnselectedTextColor:"rgba(255, 255, 255, 0.7)",switchTrackColorFalse:"rgba(255, 102, 0, 0.3)",switchTrackColorTrue:"#ff6600",switchThumbColor:"#ffffff",infoTextColor:"rgba(255, 255, 255, 0.9)"};export const BIKE_RACING_DIFFICULTY_DESCRIPTIONS={easy:"1 min, slower traffic, casual ride",medium:"2 mins, normal traffic speed, balanced challenge",hard:"3 mins, fast traffic, expert riding skills!"};export const getLanePosition=(e,o)=>(o-270)/2+90*e+45-20;
@@ -1 +1 @@
1
- "use strict";import{Dimensions}from 'react-native';import{useBikeRacingStore}from "./BikeRacingStore.js";import{BIKE_RACING_GAME_CONFIG,BIKE_RACING_COLORS,getLanePosition}from "./BikeRacingConstants.js";const{width,height}= Dimensions.get('window');export class BikeRacingService{obstacleSpawnTimer = null;gameLoopTimer = null;obstacleIdCounter = 0;roadSpeed = BIKE_RACING_GAME_CONFIG.ROAD_SPEED;obstacleSpawnInterval = BIKE_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 = useBikeRacingStore.getState();const{obstacles,playerBike,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 > playerBike.y + playerBike.height){store.markObstaclePassed(obstacle.id);if(this.onPass){this.onPass();}}store.updateObstacle(obstacle.id,{y:newY});this.checkCollision(obstacle,playerBike);}}checkCollision(obstacle,playerBike){const store = useBikeRacingStore.getState();const cooldownTime = this.collisionCooldown.get(obstacle.id);if(cooldownTime && Date.now()- cooldownTime < 1000){return;}const tolerance = BIKE_RACING_GAME_CONFIG.COLLISION_TOLERANCE;const collision = playerBike.x < obstacle.x + obstacle.width - tolerance && playerBike.x + playerBike.width > obstacle.x + tolerance && playerBike.y < obstacle.y + obstacle.height - tolerance && playerBike.y + playerBike.height > obstacle.y + tolerance;if(collision){this.collisionCooldown.set(obstacle.id,Date.now());const collisionX =(playerBike.x + playerBike.width / 2 + obstacle.x + obstacle.width / 2)/ 2;const collisionY =(playerBike.y + playerBike.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 = useBikeRacingStore.getState();if(!store.isPlaying)return;const lane = this.fastRandom(0,BIKE_RACING_GAME_CONFIG.ROAD_LANES);const x = getLanePosition(lane,width);const colors = [BIKE_RACING_COLORS.OBSTACLE_BIKE_1,BIKE_RACING_COLORS.OBSTACLE_BIKE_2,BIKE_RACING_COLORS.OBSTACLE_BIKE_3];const colorIndex = this.fastRandom(0,colors.length);const color = colors[colorIndex] || BIKE_RACING_COLORS.OBSTACLE_BIKE_1;const obstacle ={id:`obstacle-${this.obstacleIdCounter++}`,x:x,y:-BIKE_RACING_GAME_CONFIG.OBSTACLE_HEIGHT,lane,width:BIKE_RACING_GAME_CONFIG.OBSTACLE_WIDTH,height:BIKE_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 = useBikeRacingStore.getState();if(!store.isPlaying)return;store.movePlayerBike(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{useBikeRacingStore as s}from"./BikeRacingStore.js";import{BIKE_RACING_GAME_CONFIG as i,BIKE_RACING_COLORS as e,getLanePosition as a}from"./BikeRacingConstants.js";const{width:n,height:o}=t.get("window");export class BikeRacingService{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,playerBike: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_BIKE_1,e.OBSTACLE_BIKE_2,e.OBSTACLE_BIKE_3],l=r[this.fastRandom(0,r.length)]||e.OBSTACLE_BIKE_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.movePlayerBike(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{BIKE_RACING_GAME_CONFIG,getLanePosition}from "./BikeRacingConstants.js";const{width,height}= Dimensions.get('window');export const useBikeRacingStore = create()(subscribeWithSelector(immerMiddleware((set,_get)=>({score:0,timeLeft:BIKE_RACING_GAME_CONFIG.GAME_DURATION,isPlaying:false,gameOver:false,lives:3,obstacles:[],playerBike:{x:getLanePosition(1,width),y:height * 0.65,lane:1,width:BIKE_RACING_GAME_CONFIG.BIKE_WIDTH,height:BIKE_RACING_GAME_CONFIG.BIKE_HEIGHT},roadOffset:0,particleEffects:[],offset:0,gameDuration:BIKE_RACING_GAME_CONFIG.GAME_DURATION,setOffset:offset =>{set(draft =>{draft.offset = offset;const yPosition = offset > 0 ? height * 0.75:height * 0.62;draft.playerBike.y = yPosition;});},startGame:(gameDuration,offset)=>{const duration = gameDuration || BIKE_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.playerBike ={x:getLanePosition(1,width),y:yPosition,lane:1,width:BIKE_RACING_GAME_CONFIG.BIKE_WIDTH,height:BIKE_RACING_GAME_CONFIG.BIKE_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.playerBike ={x:getLanePosition(1,width),y:yPosition,lane:1,width:BIKE_RACING_GAME_CONFIG.BIKE_WIDTH,height:BIKE_RACING_GAME_CONFIG.BIKE_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.playerBike ={x:getLanePosition(1,width),y:yPosition,lane:1,width:BIKE_RACING_GAME_CONFIG.BIKE_WIDTH,height:BIKE_RACING_GAME_CONFIG.BIKE_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;}}});},movePlayerBike:lane =>{set(draft =>{const validLane = Math.max(0,Math.min(BIKE_RACING_GAME_CONFIG.ROAD_LANES - 1,lane));draft.playerBike.lane = validLane;draft.playerBike.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 + BIKE_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 =()=> useBikeRacingStore(state => state.score);export const useTimeLeft =()=> useBikeRacingStore(state => state.timeLeft);export const useLives =()=> useBikeRacingStore(state => state.lives);export const useIsPlaying =()=> useBikeRacingStore(state => state.isPlaying);export const useGameOver =()=> useBikeRacingStore(state => state.gameOver);export const useObstacles =()=> useBikeRacingStore(state => state.obstacles);export const usePlayerBike =()=> useBikeRacingStore(state => state.playerBike);export const useRoadOffset =()=> useBikeRacingStore(state => state.roadOffset);export const useParticleEffects =()=> useBikeRacingStore(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 o}from"../../services/UtilsService.js";import{BIKE_RACING_GAME_CONFIG as i,getLanePosition as a}from"./BikeRacingConstants.js";const{width:r,height:c}=s.get("window");export const useBikeRacingStore=e()(t(o((e,t)=>({score:0,timeLeft:i.GAME_DURATION,isPlaying:!1,gameOver:!1,lives:3,obstacles:[],playerBike:{x:a(1,r),y:.65*c,lane:1,width:i.BIKE_WIDTH,height:i.BIKE_HEIGHT},roadOffset:0,particleEffects:[],offset:0,gameDuration:i.GAME_DURATION,setOffset:t=>{e(e=>{e.offset=t;const s=t>0?.75*c:.62*c;e.playerBike.y=s})},startGame:(t,s)=>{const o=t||i.GAME_DURATION;e(e=>{e.score=0,e.timeLeft=o,e.gameDuration=o,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*c:.62*c;e.playerBike={x:a(1,r),y:t,lane:1,width:i.BIKE_WIDTH,height:i.BIKE_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*c:.62*c;e.playerBike={x:a(1,r),y:t,lane:1,width:i.BIKE_WIDTH,height:i.BIKE_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*c:.62*c;e.playerBike={x:a(1,r),y:t,lane:1,width:i.BIKE_WIDTH,height:i.BIKE_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 o=0;o<e.obstacles.length;o++)if(e.obstacles[o].id===t){Object.assign(e.obstacles[o],s);break}})},movePlayerBike:t=>{e(e=>{const s=Math.max(0,Math.min(i.ROAD_LANES-1,t));e.playerBike.lane=s,e.playerBike.x=a(s,r)})},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+i.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=()=>useBikeRacingStore(e=>e.score);export const useTimeLeft=()=>useBikeRacingStore(e=>e.timeLeft);export const useLives=()=>useBikeRacingStore(e=>e.lives);export const useIsPlaying=()=>useBikeRacingStore(e=>e.isPlaying);export const useGameOver=()=>useBikeRacingStore(e=>e.gameOver);export const useObstacles=()=>useBikeRacingStore(e=>e.obstacles);export const usePlayerBike=()=>useBikeRacingStore(e=>e.playerBike);export const useRoadOffset=()=>useBikeRacingStore(e=>e.roadOffset);export const useParticleEffects=()=>useBikeRacingStore(e=>e.particleEffects);
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{Canvas,Circle,RoundedRect,Rect,Path,Skia}from '@shopify/react-native-skia';import Animated,{useAnimatedStyle,withSpring}from 'react-native-reanimated';import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from "react/jsx-runtime";const BikeComponentView =({x,y,width,height,color,isPlayer})=>{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]);const centerX = width / 2;const frontY = height * 0.05;const tankY = height * 0.25;const seatY = height * 0.5;const rearY = height * 0.8;const frontWidth = width * 0.45;const tankWidth = width * 0.75;const seatWidth = width * 0.9;const rearWidth = width * 0.65;const frontWheelY = height * 0.12;const rearWheelY = height * 0.88;const wheelWidth = width * 0.22;const wheelHeight = height * 0.1;const wheelOffset = seatWidth / 2 - wheelWidth / 2;return _jsx(Animated.View,{style:[{position:'absolute',width,height},animatedStyle],children:_jsxs(Canvas,{style:{width,height},children:[_jsx(RoundedRect,{x:centerX - seatWidth / 2 + 4,y:frontY + 4,width:seatWidth,height:height * 0.85,r:15,color:"rgba(0,0,0,0.3)"}),_jsx(RoundedRect,{x:centerX - wheelOffset,y:rearWheelY,width:wheelWidth,height:wheelHeight,r:4,color:"#4a4a4a"}),_jsx(RoundedRect,{x:centerX - wheelOffset + 2,y:rearWheelY + 2,width:wheelWidth - 4,height:wheelHeight - 4,r:3,color:"#888888"}),_jsx(RoundedRect,{x:centerX - wheelOffset + 4,y:rearWheelY + 4,width:wheelWidth - 8,height:wheelHeight - 8,r:2,color:"#cccccc"}),_jsx(RoundedRect,{x:centerX + wheelOffset - wheelWidth,y:rearWheelY,width:wheelWidth,height:wheelHeight,r:4,color:"#4a4a4a"}),_jsx(RoundedRect,{x:centerX + wheelOffset - wheelWidth + 2,y:rearWheelY + 2,width:wheelWidth - 4,height:wheelHeight - 4,r:3,color:"#888888"}),_jsx(RoundedRect,{x:centerX + wheelOffset - wheelWidth + 4,y:rearWheelY + 4,width:wheelWidth - 8,height:wheelHeight - 8,r:2,color:"#cccccc"}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - rearWidth / 2,rearY);path.lineTo(centerX - seatWidth / 2,seatY + height * 0.2);path.lineTo(centerX + seatWidth / 2,seatY + height * 0.2);path.lineTo(centerX + rearWidth / 2,rearY);path.close();return path;})(),color:"#ffffff",style:"stroke",strokeWidth:3}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - rearWidth / 2,rearY);path.lineTo(centerX - seatWidth / 2,seatY + height * 0.2);path.lineTo(centerX + seatWidth / 2,seatY + height * 0.2);path.lineTo(centerX + rearWidth / 2,rearY);path.close();return path;})(),color:color}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - rearWidth / 2 + 5,rearY - 5);path.lineTo(centerX - seatWidth / 2 + 5,seatY + height * 0.2);path.lineTo(centerX + seatWidth / 2 - 5,seatY + height * 0.2);path.lineTo(centerX + rearWidth / 2 - 5,rearY - 5);path.close();return path;})(),color:"rgba(255,255,255,0.2)"}),_jsx(RoundedRect,{x:centerX - seatWidth / 2,y:seatY,width:seatWidth,height:height * 0.25,r:12,color:"#ffffff",style:"stroke",strokeWidth:3}),_jsx(RoundedRect,{x:centerX - seatWidth / 2,y:seatY,width:seatWidth,height:height * 0.25,r:12,color:color}),_jsx(Circle,{cx:centerX,cy:seatY + height * 0.12,r:width * 0.16,color:"#ffffff",style:"stroke",strokeWidth:2}),_jsx(Circle,{cx:centerX,cy:seatY + height * 0.12,r:width * 0.16,color:isPlayer ? '#ffffff':'#555555'}),_jsx(RoundedRect,{x:centerX - width * 0.11,y:seatY + height * 0.08,width:width * 0.22,height:height * 0.05,r:2,color:isPlayer ? color:'#333333'}),_jsx(RoundedRect,{x:centerX - tankWidth / 2,y:tankY,width:tankWidth,height:height * 0.2,r:10,color:color}),_jsx(RoundedRect,{x:centerX - tankWidth * 0.35,y:tankY + height * 0.02,width:tankWidth * 0.7,height:height * 0.06,r:5,color:"rgba(255,255,255,0.35)"}),_jsx(Rect,{x:centerX - width * 0.08,y:tankY,width:width * 0.16,height:height * 0.2,color:"rgba(0,0,0,0.15)"}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - tankWidth / 2,tankY);path.lineTo(centerX - frontWidth / 2,frontY + height * 0.1);path.lineTo(centerX + frontWidth / 2,frontY + height * 0.1);path.lineTo(centerX + tankWidth / 2,tankY);path.close();return path;})(),color:"#ffffff",style:"stroke",strokeWidth:3}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - tankWidth / 2,tankY);path.lineTo(centerX - frontWidth / 2,frontY + height * 0.1);path.lineTo(centerX + frontWidth / 2,frontY + height * 0.1);path.lineTo(centerX + tankWidth / 2,tankY);path.close();return path;})(),color:color}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - tankWidth / 2 + 5,tankY);path.lineTo(centerX - frontWidth / 2 + 3,frontY + height * 0.12);path.lineTo(centerX + frontWidth / 2 - 3,frontY + height * 0.12);path.lineTo(centerX + tankWidth / 2 - 5,tankY);path.close();return path;})(),color:"rgba(255,255,255,0.25)"}),_jsx(RoundedRect,{x:centerX - wheelOffset,y:frontWheelY,width:wheelWidth,height:wheelHeight,r:4,color:"#4a4a4a"}),_jsx(RoundedRect,{x:centerX - wheelOffset + 2,y:frontWheelY + 2,width:wheelWidth - 4,height:wheelHeight - 4,r:3,color:"#888888"}),_jsx(RoundedRect,{x:centerX - wheelOffset + 4,y:frontWheelY + 4,width:wheelWidth - 8,height:wheelHeight - 8,r:2,color:"#cccccc"}),_jsx(RoundedRect,{x:centerX + wheelOffset - wheelWidth,y:frontWheelY,width:wheelWidth,height:wheelHeight,r:4,color:"#4a4a4a"}),_jsx(RoundedRect,{x:centerX + wheelOffset - wheelWidth + 2,y:frontWheelY + 2,width:wheelWidth - 4,height:wheelHeight - 4,r:3,color:"#888888"}),_jsx(RoundedRect,{x:centerX + wheelOffset - wheelWidth + 4,y:frontWheelY + 4,width:wheelWidth - 8,height:wheelHeight - 8,r:2,color:"#cccccc"}),_jsx(Path,{path:(()=>{const path = Skia.Path.Make();path.moveTo(centerX - frontWidth / 2,frontY + height * 0.08);path.lineTo(centerX,frontY);path.lineTo(centerX + frontWidth / 2,frontY + height * 0.08);path.close();return path;})(),color:color}),_jsx(RoundedRect,{x:centerX - width * 0.15,y:frontY + height * 0.02,width:width * 0.3,height:height * 0.04,r:3,color:"#ffff99"}),_jsx(RoundedRect,{x:centerX - width * 0.12,y:frontY + height * 0.025,width:width * 0.24,height:height * 0.025,r:2,color:"#ffffdd"}),_jsx(Circle,{cx:centerX - seatWidth / 2 - 3,cy:tankY + height * 0.1,r:width * 0.08,color:"rgba(100,200,255,0.4)"}),_jsx(Circle,{cx:centerX + seatWidth / 2 + 3,cy:tankY + height * 0.1,r:width * 0.08,color:"rgba(100,200,255,0.4)"}),_jsx(Circle,{cx:centerX - seatWidth / 2 - 3,cy:tankY + height * 0.1,r:width * 0.08,color:color,style:"stroke",strokeWidth:2}),_jsx(Circle,{cx:centerX + seatWidth / 2 + 3,cy:tankY + height * 0.1,r:width * 0.08,color:color,style:"stroke",strokeWidth:2}),_jsx(RoundedRect,{x:centerX + rearWidth / 2 - width * 0.1,y:rearY - height * 0.08,width:width * 0.07,height:height * 0.06,r:3,color:"#555555"}),_jsx(RoundedRect,{x:centerX + rearWidth / 2 - width * 0.1 + 1,y:rearY - height * 0.08 + 1,width:width * 0.05,height:height * 0.04,r:2,color:"#333333"}),isPlayer && _jsxs(_Fragment,{children:[_jsx(Circle,{cx:centerX + rearWidth / 2 - width * 0.07,cy:rearY + height * 0.01,r:3,color:"rgba(150,150,150,0.5)"}),_jsx(Circle,{cx:centerX + rearWidth / 2 - width * 0.07,cy:rearY + height * 0.04,r:4,color:"rgba(150,150,150,0.35)"}),_jsx(Circle,{cx:centerX + rearWidth / 2 - width * 0.07,cy:rearY + height * 0.08,r:5,color:"rgba(150,150,150,0.2)"})]}),isPlayer && _jsx(RoundedRect,{x:centerX - width * 0.1,y:seatY + height * 0.18,width:width * 0.2,height:height * 0.06,r:3,color:"rgba(255,255,255,0.95)"}),_jsx(RoundedRect,{x:centerX - width * 0.08,y:rearY - height * 0.02,width:width * 0.16,height:height * 0.02,r:2,color:"#ff3333"})]})});};const arePropsEqual =(prevProps,nextProps)=>{return Math.floor(prevProps.x)=== Math.floor(nextProps.x)&& Math.floor(prevProps.y)=== Math.floor(nextProps.y)&& prevProps.width === nextProps.width && prevProps.height === nextProps.height && prevProps.color === nextProps.color && prevProps.isPlayer === nextProps.isPlayer;};export const BikeComponent = React.memo(BikeComponentView,arePropsEqual);BikeComponent.displayName = 'BikeComponent';
1
+ "use strict";import r from"react";import{Canvas as t,Circle as o,RoundedRect as h,Rect as c,Path as e,Skia as i}from"@shopify/react-native-skia";import a,{useAnimatedStyle as l,withSpring as s}from"react-native-reanimated";import{jsx as f,Fragment as y,jsxs as d}from"react/jsx-runtime";const g=({x:r,y:g,width:n,height:x,color:w,isPlayer:m})=>{const p=l(()=>m?{transform:[{translateX:s(r,{damping:25,stiffness:150,mass:.8})},{translateY:g}]}:{transform:[{translateX:r},{translateY:g}]},[r,g,m]),k=n/2,b=.05*x,u=.25*x,W=.5*x,M=.8*x,j=.45*n,B=.75*n,C=.9*n,v=.65*n,X=.12*x,Y=.88*x,F=.22*n,P=.1*x,q=C/2-F/2;return f(a.View,{style:[{position:"absolute",width:n,height:x},p],children:d(t,{style:{width:n,height:x},children:[f(h,{x:k-C/2+4,y:b+4,width:C,height:.85*x,r:15,color:"rgba(0, 0, 0, 0.3)"}),f(h,{x:k-q,y:Y,width:F,height:P,r:4,color:"#4a4a4a"}),f(h,{x:k-q+2,y:Y+2,width:F-4,height:P-4,r:3,color:"#888888"}),f(h,{x:k-q+4,y:Y+4,width:F-8,height:P-8,r:2,color:"#cccccc"}),f(h,{x:k+q-F,y:Y,width:F,height:P,r:4,color:"#4a4a4a"}),f(h,{x:k+q-F+2,y:Y+2,width:F-4,height:P-4,r:3,color:"#888888"}),f(h,{x:k+q-F+4,y:Y+4,width:F-8,height:P-8,r:2,color:"#cccccc"}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-v/2,M),r.lineTo(k-C/2,W+.2*x),r.lineTo(k+C/2,W+.2*x),r.lineTo(k+v/2,M),r.close(),r})(),color:"#ffffff",style:"stroke",strokeWidth:3}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-v/2,M),r.lineTo(k-C/2,W+.2*x),r.lineTo(k+C/2,W+.2*x),r.lineTo(k+v/2,M),r.close(),r})(),color:w}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-v/2+5,M-5),r.lineTo(k-C/2+5,W+.2*x),r.lineTo(k+C/2-5,W+.2*x),r.lineTo(k+v/2-5,M-5),r.close(),r})(),color:"rgba(255, 255, 255, 0.2)"}),f(h,{x:k-C/2,y:W,width:C,height:.25*x,r:12,color:"#ffffff",style:"stroke",strokeWidth:3}),f(h,{x:k-C/2,y:W,width:C,height:.25*x,r:12,color:w}),f(o,{cx:k,cy:W+.12*x,r:.16*n,color:"#ffffff",style:"stroke",strokeWidth:2}),f(o,{cx:k,cy:W+.12*x,r:.16*n,color:m?"#ffffff":"#555555"}),f(h,{x:k-.11*n,y:W+.08*x,width:.22*n,height:.05*x,r:2,color:m?w:"#333333"}),f(h,{x:k-B/2,y:u,width:B,height:.2*x,r:10,color:w}),f(h,{x:k-.35*B,y:u+.02*x,width:.7*B,height:.06*x,r:5,color:"rgba(255, 255, 255, 0.35)"}),f(c,{x:k-.08*n,y:u,width:.16*n,height:.2*x,color:"rgba(0, 0, 0, 0.15)"}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-B/2,u),r.lineTo(k-j/2,b+.1*x),r.lineTo(k+j/2,b+.1*x),r.lineTo(k+B/2,u),r.close(),r})(),color:"#ffffff",style:"stroke",strokeWidth:3}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-B/2,u),r.lineTo(k-j/2,b+.1*x),r.lineTo(k+j/2,b+.1*x),r.lineTo(k+B/2,u),r.close(),r})(),color:w}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-B/2+5,u),r.lineTo(k-j/2+3,b+.12*x),r.lineTo(k+j/2-3,b+.12*x),r.lineTo(k+B/2-5,u),r.close(),r})(),color:"rgba(255, 255, 255, 0.25)"}),f(h,{x:k-q,y:X,width:F,height:P,r:4,color:"#4a4a4a"}),f(h,{x:k-q+2,y:X+2,width:F-4,height:P-4,r:3,color:"#888888"}),f(h,{x:k-q+4,y:X+4,width:F-8,height:P-8,r:2,color:"#cccccc"}),f(h,{x:k+q-F,y:X,width:F,height:P,r:4,color:"#4a4a4a"}),f(h,{x:k+q-F+2,y:X+2,width:F-4,height:P-4,r:3,color:"#888888"}),f(h,{x:k+q-F+4,y:X+4,width:F-8,height:P-8,r:2,color:"#cccccc"}),f(e,{path:(()=>{const r=i.Path.Make();return r.moveTo(k-j/2,b+.08*x),r.lineTo(k,b),r.lineTo(k+j/2,b+.08*x),r.close(),r})(),color:w}),f(h,{x:k-.15*n,y:b+.02*x,width:.3*n,height:.04*x,r:3,color:"#ffff99"}),f(h,{x:k-.12*n,y:b+.025*x,width:.24*n,height:.025*x,r:2,color:"#ffffdd"}),f(o,{cx:k-C/2-3,cy:u+.1*x,r:.08*n,color:"rgba(100, 200, 255, 0.4)"}),f(o,{cx:k+C/2+3,cy:u+.1*x,r:.08*n,color:"rgba(100, 200, 255, 0.4)"}),f(o,{cx:k-C/2-3,cy:u+.1*x,r:.08*n,color:w,style:"stroke",strokeWidth:2}),f(o,{cx:k+C/2+3,cy:u+.1*x,r:.08*n,color:w,style:"stroke",strokeWidth:2}),f(h,{x:k+v/2-.1*n,y:M-.08*x,width:.07*n,height:.06*x,r:3,color:"#555555"}),f(h,{x:k+v/2-.1*n+1,y:M-.08*x+1,width:.05*n,height:.04*x,r:2,color:"#333333"}),m&&d(y,{children:[f(o,{cx:k+v/2-.07*n,cy:M+.01*x,r:3,color:"rgba(150, 150, 150, 0.5)"}),f(o,{cx:k+v/2-.07*n,cy:M+.04*x,r:4,color:"rgba(150, 150, 150, 0.35)"}),f(o,{cx:k+v/2-.07*n,cy:M+.08*x,r:5,color:"rgba(150, 150, 150, 0.2)"})]}),m&&f(h,{x:k-.1*n,y:W+.18*x,width:.2*n,height:.06*x,r:3,color:"rgba(255, 255, 255, 0.95)"}),f(h,{x:k-.08*n,y:M-.02*x,width:.16*n,height:.02*x,r:2,color:"#ff3333"})]})})},n=(r,t)=>Math.floor(r.x)===Math.floor(t.x)&&Math.floor(r.y)===Math.floor(t.y)&&r.width===t.width&&r.height===t.height&&r.color===t.color&&r.isPlayer===t.isPlayer;export const BikeComponent=r.memo(g,n);BikeComponent.displayName="BikeComponent";
@@ -1 +1 @@
1
- "use strict";import React from 'react';import{Canvas,Rect,LinearGradient,vec,Line}from '@shopify/react-native-skia';import{BIKE_RACING_COLORS,BIKE_RACING_GAME_CONFIG}from "../BikeRacingConstants.js";import{jsx as _jsx,jsxs as _jsxs}from "react/jsx-runtime";const GameBackgroundComponent =({width,height,roadOffset})=>{const roadWidth = BIKE_RACING_GAME_CONFIG.LANE_WIDTH * BIKE_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:[BIKE_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:[BIKE_RACING_COLORS.GRASS_DARK,BIKE_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:[BIKE_RACING_COLORS.GRASS_GREEN,BIKE_RACING_COLORS.GRASS_DARK]})}),_jsx(Rect,{x:roadStartX,y:0,width:roadWidth,height:height,color:BIKE_RACING_COLORS.ROAD_DARK}),[1,2].map(laneIndex =>{const lineX = roadStartX + laneIndex * BIKE_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:BIKE_RACING_COLORS.ROAD_LINE,strokeWidth:2},`line-${laneIndex}-${i}`);})},`lane-${laneIndex}`);}),_jsx(Line,{p1:vec(roadStartX,0),p2:vec(roadStartX,height),color:BIKE_RACING_COLORS.ROAD_LINE,strokeWidth:3}),_jsx(Line,{p1:vec(roadStartX + roadWidth,0),p2:vec(roadStartX + roadWidth,height),color:BIKE_RACING_COLORS.ROAD_LINE,strokeWidth:3})]});};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 i,Line as h}from"@shopify/react-native-skia";import{BIKE_RACING_COLORS as s,BIKE_RACING_GAME_CONFIG as n}from"../BikeRacingConstants.js";import{jsx as c,jsxs as a}from"react/jsx-runtime";const d=({width:d,height:l,roadOffset:m})=>{const p=n.LANE_WIDTH*n.ROAD_LANES,g=(d-p)/2,k=g,u=m%40;return a(r,{style:{width:d,height:l},children:[c(e,{x:0,y:0,width:d,height:l,children:c(o,{start:i(d/2,0),end:i(d/2,l),colors:[s.SKY_BLUE,"#b0e0e6"]})}),c(e,{x:0,y:0,width:k,height:l,children:c(o,{start:i(0,0),end:i(k,0),colors:[s.GRASS_DARK,s.GRASS_GREEN]})}),c(e,{x:g+p,y:0,width:k,height:l,children:c(o,{start:i(0,0),end:i(k,0),colors:[s.GRASS_GREEN,s.GRASS_DARK]})}),c(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 c(t.Fragment,{children:Array.from({length:o}).map((t,o)=>{const n=40*o-u;return c(h,{p1:i(e,n),p2:i(e,n+30),color:s.ROAD_LINE,strokeWidth:2},`line-${r}-${o}`)})},"lane-"+r)}),c(h,{p1:i(g,0),p2:i(g,l),color:s.ROAD_LINE,strokeWidth:3}),c(h,{p1:i(g+p,0),p2:i(g+p,l),color:s.ROAD_LINE,strokeWidth:3})]})},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{BIKE_RACING_COLORS}from "../BikeRacingConstants.js";import{useScore,useTimeLeft,useLives}from "../BikeRacingStore.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,102,0,0.4)",borderColor:"rgba(255,102,0,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:BIKE_RACING_COLORS.UI},heartsContainer:{flexDirection:'row',gap:4},heartIcon:{fontSize:22}});
1
+ "use strict";import e from"react";import{View as t,Text as r,StyleSheet as o}from"react-native";import{ScoreBoardContainer as n}from"../../../helpers/index.js";import{BIKE_RACING_COLORS as i}from"../BikeRacingConstants.js";import{useScore as l,useTimeLeft as c,useLives as s}from"../BikeRacingStore.js";import{jsx as f,jsxs as a}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 f(n,{offset:o,backgroundColor:"rgba(255, 102, 0, 0.4)",borderColor:"rgba(255, 102, 0, 0.4)",children:a(t,{style:d.rowContainer,children:[a(t,{style:d.scoreSection,children:[f(r,{style:d.label,children:"SCORE"}),f(r,{style:d.value,children:i})]}),a(t,{style:d.timeSection,children:[f(r,{style:d.label,children:"TIME"}),f(r,{style:[d.value,10>=m&&d.timeWarning],children:g})]}),a(t,{style:d.livesSection,children:[f(r,{style:d.label,children:"LIVES"}),f(t,{style:d.heartsContainer,children:Array.from({length:3}).map((e,t)=>f(r,{style:d.heartIcon,children:h>t?"\u2764\ufe0f":"\ud83d\udda4"},t))})]})]})})});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{BikeComponent}from "./BikeComponent.js";export{GameBackground}from "./GameBackground.js";export{ScoreBoard}from "./ScoreBoard.js";
1
+ "use strict";export{BikeComponent}from"./BikeComponent.js";export{GameBackground}from"./GameBackground.js";export{ScoreBoard}from"./ScoreBoard.js";
@@ -1 +1 @@
1
- "use strict";export{BikeRacing}from "./BikeRacing.js";export{BikeRacingService}from "./BikeRacingService.js";export{useBikeRacingStore}from "./BikeRacingStore.js";export * from "./BikeRacingConstants.js";
1
+ "use strict";export{BikeRacing}from"./BikeRacing.js";export{BikeRacingService}from"./BikeRacingService.js";export{useBikeRacingStore}from"./BikeRacingStore.js";export*from"./BikeRacingConstants.js";