UNPKG

advanced-games-library

Version:

Advanced Gaming Library for React Native - Four Complete Games with iOS Compatibility Fixes

478 lines (426 loc) 12.7 kB
/** * SimplePuzzleGameComponent - JavaScript Fallback Version * A React Native component for the sliding puzzle game * * @version 1.0.0 * @author Games Studio */ import React from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Alert, SafeAreaView, StatusBar, Dimensions, } from 'react-native'; const { width: screenWidth } = Dimensions.get('window'); // Fallback SimplePuzzleGameComponent const SimplePuzzleGameComponent = ({ gridSize = 3, difficulty = 'easy', onGameComplete, onGameStart, onMove, showMenu = true, autoStart = false, title = '🧩 Puzzle Game', subtitle = 'Welcome to the exciting puzzle game!', showStats = true, enableHints = true, enableReset = true, theme = { primaryColor: '#3498db', secondaryColor: '#2ecc71', backgroundColor: '#f8f9fa', textColor: '#2c3e50' } }) => { const [currentScreen, setCurrentScreen] = React.useState(showMenu ? 'menu' : 'game'); const [gameState, setGameState] = React.useState({ tiles: [], moves: 0, time: 0, score: 0, isComplete: false, startTime: null }); const [isLoading, setIsLoading] = React.useState(false); // Helper functions const formatTime = (seconds) => { const mins = Math.floor(seconds / 60); const secs = seconds % 60; return `${mins}:${secs.toString().padStart(2, '0')}`; }; const formatScore = (score) => { return score.toLocaleString(); }; const createInitialTiles = (size) => { const tiles = []; const totalTiles = size * size; for (let i = 0; i < totalTiles - 1; i++) { tiles.push({ id: `tile-${i}`, value: i + 1, position: { row: Math.floor(i / size), col: i % size }, correctPosition: { row: Math.floor(i / size), col: i % size }, isEmpty: false }); } // Add empty tile tiles.push({ id: 'empty', value: '', position: { row: size - 1, col: size - 1 }, correctPosition: { row: size - 1, col: size - 1 }, isEmpty: true }); return tiles; }; const shuffleTiles = (tiles) => { const shuffled = [...tiles]; const emptyTile = shuffled.find(tile => tile.isEmpty); let moves = 100; while (moves > 0) { const neighbors = getNeighbors(emptyTile.position, gridSize); const randomNeighbor = neighbors[Math.floor(Math.random() * neighbors.length)]; swapTiles(shuffled, emptyTile.position, randomNeighbor); moves--; } return shuffled; }; const getNeighbors = (position, size) => { const neighbors = []; const { row, col } = position; if (row > 0) neighbors.push({ row: row - 1, col }); if (row < size - 1) neighbors.push({ row: row + 1, col }); if (col > 0) neighbors.push({ row, col: col - 1 }); if (col < size - 1) neighbors.push({ row, col: col + 1 }); return neighbors; }; const swapTiles = (tiles, pos1, pos2) => { const tile1 = tiles.find(t => t.position.row === pos1.row && t.position.col === pos1.col); const tile2 = tiles.find(t => t.position.row === pos2.row && t.position.col === pos2.col); if (tile1 && tile2) { const tempPos = { ...tile1.position }; tile1.position = { ...tile2.position }; tile2.position = tempPos; } }; const startNewGame = (size = gridSize) => { setIsLoading(true); setTimeout(() => { const tiles = createInitialTiles(size); const shuffledTiles = shuffleTiles(tiles); setGameState({ tiles: shuffledTiles, moves: 0, time: 0, score: 0, isComplete: false, startTime: Date.now() }); setCurrentScreen('game'); setIsLoading(false); onGameStart?.(); }, 500); }; const moveTile = (position) => { if (gameState.isComplete) return false; const emptyTile = gameState.tiles.find(tile => tile.isEmpty); const neighbors = getNeighbors(emptyTile.position, gridSize); const canMove = neighbors.some(n => n.row === position.row && n.col === position.col); if (canMove) { const newTiles = [...gameState.tiles]; swapTiles(newTiles, emptyTile.position, position); const newMoves = gameState.moves + 1; const newScore = Math.max(0, 1000 - newMoves * 10); const newGameState = { ...gameState, tiles: newTiles, moves: newMoves, score: newScore, time: Date.now() - gameState.startTime }; setGameState(newGameState); onMove?.({ position, moves: newMoves }); if (isPuzzleSolved(newTiles)) { const finalState = { ...newGameState, isComplete: true }; setGameState(finalState); onGameComplete?.(finalState); } return true; } return false; }; const isPuzzleSolved = (tiles) => { return tiles.every(tile => tile.position.row === tile.correctPosition.row && tile.position.col === tile.correctPosition.col ); }; const resetGame = () => { startNewGame(gridSize); }; const renderTile = (tile, index) => { if (tile.isEmpty) { return ( <View key={tile.id} style={[ styles.tile, styles.emptyTile, { width: (screenWidth - 80) / gridSize, height: (screenWidth - 80) / gridSize, } ]} /> ); } return ( <TouchableOpacity key={tile.id} style={[ styles.tile, { width: (screenWidth - 80) / gridSize, height: (screenWidth - 80) / gridSize, backgroundColor: theme.primaryColor, } ]} onPress={() => moveTile(tile.position)} activeOpacity={0.7} > <Text style={[styles.tileText, { color: 'white' }]}> {tile.value} </Text> </TouchableOpacity> ); }; const renderPuzzleBoard = () => { const boardSize = gridSize; const rows = []; for (let row = 0; row < boardSize; row++) { const rowTiles = []; for (let col = 0; col < boardSize; col++) { const tile = gameState.tiles.find(t => t.position.row === row && t.position.col === col ); if (tile) { rowTiles.push(renderTile(tile, row * boardSize + col)); } } rows.push( <View key={row} style={styles.row}> {rowTiles} </View> ); } return <View style={styles.board}>{rows}</View>; }; const renderMenuScreen = () => ( <SafeAreaView style={[styles.container, { backgroundColor: theme.backgroundColor }]}> <StatusBar barStyle="dark-content" backgroundColor={theme.backgroundColor} /> <View style={styles.menuContent}> <Text style={[styles.title, { color: theme.textColor }]}>{title}</Text> <Text style={[styles.subtitle, { color: theme.textColor }]}>{subtitle}</Text> <View style={styles.menuButtons}> <TouchableOpacity style={[styles.menuButton, { backgroundColor: theme.primaryColor }]} onPress={() => startNewGame(3)} > <Text style={styles.menuButtonText}>3x3 Grid</Text> </TouchableOpacity> <TouchableOpacity style={[styles.menuButton, { backgroundColor: theme.primaryColor }]} onPress={() => startNewGame(4)} > <Text style={styles.menuButtonText}>4x4 Grid</Text> </TouchableOpacity> <TouchableOpacity style={[styles.menuButton, { backgroundColor: theme.primaryColor }]} onPress={() => startNewGame(5)} > <Text style={styles.menuButtonText}>5x5 Grid</Text> </TouchableOpacity> </View> </View> </SafeAreaView> ); const renderGameScreen = () => ( <SafeAreaView style={[styles.container, { backgroundColor: theme.backgroundColor }]}> <StatusBar barStyle="dark-content" backgroundColor={theme.backgroundColor} /> <View style={styles.gameHeader}> <Text style={[styles.gameTitle, { color: theme.textColor }]}>Puzzle Game</Text> {showStats && ( <View style={styles.stats}> <Text style={[styles.statText, { color: theme.textColor }]}> Moves: {gameState.moves} </Text> <Text style={[styles.statText, { color: theme.textColor }]}> Time: {formatTime(Math.floor(gameState.time / 1000))} </Text> <Text style={[styles.statText, { color: theme.textColor }]}> Score: {formatScore(gameState.score)} </Text> </View> )} </View> <View style={styles.gameContent}> {renderPuzzleBoard()} </View> <View style={styles.gameControls}> {enableReset && ( <TouchableOpacity style={[styles.controlButton, { backgroundColor: theme.secondaryColor }]} onPress={resetGame} > <Text style={styles.controlButtonText}>Reset</Text> </TouchableOpacity> )} {showMenu && ( <TouchableOpacity style={[styles.controlButton, { backgroundColor: theme.primaryColor }]} onPress={() => setCurrentScreen('menu')} > <Text style={styles.controlButtonText}>Menu</Text> </TouchableOpacity> )} </View> </SafeAreaView> ); if (isLoading) { return ( <SafeAreaView style={[styles.container, { backgroundColor: theme.backgroundColor }]}> <View style={styles.loadingContainer}> <Text style={[styles.loadingText, { color: theme.textColor }]}>Loading...</Text> </View> </SafeAreaView> ); } return currentScreen === 'menu' ? renderMenuScreen() : renderGameScreen(); }; const styles = StyleSheet.create({ container: { flex: 1, }, menuContent: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, title: { fontSize: 32, fontWeight: 'bold', marginBottom: 10, textAlign: 'center', }, subtitle: { fontSize: 16, textAlign: 'center', marginBottom: 40, }, menuButtons: { width: '100%', maxWidth: 300, }, menuButton: { padding: 15, borderRadius: 10, marginBottom: 15, alignItems: 'center', }, menuButtonText: { color: 'white', fontSize: 18, fontWeight: 'bold', }, gameHeader: { padding: 20, alignItems: 'center', }, gameTitle: { fontSize: 24, fontWeight: 'bold', marginBottom: 10, }, stats: { flexDirection: 'row', justifyContent: 'space-around', width: '100%', }, statText: { fontSize: 14, fontWeight: 'bold', }, gameContent: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, board: { borderWidth: 2, borderColor: '#ddd', borderRadius: 10, padding: 10, backgroundColor: 'white', }, row: { flexDirection: 'row', }, tile: { justifyContent: 'center', alignItems: 'center', margin: 2, borderRadius: 8, elevation: 3, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, }, emptyTile: { backgroundColor: 'transparent', elevation: 0, shadowOpacity: 0, }, tileText: { fontSize: 18, fontWeight: 'bold', }, gameControls: { flexDirection: 'row', justifyContent: 'space-around', padding: 20, }, controlButton: { padding: 15, borderRadius: 10, minWidth: 100, alignItems: 'center', }, controlButtonText: { color: 'white', fontSize: 16, fontWeight: 'bold', }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, loadingText: { fontSize: 18, fontWeight: 'bold', }, }); export { SimplePuzzleGameComponent }; export default SimplePuzzleGameComponent;