floating-games-sdk 1.0.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/package.json +44 -0
- package/src/FloatingGames.tsx +25 -0
- package/src/assets/fonts/Creepster-Regular.ttf +0 -0
- package/src/assets/images/android-icon-background.png +0 -0
- package/src/assets/images/android-icon-foreground.png +0 -0
- package/src/assets/images/android-icon-monochrome.png +0 -0
- package/src/assets/images/blocks-icon.png +0 -0
- package/src/assets/images/bright-rubber-puzzles-blue.png +0 -0
- package/src/assets/images/close.png +0 -0
- package/src/assets/images/eriri.png +0 -0
- package/src/assets/images/favicon.png +0 -0
- package/src/assets/images/first-play.png +0 -0
- package/src/assets/images/game-over.gif +0 -0
- package/src/assets/images/game-pad.png +0 -0
- package/src/assets/images/game-pad2.png +0 -0
- package/src/assets/images/game-page-bg1.png +0 -0
- package/src/assets/images/hands-down-bg.png +0 -0
- package/src/assets/images/icon.png +0 -0
- package/src/assets/images/lets-play.gif +0 -0
- package/src/assets/images/lucky-day.gif +0 -0
- package/src/assets/images/maths.png +0 -0
- package/src/assets/images/not-playing.png +0 -0
- package/src/assets/images/number-puzzle-select.png +0 -0
- package/src/assets/images/number-puzzle-selector.png +0 -0
- package/src/assets/images/pause-clock.png +0 -0
- package/src/assets/images/pause-icon.png +0 -0
- package/src/assets/images/play-icon.png +0 -0
- package/src/assets/images/play-now.gif +0 -0
- package/src/assets/images/play-play.png +0 -0
- package/src/assets/images/play.png +0 -0
- package/src/assets/images/quit-game.png +0 -0
- package/src/assets/images/quit-icon.png +0 -0
- package/src/assets/images/quit.png +0 -0
- package/src/assets/images/review-win-selector.png +0 -0
- package/src/assets/images/select-bg.png +0 -0
- package/src/assets/images/select-logo.png +0 -0
- package/src/assets/images/spin-wheel-select.png +0 -0
- package/src/assets/images/spin-wheel-selector.png +0 -0
- package/src/assets/images/splash-icon.png +0 -0
- package/src/assets/images/start-button.png +0 -0
- package/src/assets/images/start-game.png +0 -0
- package/src/assets/images/stop-quit.png +0 -0
- package/src/assets/images/waiting-for-you.gif +0 -0
- package/src/assets/sounds/selector-music.mp3 +0 -0
- package/src/assets/sounds/timeup-sound.wav +0 -0
- package/src/components/atoms/Amount.tsx +48 -0
- package/src/components/atoms/FloatingMenu.tsx +119 -0
- package/src/components/atoms/ShimmerHR.tsx +64 -0
- package/src/components/atoms/UseAnimatedCounter.tsx +31 -0
- package/src/components/games/Chain.tsx +26 -0
- package/src/components/games/GameItem.tsx +38 -0
- package/src/components/games/GameSelectorScreen.tsx +221 -0
- package/src/components/games/GameSplash.tsx +44 -0
- package/src/components/games/HangingSign.tsx +75 -0
- package/src/components/games/SplashScreen.tsx +69 -0
- package/src/components/games/number-puzzle/DragTile.tsx +65 -0
- package/src/components/games/number-puzzle/GameScreen.tsx +597 -0
- package/src/components/games/number-puzzle/PuzzleSplash.tsx +50 -0
- package/src/components/games/number-puzzle/TileComponent.tsx +47 -0
- package/src/components/games/review-and-win/EmojiTracker.tsx +96 -0
- package/src/components/games/review-and-win/GameScreen.tsx +135 -0
- package/src/components/games/review-and-win/Tile.tsx +60 -0
- package/src/components/games/spin-wheel/SpinAndWin.tsx +507 -0
- package/src/components/payment/CheckoutScreen.tsx +50 -0
- package/src/components/payment/FundAccount.tsx +281 -0
- package/src/components/payment/Payment.tsx +45 -0
- package/src/components/reusables/AppSelect.tsx +70 -0
- package/src/components/reusables/CountdownTimer.tsx +116 -0
- package/src/components/reusables/FloatingButton.tsx +71 -0
- package/src/components/reusables/SoundPlayer.ts +28 -0
- package/src/components/utils/shuffle.ts +48 -0
- package/src/context/GameContext.tsx +15 -0
- package/src/index.tsx +5 -0
- package/src/modals/BottomSheetModal.tsx +38 -0
- package/src/modals/GameOverModal.tsx +76 -0
- package/src/modals/PauseModal.tsx +95 -0
- package/src/navigation/GameNavigator.tsx +48 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// components/EmojiTracker.tsx
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { StyleSheet, Text, View } from 'react-native';
|
|
4
|
+
import { Amount } from '../../atoms/Amount';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
counts: { [key: string]: number }, // how many times player opened
|
|
8
|
+
maxCounts: { [key: string]: number }, // how many slots to show (max 3)
|
|
9
|
+
emojiValues: { [key: string]: number } // values for each emoji
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const EMOJIS = ['😀', '🔥', '⭐'];
|
|
13
|
+
|
|
14
|
+
export default function EmojiTracker({ counts, maxCounts, emojiValues }: Props) {
|
|
15
|
+
return (
|
|
16
|
+
<View style={ styles.container }>
|
|
17
|
+
{ EMOJIS.map(emoji => {
|
|
18
|
+
const max = maxCounts[emoji] || 3; // always show up to 3 slots
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<View key={ emoji } style={ styles.row }>
|
|
22
|
+
{ [...Array(max)].map((_, i) => {
|
|
23
|
+
const active = counts[emoji] > i;
|
|
24
|
+
return (
|
|
25
|
+
<View key={ i }
|
|
26
|
+
style={ [styles.box, active && styles.active, counts[emoji] >= 3 && styles.won] }>
|
|
27
|
+
<Text style={ styles.emoji }>{ emoji }</Text>
|
|
28
|
+
</View>
|
|
29
|
+
)
|
|
30
|
+
}) }
|
|
31
|
+
|
|
32
|
+
<View style={ styles.pointCover }>
|
|
33
|
+
<Text style={ {
|
|
34
|
+
color: counts[emoji] >= 3 ? '#0ff35e' : '#f6e573',
|
|
35
|
+
fontWeight: 900,
|
|
36
|
+
fontSize: 23,
|
|
37
|
+
marginHorizontal: 4
|
|
38
|
+
} }>=</Text>
|
|
39
|
+
<Text style={ counts[emoji] >= 3 ? styles.points1 : styles.points2 }>
|
|
40
|
+
<Amount
|
|
41
|
+
value={ emojiValues[emoji] } // numeric value
|
|
42
|
+
fontSize={ 23 }
|
|
43
|
+
color={ counts[emoji] >= 3 ? '#0ff35e' : '#f6e573' }
|
|
44
|
+
/>
|
|
45
|
+
</Text>
|
|
46
|
+
{ /*<Text style={{color:'#fff'}}>{counts[emoji] >= 3 && '💰'}</Text>*/ }
|
|
47
|
+
</View>
|
|
48
|
+
</View>
|
|
49
|
+
)
|
|
50
|
+
}) }
|
|
51
|
+
</View>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const styles = StyleSheet.create({
|
|
56
|
+
container: { marginBottom: 8 },
|
|
57
|
+
row: { flexDirection: 'row', alignItems: 'center', marginBottom: 8 },
|
|
58
|
+
box: {
|
|
59
|
+
width: 50, height: 50,
|
|
60
|
+
borderWidth: 4, borderColor: '#999',
|
|
61
|
+
justifyContent: 'center', alignItems: 'center',
|
|
62
|
+
marginHorizontal: 5, borderRadius: 50
|
|
63
|
+
},
|
|
64
|
+
active: { borderColor: 'gold' },
|
|
65
|
+
emoji: { fontSize: 20 },
|
|
66
|
+
points1: {
|
|
67
|
+
marginLeft: 4,
|
|
68
|
+
fontSize: 20,
|
|
69
|
+
fontWeight: 'bold',
|
|
70
|
+
color: '#0ff35e',
|
|
71
|
+
// backgroundColor:'#fff',
|
|
72
|
+
// width: '60%'
|
|
73
|
+
},
|
|
74
|
+
points2: {
|
|
75
|
+
marginLeft: 4,
|
|
76
|
+
fontSize: 20,
|
|
77
|
+
fontWeight: 'bold',
|
|
78
|
+
color: '#f6e573',
|
|
79
|
+
// backgroundColor:'#fff',
|
|
80
|
+
// alignSelf:'center'
|
|
81
|
+
},
|
|
82
|
+
won: { borderColor: '#0ff35e' },
|
|
83
|
+
pointCover: {
|
|
84
|
+
display: 'flex',
|
|
85
|
+
flexDirection: 'row',
|
|
86
|
+
// borderWidth: 3,
|
|
87
|
+
// borderRadius: 8,
|
|
88
|
+
// borderColor: '#0ff35e',
|
|
89
|
+
// paddingHorizontal: 3,
|
|
90
|
+
// paddingVertical: 10,
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
// width: '50%',
|
|
93
|
+
alignSelf: 'center',
|
|
94
|
+
// justifyContent:'center'
|
|
95
|
+
}
|
|
96
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// components/GameScreen.tsx
|
|
2
|
+
import React, {useState} from 'react';
|
|
3
|
+
import {Alert, FlatList, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
|
|
4
|
+
import EmojiTracker from './EmojiTracker';
|
|
5
|
+
import Tile from './Tile';
|
|
6
|
+
import {createBoard, TileData} from '../../utils/shuffle';
|
|
7
|
+
|
|
8
|
+
export default function GameScreen({navigation}: any) {
|
|
9
|
+
|
|
10
|
+
const [tiles, setTiles] = useState<TileData[]>(createBoard());
|
|
11
|
+
const [reviewsLeft, setReviewsLeft] = useState(5);
|
|
12
|
+
|
|
13
|
+
const [counts, setCounts] = useState<{ [key: string]: number }>({
|
|
14
|
+
'😀': 0, '🔥': 0, '⭐': 0
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Tracker max slots always 3
|
|
18
|
+
const [maxCounts, setMaxCounts] = useState<{ [key: string]: number }>({
|
|
19
|
+
'😀': 3, '🔥': 3, '⭐': 3
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Function to restart game
|
|
23
|
+
const restartGame = () => {
|
|
24
|
+
setTiles(createBoard());
|
|
25
|
+
setReviewsLeft(6);
|
|
26
|
+
setCounts({'😀': 0, '🔥': 0, '⭐': 0});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const openTile = (index: number) => {
|
|
30
|
+
if (reviewsLeft === 0) {
|
|
31
|
+
Alert.alert('Reviews', 'No reviews left!');
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const newTiles = [...tiles];
|
|
36
|
+
if (newTiles[index].opened) return;
|
|
37
|
+
|
|
38
|
+
newTiles[index].opened = true;
|
|
39
|
+
setTiles(newTiles);
|
|
40
|
+
|
|
41
|
+
const emoji = newTiles[index].type;
|
|
42
|
+
|
|
43
|
+
setCounts(prev => {
|
|
44
|
+
const newCount = prev[emoji] + 1;
|
|
45
|
+
|
|
46
|
+
// Trigger alert when any emoji reaches 3 occurrences
|
|
47
|
+
if (newCount === 3) {
|
|
48
|
+
Alert.alert('Match!', `You opened 3 ${emoji} tiles!`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
...prev,
|
|
53
|
+
[emoji]: newCount
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
setReviewsLeft(prev => prev - 1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
|
|
63
|
+
<View style={{marginTop: 50, paddingVertical: 10, paddingHorizontal: 20, alignSelf: 'center'}}>
|
|
64
|
+
<EmojiTracker counts={counts} maxCounts={maxCounts} emojiValues={{'😀': 25000, '🔥': 1500, '⭐': 1000}}/>
|
|
65
|
+
</View>
|
|
66
|
+
|
|
67
|
+
<View style={styles.container}>
|
|
68
|
+
|
|
69
|
+
<Text style={{
|
|
70
|
+
color: '#0ff35e',
|
|
71
|
+
paddingHorizontal: 40,
|
|
72
|
+
paddingVertical: 16,
|
|
73
|
+
fontWeight: '600',
|
|
74
|
+
fontSize: 13
|
|
75
|
+
}}>
|
|
76
|
+
Enjoy the Challenge!{'\n'}
|
|
77
|
+
Test your memory, match the emojis, and watch your points climb with each successful match!
|
|
78
|
+
</Text>
|
|
79
|
+
|
|
80
|
+
<Text style={styles.text}>Reviews Left: {reviewsLeft}</Text>
|
|
81
|
+
|
|
82
|
+
<FlatList
|
|
83
|
+
scrollEnabled={false}
|
|
84
|
+
data={tiles}
|
|
85
|
+
numColumns={4}
|
|
86
|
+
keyExtractor={(item) => item.id.toString()}
|
|
87
|
+
renderItem={({item, index}) => {
|
|
88
|
+
return (
|
|
89
|
+
<Tile tile={item} disabled={reviewsLeft === 0} onPress={() => openTile(index)}/>
|
|
90
|
+
)
|
|
91
|
+
}}
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<View
|
|
95
|
+
style={{flexDirection: 'row', marginBottom: 50}}>
|
|
96
|
+
<TouchableOpacity style={[styles.restartBtn, {marginEnd: 30}]} onPress={restartGame}>
|
|
97
|
+
<Text style={styles.btnText}>Restart</Text>
|
|
98
|
+
</TouchableOpacity>
|
|
99
|
+
|
|
100
|
+
<TouchableOpacity style={styles.backBtn} onPress={() => navigation.replace('GameSelector')}>
|
|
101
|
+
<Text style={styles.btnText}>Back</Text>
|
|
102
|
+
</TouchableOpacity>
|
|
103
|
+
</View>
|
|
104
|
+
|
|
105
|
+
</View>
|
|
106
|
+
</>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const styles = StyleSheet.create({
|
|
111
|
+
container: {
|
|
112
|
+
flex: 1,
|
|
113
|
+
// paddingTop: 0,
|
|
114
|
+
alignItems: 'center',
|
|
115
|
+
backgroundColor: '#222'
|
|
116
|
+
},
|
|
117
|
+
text: {fontSize: 18, marginVertical: 10, color: '#fff'},
|
|
118
|
+
restartBtn: {
|
|
119
|
+
// marginTop: 20,
|
|
120
|
+
paddingHorizontal: 30,
|
|
121
|
+
paddingVertical: 12,
|
|
122
|
+
backgroundColor: 'gold',
|
|
123
|
+
borderRadius: 10
|
|
124
|
+
},
|
|
125
|
+
backBtn: {
|
|
126
|
+
// position:"absolute",
|
|
127
|
+
// top:40,
|
|
128
|
+
// left:20,
|
|
129
|
+
paddingHorizontal: 20,
|
|
130
|
+
paddingVertical: 10,
|
|
131
|
+
backgroundColor: '#888',
|
|
132
|
+
borderRadius: 8
|
|
133
|
+
},
|
|
134
|
+
btnText: {fontSize: 16, fontWeight: 'bold'}
|
|
135
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// components/Tile.tsx
|
|
2
|
+
import React, {useRef} from 'react';
|
|
3
|
+
import {Alert, Animated, StyleSheet, Text, TouchableOpacity} from 'react-native';
|
|
4
|
+
import {TileData} from '../../utils/shuffle';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
tile: TileData,
|
|
8
|
+
onPress: () => void,
|
|
9
|
+
disabled?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function Tile({tile, onPress, disabled}: Props) {
|
|
13
|
+
|
|
14
|
+
const rotate = useRef(new Animated.Value(0)).current;
|
|
15
|
+
|
|
16
|
+
const flip = () => {
|
|
17
|
+
// If tile is disabled, show alert instead of opening
|
|
18
|
+
if (disabled) {
|
|
19
|
+
Alert.alert('Notice', 'You cannot open this tile right now!');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Already opened tile
|
|
24
|
+
if (tile.opened) return;
|
|
25
|
+
|
|
26
|
+
// Start flip animation
|
|
27
|
+
Animated.timing(rotate, {
|
|
28
|
+
toValue: 1,
|
|
29
|
+
duration: 400,
|
|
30
|
+
useNativeDriver: true
|
|
31
|
+
}).start();
|
|
32
|
+
|
|
33
|
+
onPress();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const rotateY = rotate.interpolate({
|
|
37
|
+
inputRange: [0, 1],
|
|
38
|
+
outputRange: ['0deg', '180deg']
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<TouchableOpacity activeOpacity={0.8} onPress={flip}>
|
|
43
|
+
<Animated.View style={[styles.tile, {transform: [{rotateY}]}]}>
|
|
44
|
+
<Text style={styles.emoji}>{tile.opened ? tile.type : 'e'}</Text>
|
|
45
|
+
</Animated.View>
|
|
46
|
+
</TouchableOpacity>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const styles = StyleSheet.create({
|
|
51
|
+
tile: {
|
|
52
|
+
width: 70, height: 70,
|
|
53
|
+
backgroundColor: '#444',
|
|
54
|
+
margin: 2,
|
|
55
|
+
justifyContent: 'center',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
borderRadius: 10
|
|
58
|
+
},
|
|
59
|
+
emoji: {fontSize: 30}
|
|
60
|
+
});
|