react-native-games 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -368
- package/lib/module/games/balloon-blaster/BalloonBlaster.js +1 -167
- package/lib/module/games/balloon-blaster/BalloonBlaster.js.map +1 -1
- package/lib/module/games/balloon-blaster/BalloonBlasterConstants.js +1 -182
- package/lib/module/games/balloon-blaster/BalloonBlasterConstants.js.map +1 -1
- package/lib/module/games/balloon-blaster/BalloonBlasterService.js +1 -318
- package/lib/module/games/balloon-blaster/BalloonBlasterStore.js +1 -183
- package/lib/module/games/balloon-blaster/components/BalloonComponent.js +1 -237
- package/lib/module/games/balloon-blaster/components/GameArea.js +1 -156
- package/lib/module/games/balloon-blaster/components/GameBackground.js +1 -476
- package/lib/module/games/balloon-blaster/components/ScoreBoard.js +1 -112
- package/lib/module/games/balloon-blaster/components/ScoreBoard.js.map +1 -1
- package/lib/module/games/balloon-blaster/components/index.js +1 -7
- package/lib/module/games/candy-crush/CandyCrush.js +1 -131
- package/lib/module/games/candy-crush/CandyCrush.js.map +1 -1
- package/lib/module/games/candy-crush/CandyCrushConstants.js +1 -125
- package/lib/module/games/candy-crush/CandyCrushConstants.js.map +1 -1
- package/lib/module/games/candy-crush/CandyCrushService.js +1 -370
- package/lib/module/games/candy-crush/CandyCrushStore.js +1 -303
- package/lib/module/games/candy-crush/components/CandyItem.js +1 -191
- package/lib/module/games/candy-crush/components/GameBackground.js +1 -85
- package/lib/module/games/candy-crush/components/GameGrid.js +1 -314
- package/lib/module/games/candy-crush/components/ScoreBoard.js +1 -79
- package/lib/module/games/candy-crush/components/index.js +1 -7
- package/lib/module/games/candy-crush/index.js +1 -6
- package/lib/module/games/colors-sort/ColorsSort.js +1 -143
- package/lib/module/games/colors-sort/ColorsSort.js.map +1 -1
- package/lib/module/games/colors-sort/ColorsSortConstants.js +1 -72
- package/lib/module/games/colors-sort/ColorsSortConstants.js.map +1 -1
- package/lib/module/games/colors-sort/ColorsSortService.js +1 -255
- package/lib/module/games/colors-sort/ColorsSortStore.js +1 -257
- package/lib/module/games/colors-sort/ColorsSortStore.js.map +1 -1
- package/lib/module/games/colors-sort/components/ColorContainer.js +1 -140
- package/lib/module/games/colors-sort/components/GameBackground.js +1 -135
- package/lib/module/games/colors-sort/components/ScoreBoard.js +1 -70
- package/lib/module/games/colors-sort/components/index.js +1 -6
- package/lib/module/games/dino-jump/DinoJump.js +1 -209
- package/lib/module/games/dino-jump/DinoJump.js.map +1 -1
- package/lib/module/games/dino-jump/DinoJumpConstants.js +1 -189
- package/lib/module/games/dino-jump/DinoJumpConstants.js.map +1 -1
- package/lib/module/games/dino-jump/DinoJumpService.js +1 -270
- package/lib/module/games/dino-jump/DinoJumpStore.js +1 -381
- package/lib/module/games/dino-jump/components/DinoSprite.js +1 -418
- package/lib/module/games/dino-jump/components/DinoSprite.js.map +1 -1
- package/lib/module/games/dino-jump/components/GameArea.js +1 -68
- package/lib/module/games/dino-jump/components/GameBackground.js +1 -444
- package/lib/module/games/dino-jump/components/ObstacleSprite.js +1 -306
- package/lib/module/games/dino-jump/components/ScoreBoard.js +1 -105
- package/lib/module/games/dino-jump/components/ScoreBoard.js.map +1 -1
- package/lib/module/games/dino-jump/components/StarSprite.js +1 -45
- package/lib/module/games/dino-jump/components/index.js +1 -9
- package/lib/module/games/flappy-bird/FlappyBird.js +1 -126
- package/lib/module/games/flappy-bird/FlappyBird.js.map +1 -1
- package/lib/module/games/flappy-bird/FlappyBirdConstants.js +1 -90
- package/lib/module/games/flappy-bird/FlappyBirdConstants.js.map +1 -1
- package/lib/module/games/flappy-bird/FlappyBirdStore.js +1 -300
- package/lib/module/games/flappy-bird/components/Bird.js +1 -87
- package/lib/module/games/flappy-bird/components/GameArea.js +1 -87
- package/lib/module/games/flappy-bird/components/GameBackground.js +1 -79
- package/lib/module/games/flappy-bird/components/Pipes.js +1 -172
- package/lib/module/games/flappy-bird/components/ScoreBoard.js +1 -73
- package/lib/module/games/flappy-bird/components/index.js +1 -8
- package/lib/module/games/fruit-merger/FruitMerger.js +1 -120
- package/lib/module/games/fruit-merger/FruitMerger.js.map +1 -1
- package/lib/module/games/fruit-merger/FruitMergerConstants.js +1 -119
- package/lib/module/games/fruit-merger/FruitMergerConstants.js.map +1 -1
- package/lib/module/games/fruit-merger/FruitMergerService.js +1 -13
- package/lib/module/games/fruit-merger/FruitMergerStore.js +1 -315
- package/lib/module/games/fruit-merger/components/FruitItem.js +1 -102
- package/lib/module/games/fruit-merger/components/GameArea.js +1 -103
- package/lib/module/games/fruit-merger/components/GameBackground.js +1 -498
- package/lib/module/games/fruit-merger/components/ScoreBoard.js +1 -58
- package/lib/module/games/fruit-merger/components/index.js +1 -7
- package/lib/module/games/fruit-ninja/FruitNinja.js +1 -134
- package/lib/module/games/fruit-ninja/FruitNinja.js.map +1 -1
- package/lib/module/games/fruit-ninja/FruitNinjaConstants.js +1 -148
- package/lib/module/games/fruit-ninja/FruitNinjaConstants.js.map +1 -1
- package/lib/module/games/fruit-ninja/FruitNinjaService.js +1 -311
- package/lib/module/games/fruit-ninja/FruitNinjaStore.js +1 -191
- package/lib/module/games/fruit-ninja/FruitNinjaStore.js.map +1 -1
- package/lib/module/games/fruit-ninja/components/FruitComponent.js +1 -99
- package/lib/module/games/fruit-ninja/components/GameArea.js +1 -215
- package/lib/module/games/fruit-ninja/components/GameBackground.js +1 -1267
- package/lib/module/games/fruit-ninja/components/ScoreBoard.js +1 -92
- package/lib/module/games/fruit-ninja/components/ScoreBoard.js.map +1 -1
- package/lib/module/games/fruit-ninja/components/index.js +1 -7
- package/lib/module/games/game-2048/Game2048.js +1 -149
- package/lib/module/games/game-2048/Game2048.js.map +1 -1
- package/lib/module/games/game-2048/Game2048Constants.js +1 -263
- package/lib/module/games/game-2048/Game2048Constants.js.map +1 -1
- package/lib/module/games/game-2048/Game2048Service.js +1 -457
- package/lib/module/games/game-2048/Game2048Store.js +1 -236
- package/lib/module/games/game-2048/components/GameBackground.js +1 -247
- package/lib/module/games/game-2048/components/GameGrid.js +1 -139
- package/lib/module/games/game-2048/components/GameTile.js +1 -72
- package/lib/module/games/game-2048/components/ScoreBoard.js +1 -52
- package/lib/module/games/game-2048/components/index.js +1 -7
- package/lib/module/games/maze-runner/MazeRunner.js +1 -267
- package/lib/module/games/maze-runner/MazeRunner.js.map +1 -1
- package/lib/module/games/maze-runner/MazeRunnerConstants.js +1 -100
- package/lib/module/games/maze-runner/MazeRunnerConstants.js.map +1 -1
- package/lib/module/games/maze-runner/MazeRunnerService.js +1 -586
- package/lib/module/games/maze-runner/components/EnhancedBallComponent.js +1 -150
- package/lib/module/games/maze-runner/components/EnhancedGameArea.js +1 -370
- package/lib/module/games/maze-runner/components/GameBackground.js +1 -175
- package/lib/module/games/maze-runner/components/ScoreBoard.js +1 -61
- package/lib/module/games/maze-runner/components/SkiaPipeComponent.js +1 -209
- package/lib/module/games/maze-runner/components/StaticGameBackground.js +1 -169
- package/lib/module/games/maze-runner/components/WallComponent.js +1 -91
- package/lib/module/games/maze-runner/components/index.js +1 -8
- package/lib/module/games/popit-fidget/PopitFidget.js +1 -285
- package/lib/module/games/popit-fidget/PopitFidget.js.map +1 -1
- package/lib/module/games/popit-fidget/PopitFidgetConstants.js +1 -113
- package/lib/module/games/popit-fidget/PopitFidgetConstants.js.map +1 -1
- package/lib/module/games/popit-fidget/PopitFidgetService.js +1 -132
- package/lib/module/games/popit-fidget/PopitFidgetStore.js +1 -125
- package/lib/module/games/popit-fidget/components/BubbleComponent.js +1 -198
- package/lib/module/games/popit-fidget/components/FidgetGrid.js +1 -165
- package/lib/module/games/popit-fidget/components/GameBackground.js +1 -177
- package/lib/module/games/popit-fidget/components/ScoreBoard.js +1 -61
- package/lib/module/games/popit-fidget/components/index.js +1 -7
- package/lib/module/games/sliding-numbers/SlidingNumbers.js +1 -159
- package/lib/module/games/sliding-numbers/SlidingNumbers.js.map +1 -1
- package/lib/module/games/sliding-numbers/SlidingNumbersConstants.js +1 -207
- package/lib/module/games/sliding-numbers/SlidingNumbersConstants.js.map +1 -1
- package/lib/module/games/sliding-numbers/SlidingNumbersService.js +1 -248
- package/lib/module/games/sliding-numbers/SlidingNumbersStore.js +1 -274
- package/lib/module/games/sliding-numbers/components/GameBackground.js +1 -259
- package/lib/module/games/sliding-numbers/components/NumbersGrid.js +1 -174
- package/lib/module/games/sliding-numbers/components/NumbersTile.js +1 -116
- package/lib/module/games/sliding-numbers/components/ScoreBoard.js +1 -64
- package/lib/module/games/sliding-numbers/components/index.js +1 -7
- package/lib/module/games/snake/Snake.js +1 -189
- package/lib/module/games/snake/Snake.js.map +1 -1
- package/lib/module/games/snake/SnakeConstants.js +1 -138
- package/lib/module/games/snake/SnakeConstants.js.map +1 -1
- package/lib/module/games/snake/SnakeService.js +1 -148
- package/lib/module/games/snake/SnakeStore.js +1 -182
- package/lib/module/games/snake/components/GameBackground.js +1 -221
- package/lib/module/games/snake/components/GameGrid.js +1 -153
- package/lib/module/games/snake/components/ScoreBoard.js +1 -51
- package/lib/module/games/snake/components/index.js +1 -6
- package/lib/module/games/snake/index.js +1 -6
- package/lib/module/games/space-fighter/SpaceFighter.js +1 -165
- package/lib/module/games/space-fighter/SpaceFighter.js.map +1 -1
- package/lib/module/games/space-fighter/SpaceFighterConstants.js +1 -108
- package/lib/module/games/space-fighter/SpaceFighterConstants.js.map +1 -1
- package/lib/module/games/space-fighter/SpaceFighterService.js +1 -326
- package/lib/module/games/space-fighter/SpaceFighterStore.js +1 -209
- package/lib/module/games/space-fighter/components/AsteroidComponent.js +1 -113
- package/lib/module/games/space-fighter/components/GameArea.js +1 -289
- package/lib/module/games/space-fighter/components/GameBackground.js +1 -239
- package/lib/module/games/space-fighter/components/ScoreBoard.js +1 -136
- package/lib/module/games/space-fighter/components/Spacecraft3D.js +1 -202
- package/lib/module/games/space-fighter/components/SpacecraftPath.js +1 -52
- package/lib/module/games/space-fighter/components/index.js +1 -9
- package/lib/module/games/whack-a-mole/WhackAMole.js +1 -270
- package/lib/module/games/whack-a-mole/WhackAMole.js.map +1 -1
- package/lib/module/games/whack-a-mole/WhackAMoleConstants.js +1 -115
- package/lib/module/games/whack-a-mole/WhackAMoleConstants.js.map +1 -1
- package/lib/module/games/whack-a-mole/WhackAMoleService.js +1 -120
- package/lib/module/games/whack-a-mole/WhackAMoleStore.js +1 -172
- package/lib/module/games/whack-a-mole/components/GameBackground.js +1 -477
- package/lib/module/games/whack-a-mole/components/GameGrid.js +1 -97
- package/lib/module/games/whack-a-mole/components/GameHole.js +1 -196
- package/lib/module/games/whack-a-mole/components/MoleCharacter.js +1 -241
- package/lib/module/games/whack-a-mole/components/ScoreBoard.js +1 -67
- package/lib/module/games/whack-a-mole/components/ScoreBoard.js.map +1 -1
- package/lib/module/games/whack-a-mole/components/index.js +1 -8
- package/lib/module/helpers/AnimationFrame.js +1 -120
- package/lib/module/helpers/AnimationTracker.js +1 -89
- package/lib/module/helpers/ErrorHandler.js +1 -269
- package/lib/module/helpers/GameControlButton.js +1 -219
- package/lib/module/helpers/GameOverModal.js +1 -144
- package/lib/module/helpers/GameOverModal.js.map +1 -1
- package/lib/module/helpers/GameSettingsModal.js +1 -287
- package/lib/module/helpers/ParticleBlast.js +1 -134
- package/lib/module/helpers/ScoreBoardContainer.js +1 -34
- package/lib/module/helpers/index.js +1 -12
- package/lib/module/index.js +1 -22
- package/lib/module/services/GamesConstants.js +1 -178
- package/lib/module/services/GamesService.js +1 -112
- package/lib/module/services/GamesService.js.map +1 -1
- package/lib/module/services/HapticsService.js +1 -77
- package/lib/module/services/SoundsService.js +1 -302
- package/lib/module/services/UtilsService.js +1 -32
- package/lib/typescript/src/games/balloon-blaster/BalloonBlaster.d.ts.map +1 -1
- package/lib/typescript/src/games/balloon-blaster/BalloonBlasterConstants.d.ts +1 -1
- package/lib/typescript/src/games/balloon-blaster/components/ScoreBoard.d.ts.map +1 -1
- package/lib/typescript/src/games/candy-crush/CandyCrushConstants.d.ts +7 -7
- package/lib/typescript/src/games/colors-sort/ColorsSort.d.ts.map +1 -1
- package/lib/typescript/src/games/colors-sort/ColorsSortStore.d.ts.map +1 -1
- package/lib/typescript/src/games/dino-jump/DinoJump.d.ts.map +1 -1
- package/lib/typescript/src/games/dino-jump/components/DinoSprite.d.ts.map +1 -1
- package/lib/typescript/src/games/flappy-bird/FlappyBird.d.ts.map +1 -1
- package/lib/typescript/src/games/flappy-bird/FlappyBirdConstants.d.ts.map +1 -1
- package/lib/typescript/src/games/fruit-merger/FruitMerger.d.ts.map +1 -1
- package/lib/typescript/src/games/fruit-merger/FruitMergerConstants.d.ts.map +1 -1
- package/lib/typescript/src/games/fruit-ninja/FruitNinja.d.ts.map +1 -1
- package/lib/typescript/src/games/fruit-ninja/components/ScoreBoard.d.ts.map +1 -1
- package/lib/typescript/src/games/game-2048/Game2048.d.ts.map +1 -1
- package/lib/typescript/src/games/maze-runner/MazeRunner.d.ts.map +1 -1
- package/lib/typescript/src/games/popit-fidget/PopitFidget.d.ts.map +1 -1
- package/lib/typescript/src/games/sliding-numbers/SlidingNumbers.d.ts.map +1 -1
- package/lib/typescript/src/games/space-fighter/SpaceFighter.d.ts.map +1 -1
- package/lib/typescript/src/games/whack-a-mole/WhackAMole.d.ts.map +1 -1
- package/lib/typescript/src/games/whack-a-mole/WhackAMoleConstants.d.ts +1 -1
- package/lib/typescript/src/games/whack-a-mole/components/ScoreBoard.d.ts.map +1 -1
- package/lib/typescript/src/helpers/GameOverModal.d.ts +3 -0
- package/lib/typescript/src/helpers/GameOverModal.d.ts.map +1 -1
- package/lib/typescript/src/services/GamesConstants.d.ts +7 -7
- package/package.json +2 -2
|
@@ -1,237 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import React, { useEffect, useMemo, useCallback } from 'react';
|
|
4
|
-
import { TouchableOpacity, Dimensions } from 'react-native';
|
|
5
|
-
import { Canvas, vec, Path, Skia, Oval, Circle } from '@shopify/react-native-skia';
|
|
6
|
-
import Animated, { useSharedValue, useAnimatedStyle, withSpring, withTiming } from 'react-native-reanimated';
|
|
7
|
-
import { GAME_CONFIG, ANIMATION_CONFIG } from "../BalloonBlasterService.js";
|
|
8
|
-
|
|
9
|
-
// Constants for better maintainability
|
|
10
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
const BALLOON_HEIGHT_MULTIPLIER = 1.2;
|
|
12
|
-
const STRING_LENGTH = 25;
|
|
13
|
-
const HIGHLIGHT_OPACITY = 0.5;
|
|
14
|
-
const BALLOON_OPACITY = 0.8;
|
|
15
|
-
const DANGER_CIRCLE_RADIUS = 8;
|
|
16
|
-
const GLOW_RADIUS_MULTIPLIER = 0.6;
|
|
17
|
-
const GLOW_OPACITY = 0.3;
|
|
18
|
-
|
|
19
|
-
// Types for better type safety
|
|
20
|
-
|
|
21
|
-
export const BalloonComponent = /*#__PURE__*/React.memo(({
|
|
22
|
-
balloon,
|
|
23
|
-
onPop
|
|
24
|
-
}) => {
|
|
25
|
-
// Get screen dimensions
|
|
26
|
-
const {
|
|
27
|
-
height
|
|
28
|
-
} = Dimensions.get('window');
|
|
29
|
-
|
|
30
|
-
// FORCE all balloons to start from bottom - override any wrong positions
|
|
31
|
-
const initialY = balloon.position.y > height ? balloon.position.y : height - 30;
|
|
32
|
-
|
|
33
|
-
// Animated values for smooth movement
|
|
34
|
-
const translateX = useSharedValue(balloon.position.x);
|
|
35
|
-
const translateY = useSharedValue(initialY); // Force bottom start
|
|
36
|
-
const rotation = useSharedValue(balloon.rotation);
|
|
37
|
-
const scale = useSharedValue(balloon.isPopped ? 0 : 1);
|
|
38
|
-
const opacity = useSharedValue(balloon.isPopped ? 0 : 1);
|
|
39
|
-
|
|
40
|
-
// Update animated values when balloon properties change
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
translateX.value = withSpring(balloon.position.x, ANIMATION_CONFIG.BALLOON_SPRING);
|
|
43
|
-
translateY.value = withSpring(balloon.position.y, ANIMATION_CONFIG.BALLOON_SPRING);
|
|
44
|
-
rotation.value = withSpring(balloon.rotation, ANIMATION_CONFIG.BALLOON_SPRING);
|
|
45
|
-
}, [balloon.position.x, balloon.position.y, balloon.rotation]);
|
|
46
|
-
|
|
47
|
-
// Handle popped state with animation
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
if (balloon.isPopped) {
|
|
50
|
-
scale.value = withTiming(0, ANIMATION_CONFIG.SLICE_TIMING);
|
|
51
|
-
opacity.value = withTiming(0, ANIMATION_CONFIG.SLICE_TIMING);
|
|
52
|
-
} else {
|
|
53
|
-
scale.value = withSpring(1, ANIMATION_CONFIG.BALLOON_SPRING);
|
|
54
|
-
opacity.value = withSpring(1, ANIMATION_CONFIG.BALLOON_SPRING);
|
|
55
|
-
}
|
|
56
|
-
}, [balloon.isPopped]);
|
|
57
|
-
|
|
58
|
-
// Animated style
|
|
59
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
60
|
-
return {
|
|
61
|
-
transform: [{
|
|
62
|
-
translateX: translateX.value
|
|
63
|
-
}, {
|
|
64
|
-
translateY: translateY.value
|
|
65
|
-
}, {
|
|
66
|
-
rotate: `${rotation.value}rad`
|
|
67
|
-
}, {
|
|
68
|
-
scale: scale.value
|
|
69
|
-
}],
|
|
70
|
-
opacity: opacity.value
|
|
71
|
-
};
|
|
72
|
-
});
|
|
73
|
-
const containerStyle = {
|
|
74
|
-
position: 'absolute',
|
|
75
|
-
width: GAME_CONFIG.BALLOON_SIZE,
|
|
76
|
-
height: GAME_CONFIG.BALLOON_SIZE,
|
|
77
|
-
zIndex: balloon.isBomb ? 10 : 5
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// Optimized color manipulation functions
|
|
81
|
-
const lightenColor = useCallback((color, amount) => {
|
|
82
|
-
const hex = color.replace('#', '');
|
|
83
|
-
const r = Math.min(255, parseInt(hex.substring(0, 2), 16) + Math.round(255 * amount));
|
|
84
|
-
const g = Math.min(255, parseInt(hex.substring(2, 4), 16) + Math.round(255 * amount));
|
|
85
|
-
const b = Math.min(255, parseInt(hex.substring(4, 6), 16) + Math.round(255 * amount));
|
|
86
|
-
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
87
|
-
}, []);
|
|
88
|
-
const darkenColor = useCallback((color, amount) => {
|
|
89
|
-
const hex = color.replace('#', '');
|
|
90
|
-
const r = Math.max(0, parseInt(hex.substring(0, 2), 16) - Math.round(255 * amount));
|
|
91
|
-
const g = Math.max(0, parseInt(hex.substring(2, 4), 16) - Math.round(255 * amount));
|
|
92
|
-
const b = Math.max(0, parseInt(hex.substring(4, 6), 16) - Math.round(255 * amount));
|
|
93
|
-
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
94
|
-
}, []);
|
|
95
|
-
|
|
96
|
-
// Optimized balloon color calculation with proper memoization
|
|
97
|
-
const colors = useMemo(() => {
|
|
98
|
-
if (balloon.isBomb) {
|
|
99
|
-
return {
|
|
100
|
-
primary: '#1a1a1a',
|
|
101
|
-
secondary: '#333333',
|
|
102
|
-
highlight: '#555555',
|
|
103
|
-
shadow: '#000000'
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
if (balloon.isBonus) {
|
|
107
|
-
return {
|
|
108
|
-
primary: '#FFD700',
|
|
109
|
-
secondary: '#FFEB3B',
|
|
110
|
-
highlight: '#FFF59D',
|
|
111
|
-
shadow: '#CC8800'
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Regular balloon colors with optimized calculation
|
|
116
|
-
const baseColor = balloon.type.color || '#FF0080';
|
|
117
|
-
return {
|
|
118
|
-
primary: baseColor,
|
|
119
|
-
secondary: lightenColor(baseColor, 0.3),
|
|
120
|
-
highlight: lightenColor(baseColor, 0.5),
|
|
121
|
-
shadow: darkenColor(baseColor, 0.3)
|
|
122
|
-
};
|
|
123
|
-
}, [balloon.isBomb, balloon.isBonus, balloon.type.color, lightenColor, darkenColor]);
|
|
124
|
-
|
|
125
|
-
// Memoized dimensions for better performance
|
|
126
|
-
const dimensions = useMemo(() => {
|
|
127
|
-
const balloonWidth = GAME_CONFIG.BALLOON_SIZE;
|
|
128
|
-
const balloonHeight = GAME_CONFIG.BALLOON_SIZE * BALLOON_HEIGHT_MULTIPLIER;
|
|
129
|
-
const totalHeight = balloonHeight + STRING_LENGTH;
|
|
130
|
-
const center = vec(balloonWidth / 2, balloonHeight / 2);
|
|
131
|
-
return {
|
|
132
|
-
balloonWidth,
|
|
133
|
-
balloonHeight,
|
|
134
|
-
totalHeight,
|
|
135
|
-
center
|
|
136
|
-
};
|
|
137
|
-
}, []);
|
|
138
|
-
|
|
139
|
-
// Optimized curved string path generation with better memoization
|
|
140
|
-
const curvedStringPath = useMemo(() => {
|
|
141
|
-
const path = Skia.Path.Make();
|
|
142
|
-
const startX = dimensions.center.x;
|
|
143
|
-
const startY = dimensions.balloonHeight - 2;
|
|
144
|
-
|
|
145
|
-
// Optimized seed generation for consistent random curves
|
|
146
|
-
const seed = balloon.id.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
|
|
147
|
-
const random = index => (seed + index * 17) % 100 / 100;
|
|
148
|
-
path.moveTo(startX, startY);
|
|
149
|
-
|
|
150
|
-
// Optimized string generation with minimal segments
|
|
151
|
-
const segments = 2;
|
|
152
|
-
const segmentHeight = STRING_LENGTH / segments;
|
|
153
|
-
for (let i = 1; i <= segments; i++) {
|
|
154
|
-
const y = startY + segmentHeight * i;
|
|
155
|
-
const waveAmplitude = 2 + random(i) * 2;
|
|
156
|
-
const waveOffset = (random(i + 10) - 0.5) * waveAmplitude;
|
|
157
|
-
const x = startX + waveOffset;
|
|
158
|
-
const controlX1 = startX + (random(i + 20) - 0.5) * waveAmplitude * 0.5;
|
|
159
|
-
const controlY1 = y - segmentHeight * 0.5;
|
|
160
|
-
path.quadTo(controlX1, controlY1, x, y);
|
|
161
|
-
}
|
|
162
|
-
return path;
|
|
163
|
-
}, [balloon.id, dimensions.center.x, dimensions.balloonHeight]);
|
|
164
|
-
|
|
165
|
-
// Memoized tap handler for better performance
|
|
166
|
-
const handleTap = useCallback(() => {
|
|
167
|
-
onPop?.(balloon.id);
|
|
168
|
-
}, [onPop, balloon.id]);
|
|
169
|
-
return /*#__PURE__*/_jsx(Animated.View, {
|
|
170
|
-
style: [containerStyle, animatedStyle],
|
|
171
|
-
children: /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
172
|
-
onPress: handleTap,
|
|
173
|
-
activeOpacity: 0.8,
|
|
174
|
-
style: {
|
|
175
|
-
width: dimensions.balloonWidth,
|
|
176
|
-
height: dimensions.totalHeight
|
|
177
|
-
},
|
|
178
|
-
children: /*#__PURE__*/_jsxs(Canvas, {
|
|
179
|
-
style: {
|
|
180
|
-
width: dimensions.balloonWidth,
|
|
181
|
-
height: dimensions.totalHeight
|
|
182
|
-
},
|
|
183
|
-
pointerEvents: "none",
|
|
184
|
-
children: [/*#__PURE__*/_jsx(Oval, {
|
|
185
|
-
x: 0,
|
|
186
|
-
y: 0,
|
|
187
|
-
width: dimensions.balloonWidth,
|
|
188
|
-
height: dimensions.balloonHeight,
|
|
189
|
-
color: colors.primary,
|
|
190
|
-
opacity: BALLOON_OPACITY
|
|
191
|
-
}), /*#__PURE__*/_jsx(Oval, {
|
|
192
|
-
x: dimensions.balloonWidth * 0.2,
|
|
193
|
-
y: dimensions.balloonHeight * 0.15,
|
|
194
|
-
width: dimensions.balloonWidth * 0.3,
|
|
195
|
-
height: dimensions.balloonHeight * 0.2,
|
|
196
|
-
color: colors.highlight,
|
|
197
|
-
opacity: HIGHLIGHT_OPACITY
|
|
198
|
-
}), balloon.isBomb && /*#__PURE__*/_jsxs(_Fragment, {
|
|
199
|
-
children: [/*#__PURE__*/_jsx(Circle, {
|
|
200
|
-
cx: dimensions.center.x,
|
|
201
|
-
cy: dimensions.center.y,
|
|
202
|
-
r: DANGER_CIRCLE_RADIUS,
|
|
203
|
-
color: "#FF0000",
|
|
204
|
-
opacity: 0.9
|
|
205
|
-
}), /*#__PURE__*/_jsx(Path, {
|
|
206
|
-
path: Skia.Path.Make().moveTo(dimensions.center.x, dimensions.center.y - 4).lineTo(dimensions.center.x, dimensions.center.y + 1),
|
|
207
|
-
color: "#FFFFFF",
|
|
208
|
-
style: "stroke",
|
|
209
|
-
strokeWidth: 2,
|
|
210
|
-
strokeCap: "round"
|
|
211
|
-
}), /*#__PURE__*/_jsx(Circle, {
|
|
212
|
-
cx: dimensions.center.x,
|
|
213
|
-
cy: dimensions.center.y + 3,
|
|
214
|
-
r: 1,
|
|
215
|
-
color: "#FFFFFF"
|
|
216
|
-
})]
|
|
217
|
-
}), !balloon.isBonus && /*#__PURE__*/_jsx(Path, {
|
|
218
|
-
path: curvedStringPath,
|
|
219
|
-
color: "#8B4513",
|
|
220
|
-
style: "stroke",
|
|
221
|
-
strokeWidth: 1.5,
|
|
222
|
-
strokeCap: "round"
|
|
223
|
-
}), balloon.isBonus && /*#__PURE__*/_jsx(Circle, {
|
|
224
|
-
cx: dimensions.center.x,
|
|
225
|
-
cy: dimensions.center.y,
|
|
226
|
-
r: dimensions.balloonWidth * GLOW_RADIUS_MULTIPLIER,
|
|
227
|
-
color: "#FFD700",
|
|
228
|
-
opacity: GLOW_OPACITY
|
|
229
|
-
})]
|
|
230
|
-
})
|
|
231
|
-
})
|
|
232
|
-
});
|
|
233
|
-
}, (prevProps, nextProps) => {
|
|
234
|
-
// Custom comparison for React.memo - only re-render if essential props change
|
|
235
|
-
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;
|
|
236
|
-
});
|
|
237
|
-
//# sourceMappingURL=BalloonComponent.js.map
|
|
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,156 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
|
4
|
-
import { View, StyleSheet } from 'react-native';
|
|
5
|
-
import { useBalloonBlasterStore } from "../BalloonBlasterStore.js";
|
|
6
|
-
import { GAME_CONFIG } from "../BalloonBlasterService.js";
|
|
7
|
-
import { playSound, GAME_SOUNDS } from "../../../services/SoundsService.js";
|
|
8
|
-
import { playHaptic, HapticType } from "../../../services/HapticsService.js";
|
|
9
|
-
import { ParticleBlast, useAnimationTracker } from "../../../helpers/index.js";
|
|
10
|
-
import { BalloonComponent } from "./BalloonComponent.js";
|
|
11
|
-
|
|
12
|
-
// Constants for better maintainability
|
|
13
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
-
const BALLOON_REMOVAL_DELAY = 500; // ms
|
|
15
|
-
const PARTICLE_COUNT = 8;
|
|
16
|
-
const PARTICLE_DURATION = 1000; // ms
|
|
17
|
-
|
|
18
|
-
// Types for better type safety
|
|
19
|
-
|
|
20
|
-
export const GameArea = /*#__PURE__*/React.memo(() => {
|
|
21
|
-
// Optimized store subscriptions - only subscribe to what we need
|
|
22
|
-
const balloons = useBalloonBlasterStore(state => state.balloons);
|
|
23
|
-
const isPlaying = useBalloonBlasterStore(state => state.isPlaying);
|
|
24
|
-
const gameOver = useBalloonBlasterStore(state => state.gameOver);
|
|
25
|
-
|
|
26
|
-
// Get store actions (these don't cause re-renders)
|
|
27
|
-
const {
|
|
28
|
-
popBalloon,
|
|
29
|
-
removeBalloon,
|
|
30
|
-
updateBalloon,
|
|
31
|
-
resetCombo,
|
|
32
|
-
loseLife,
|
|
33
|
-
addLife
|
|
34
|
-
} = useBalloonBlasterStore();
|
|
35
|
-
|
|
36
|
-
// Animation tracking for balloons using shared utility
|
|
37
|
-
const balloonAnimations = useAnimationTracker();
|
|
38
|
-
|
|
39
|
-
// State for managing active particle blasts with proper typing
|
|
40
|
-
const [activeBlasts, setActiveBlasts] = useState([]);
|
|
41
|
-
|
|
42
|
-
// Memoized sound and haptic feedback functions (using default enabled state)
|
|
43
|
-
const playPopSound = useCallback(() => {
|
|
44
|
-
playSound(GAME_SOUNDS.BALLOON_BLASTER.POP, true);
|
|
45
|
-
playHaptic(HapticType.LIGHT, true);
|
|
46
|
-
}, []);
|
|
47
|
-
const playBombSound = useCallback(() => {
|
|
48
|
-
playSound(GAME_SOUNDS.BALLOON_BLASTER.BOMB, true);
|
|
49
|
-
playHaptic(HapticType.HEAVY, true);
|
|
50
|
-
}, []);
|
|
51
|
-
|
|
52
|
-
// Optimized blast particle creation
|
|
53
|
-
const createBlastParticles = useCallback(balloon => {
|
|
54
|
-
const blastX = balloon.position.x + GAME_CONFIG.BALLOON_SIZE / 2;
|
|
55
|
-
const blastY = balloon.position.y + GAME_CONFIG.BALLOON_SIZE / 2;
|
|
56
|
-
const blastId = `blast_${Date.now()}_${Math.random()}`;
|
|
57
|
-
setActiveBlasts(prev => [...prev, {
|
|
58
|
-
id: blastId,
|
|
59
|
-
x: blastX,
|
|
60
|
-
y: blastY
|
|
61
|
-
}]);
|
|
62
|
-
}, []);
|
|
63
|
-
|
|
64
|
-
// Optimized blast completion handler
|
|
65
|
-
const handleBlastComplete = useCallback(blastId => {
|
|
66
|
-
setActiveBlasts(prev => prev.filter(blast => blast.id !== blastId));
|
|
67
|
-
}, []);
|
|
68
|
-
|
|
69
|
-
// Optimized balloon popping logic with better error handling
|
|
70
|
-
const handleBalloonPop = useCallback(balloonId => {
|
|
71
|
-
// Early exit if game is not active
|
|
72
|
-
if (!isPlaying || gameOver) return;
|
|
73
|
-
|
|
74
|
-
// Get current balloon state
|
|
75
|
-
const currentBalloons = useBalloonBlasterStore.getState().balloons;
|
|
76
|
-
const balloon = currentBalloons.find(b => b.id === balloonId);
|
|
77
|
-
|
|
78
|
-
// Validate balloon exists and is not already popped
|
|
79
|
-
if (!balloon || balloon.isPopped) return;
|
|
80
|
-
|
|
81
|
-
// Handle different balloon types with optimized logic
|
|
82
|
-
if (balloon.isBomb) {
|
|
83
|
-
// Bomb balloon - lose life and reset combo
|
|
84
|
-
playBombSound();
|
|
85
|
-
loseLife();
|
|
86
|
-
resetCombo();
|
|
87
|
-
updateBalloon(balloonId, {
|
|
88
|
-
isPopped: true
|
|
89
|
-
});
|
|
90
|
-
} else if (balloon.isBonus) {
|
|
91
|
-
// Bonus balloon - add life
|
|
92
|
-
playPopSound();
|
|
93
|
-
addLife();
|
|
94
|
-
updateBalloon(balloonId, {
|
|
95
|
-
isPopped: true
|
|
96
|
-
});
|
|
97
|
-
} else {
|
|
98
|
-
// Regular balloon - add points (popBalloon handles marking as popped)
|
|
99
|
-
playPopSound();
|
|
100
|
-
popBalloon(balloonId);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Create visual blast effect
|
|
104
|
-
createBlastParticles(balloon);
|
|
105
|
-
|
|
106
|
-
// Schedule balloon removal after animation completes
|
|
107
|
-
setTimeout(() => {
|
|
108
|
-
removeBalloon(balloonId);
|
|
109
|
-
balloonAnimations.delete(balloonId);
|
|
110
|
-
}, BALLOON_REMOVAL_DELAY);
|
|
111
|
-
}, [isPlaying, gameOver, playBombSound, playPopSound, loseLife, resetCombo, addLife, popBalloon, updateBalloon, createBlastParticles, removeBalloon, balloonAnimations]);
|
|
112
|
-
|
|
113
|
-
// Optimized balloon animation tracking
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
balloons.forEach(balloon => {
|
|
116
|
-
if (!balloonAnimations.has(balloon.id)) {
|
|
117
|
-
balloonAnimations.initialize(balloon.id);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}, [balloons, balloonAnimations]);
|
|
121
|
-
|
|
122
|
-
// Memoized balloon components for better performance
|
|
123
|
-
const balloonComponents = useMemo(() => {
|
|
124
|
-
return balloons.map(balloon => {
|
|
125
|
-
const animation = balloonAnimations.get(balloon.id);
|
|
126
|
-
return /*#__PURE__*/_jsx(BalloonComponent, {
|
|
127
|
-
balloon: balloon,
|
|
128
|
-
animation: animation,
|
|
129
|
-
onPop: handleBalloonPop
|
|
130
|
-
}, balloon.id);
|
|
131
|
-
});
|
|
132
|
-
}, [balloons, balloonAnimations, handleBalloonPop]);
|
|
133
|
-
|
|
134
|
-
// Memoized particle blast components
|
|
135
|
-
const blastComponents = useMemo(() => {
|
|
136
|
-
return activeBlasts.map(blast => /*#__PURE__*/_jsx(ParticleBlast, {
|
|
137
|
-
x: blast.x,
|
|
138
|
-
y: blast.y,
|
|
139
|
-
particleCount: PARTICLE_COUNT,
|
|
140
|
-
duration: PARTICLE_DURATION,
|
|
141
|
-
onComplete: () => handleBlastComplete(blast.id)
|
|
142
|
-
}, blast.id));
|
|
143
|
-
}, [activeBlasts, handleBlastComplete]);
|
|
144
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
145
|
-
style: styles.gameArea,
|
|
146
|
-
children: [balloonComponents, blastComponents]
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
const styles = StyleSheet.create({
|
|
150
|
-
gameArea: {
|
|
151
|
-
flex: 1,
|
|
152
|
-
position: 'relative',
|
|
153
|
-
overflow: 'hidden'
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
//# sourceMappingURL=GameArea.js.map
|
|
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'}});
|