advanced-games-library
Version:
Advanced Gaming Library for React Native - Four Complete Games with iOS Compatibility Fixes
634 lines (548 loc) • 17.9 kB
text/typescript
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { GameManager } from '../services/GameManager';
import { GameResult, PlayerData, GameLibraryError } from '../core/types';
// AudioService was deleted, removing import
/**
* Hook for managing games library with initialization and game launching
*/
export const useGamesLibrary = () => {
const [isInitialized, setIsInitialized] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [availableGames, setAvailableGames] = useState<any[]>([]);
const gameManager = GameManager.getInstance();
// Initialize library
const initialize = useCallback(async (config: any) => {
setIsLoading(true);
setError(null);
try {
await gameManager.initialize(config);
const games = gameManager.getAvailableGames();
setAvailableGames(games);
setIsInitialized(true);
} catch (err) {
const errorMessage = err instanceof GameLibraryError ? err.message : 'Failed to initialize library';
setError(errorMessage);
throw err;
} finally {
setIsLoading(false);
}
}, []);
// Launch game
const launchGame = useCallback(async (gameId: string, config?: any) => {
setIsLoading(true);
setError(null);
try {
const game = await gameManager.launchGame(gameId, config);
return game;
} catch (err) {
const errorMessage = err instanceof GameLibraryError ? err.message : 'Failed to launch game';
setError(errorMessage);
throw err;
} finally {
setIsLoading(false);
}
}, []);
return {
// State
isInitialized,
isLoading,
error,
availableGames,
// Methods
initialize,
launchGame,
// Utils
clearError: () => setError(null),
};
};
/**
* Hook for managing game history and statistics
*/
export const useGameHistory = () => {
const [gameHistory, setGameHistory] = useState<GameResult[]>([]);
const [isLoading, setIsLoading] = useState(false);
const gameManager = GameManager.getInstance();
// Load game history
const loadGameHistory = useCallback(async (playerId?: string) => {
setIsLoading(true);
try {
const history = await gameManager.getGameHistory(playerId);
setGameHistory(history);
} catch (err) {
console.warn('Failed to load game history:', err);
} finally {
setIsLoading(false);
}
}, []);
// Calculate improvement trend
const calculateImprovement = useCallback((results: GameResult[]) => {
if (results.length < 2) return 0;
const recent = results.slice(-3);
const earlier = results.slice(0, 3);
if (earlier.length === 0) return 0;
const recentAvg = recent.reduce((sum, r) => sum + r.score, 0) / recent.length;
const earlierAvg = earlier.reduce((sum, r) => sum + r.score, 0) / earlier.length;
return Math.round(((recentAvg - earlierAvg) / earlierAvg) * 100);
}, []);
// Get statistics for a specific game
const getGameSpecificStats = useCallback((gameId: string) => {
const gameResults = gameHistory.filter(result => result.gameId === gameId);
if (gameResults.length === 0) {
return null;
}
const totalPlays = gameResults.length;
const completedGames = gameResults.filter(r => r.completed);
const bestScore = Math.max(...gameResults.map(r => r.score));
const averageScore = gameResults.reduce((sum, r) => sum + r.score, 0) / totalPlays;
const completionRate = (completedGames.length / totalPlays) * 100;
const averageTime = gameResults.reduce((sum, r) => sum + r.timeSpent, 0) / totalPlays;
return {
gameId,
totalPlays,
bestScore,
averageScore: Math.round(averageScore),
completionRate: Math.round(completionRate),
averageTime: Math.round(averageTime),
lastPlayed: gameResults[gameResults.length - 1]?.timestamp || null,
improvement: calculateImprovement(gameResults)
};
}, [gameHistory, calculateImprovement]);
// Calculate general statistics
const stats = React.useMemo(() => {
const totalPlays = gameHistory.length;
const completedGames = gameHistory.filter(r => r.completed);
const bestScore = gameHistory.length > 0 ? Math.max(...gameHistory.map(r => r.score)) : 0;
const averageScore = totalPlays > 0 ? gameHistory.reduce((sum, r) => sum + r.score, 0) / totalPlays : 0;
const completionRate = totalPlays > 0 ? (completedGames.length / totalPlays) * 100 : 0;
const averageTime = totalPlays > 0 ? gameHistory.reduce((sum, r) => sum + r.timeSpent, 0) / totalPlays : 0;
return {
totalPlays,
bestScore,
averageScore: Math.round(averageScore),
completionRate: Math.round(completionRate),
averageTime: Math.round(averageTime),
lastPlayed: gameHistory[gameHistory.length - 1]?.timestamp || null,
improvement: calculateImprovement(gameHistory)
};
}, [gameHistory, calculateImprovement]);
// Load history on mount
useEffect(() => {
loadGameHistory();
}, [loadGameHistory]);
return {
// State
gameHistory,
stats,
isLoading,
// Methods
loadGameHistory,
getGameSpecificStats,
};
};
/**
* Hook for managing player data
*/
export const usePlayer = () => {
const [player, setPlayerState] = useState<PlayerData | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const gameManager = GameManager.getInstance();
// Load player data
const loadPlayer = useCallback(() => {
try {
const playerData = gameManager.getPlayer();
setPlayerState(playerData);
} catch (err) {
setError('Failed to load player data');
}
}, []);
// Update player data
const updatePlayer = useCallback(async (playerData: PlayerData) => {
setIsLoading(true);
setError(null);
try {
gameManager.setPlayer(playerData);
setPlayerState(playerData);
} catch (err) {
const errorMessage = err instanceof GameLibraryError ? err.message : 'Failed to update player data';
setError(errorMessage);
throw err;
} finally {
setIsLoading(false);
}
}, []);
// Get player statistics
const getPlayerStats = useCallback(() => {
if (!player) return null;
return {
totalGames: player.totalGamesPlayed,
achievements: player.achievements.length,
memberSince: player.createdAt,
lastActive: player.lastActive
};
}, [player]);
// Load player on mount
useEffect(() => {
loadPlayer();
}, [loadPlayer]);
return {
// State
player,
isLoading,
error,
// Methods
updatePlayer,
loadPlayer,
getPlayerStats,
// Utils
clearError: () => setError(null),
};
};
/**
* Hook for managing game timer
*/
export const useGameTimer = (initialTime: number, onTimeUp?: () => void) => {
const [timeLeft, setTimeLeft] = useState(initialTime);
const [isRunning, setIsRunning] = useState(false);
const [isPaused, setIsPaused] = useState(false);
const intervalRef = useRef<NodeJS.Timeout>();
// Start timer
const start = useCallback(() => {
setIsRunning(true);
setIsPaused(false);
}, []);
// Pause timer
const pause = useCallback(() => {
setIsRunning(false);
setIsPaused(true);
}, []);
// Resume timer
const resume = useCallback(() => {
setIsRunning(true);
setIsPaused(false);
}, []);
// Reset timer
const reset = useCallback((newTime?: number) => {
setTimeLeft(newTime || initialTime);
setIsRunning(false);
setIsPaused(false);
}, [initialTime]);
// Stop timer
const stop = useCallback(() => {
setIsRunning(false);
setIsPaused(false);
setTimeLeft(0);
}, []);
// Timer logic
useEffect(() => {
if (isRunning && timeLeft > 0) {
intervalRef.current = setInterval(() => {
setTimeLeft(prev => {
const newTime = prev - 1;
if (newTime <= 0) {
setIsRunning(false);
onTimeUp?.();
return 0;
}
return newTime;
});
}, 1000);
} else {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
}
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [isRunning, timeLeft, onTimeUp]);
// Format time for display
const formatTime = useCallback((seconds: number) => {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}, []);
return {
// State
timeLeft,
isRunning,
isPaused,
formattedTime: formatTime(timeLeft),
// Methods
start,
pause,
resume,
reset,
stop,
formatTime,
};
};
/**
* Hook for managing sound effects
*/
export const useGameSounds = () => {
const [isMuted, setIsMuted] = useState(false);
const [volume, setVolume] = useState(1.0);
// AudioService was deleted, using placeholder
const audioService = null;
// Initialize audio service
useEffect(() => {
// AudioService was deleted, skipping initialization
}, []);
// Update audio config when settings change
useEffect(() => {
// AudioService was deleted, skipping config update
}, [isMuted, volume]);
// Play sound effect
const playSound = useCallback(async (soundType: 'success' | 'failure' | 'click' | 'countdown' | 'background' | 'notification' | 'achievement' | 'move' | 'card_flip' | 'match_found' | 'wrong_answer' | 'correct_answer' | 'level_complete') => {
if (isMuted) return;
// AudioService was deleted, skipping sound playback
console.log(`Would play sound: ${soundType}`);
}, [isMuted, volume]);
// Play background music
const playBackgroundMusic = useCallback(async (audioUrl?: string) => {
if (isMuted) return;
// AudioService was deleted, skipping background music
console.log(`Would play background music: ${audioUrl}`);
}, [isMuted, volume]);
// Stop background music
const stopBackgroundMusic = useCallback(() => {
// AudioService was deleted, skipping stop
console.log('Would stop background music');
}, []);
// Stop all sounds
const stopAllSounds = useCallback(() => {
// AudioService was deleted, skipping stop
console.log('Would stop all sounds');
}, []);
// Toggle mute
const toggleMute = useCallback(() => {
setIsMuted(prev => !prev);
}, []);
// Set volume (0.0 to 1.0)
const changeVolume = useCallback((newVolume: number) => {
setVolume(Math.max(0, Math.min(1, newVolume)));
}, []);
// Preload custom sound
const preloadSound = useCallback(async (soundId: string, audioUrl: string) => {
// AudioService was deleted, skipping preload
console.log(`Would preload sound: ${soundId}`);
}, []);
// Get available sounds
const getAvailableSounds = useCallback(() => {
// AudioService was deleted, returning empty array
return [];
}, []);
return {
// State
isMuted,
volume,
isAudioSupported: false, // AudioService was deleted
// Methods
playSound,
playBackgroundMusic,
stopBackgroundMusic,
stopAllSounds,
toggleMute,
changeVolume,
preloadSound,
getAvailableSounds,
};
};
/**
* Hook for managing game performance metrics
*/
export const useGamePerformance = () => {
const [metrics, setMetrics] = useState({
fps: 60,
memoryUsage: 0,
renderTime: 0,
lastUpdate: Date.now()
});
// Update performance metrics
const updateMetrics = useCallback(() => {
// This would integrate with performance monitoring
// For now, just mock data
setMetrics({
fps: Math.floor(Math.random() * 10) + 55,
memoryUsage: Math.floor(Math.random() * 50) + 50,
renderTime: Math.floor(Math.random() * 5) + 10,
lastUpdate: Date.now()
});
}, []);
// Start performance monitoring
useEffect(() => {
const interval = setInterval(updateMetrics, 1000);
return () => clearInterval(interval);
}, [updateMetrics]);
return {
metrics,
updateMetrics,
};
};
/**
* Hook for managing game achievements
*/
export const useAchievements = () => {
const [achievements, setAchievements] = useState<any[]>([]);
const [unlockedAchievements, setUnlockedAchievements] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(false);
const gameManager = GameManager.getInstance();
// Load achievements
const loadAchievements = useCallback(async () => {
setIsLoading(true);
try {
const player = gameManager.getPlayer();
if (player) {
setUnlockedAchievements(player.achievements);
}
// In a real implementation, this would load all possible achievements
setAchievements([
{
id: 'first_game',
name: 'המשחק הראשון',
description: 'השלם את המשחק הראשון שלך',
icon: '🎮',
category: 'milestone'
},
{
id: 'speed_demon',
name: 'שד המהירות',
description: 'השלם משחק תוך פחות מ-30 שניות',
icon: '⚡',
category: 'speed'
},
{
id: 'perfectionist',
name: 'פרפקציוניסט',
description: 'השג ציון מושלם',
icon: '🏆',
category: 'performance'
}
]);
} catch (err) {
console.warn('Failed to load achievements:', err);
} finally {
setIsLoading(false);
}
}, []);
// Check for new achievements
const checkAchievements = useCallback((gameResult: GameResult) => {
const newAchievements: any[] = [];
// Check first game achievement
if (!unlockedAchievements.find(a => a.id === 'first_game')) {
newAchievements.push({
id: 'first_game',
name: 'המשחק הראשון',
description: 'השלם את המשחק הראשון שלך',
icon: '🎮',
unlockedAt: new Date()
});
}
// Check speed achievement
if (gameResult.timeSpent < 30000 && !unlockedAchievements.find(a => a.id === 'speed_demon')) {
newAchievements.push({
id: 'speed_demon',
name: 'שד המהירות',
description: 'השלם משחק תוך פחות מ-30 שניות',
icon: '⚡',
unlockedAt: new Date()
});
}
// Check perfect score achievement
if (gameResult.score === gameResult.maxScore && !unlockedAchievements.find(a => a.id === 'perfectionist')) {
newAchievements.push({
id: 'perfectionist',
name: 'פרפקציוניסט',
description: 'השג ציון מושלם',
icon: '🏆',
unlockedAt: new Date()
});
}
if (newAchievements.length > 0) {
setUnlockedAchievements(prev => [...prev, ...newAchievements]);
return newAchievements;
}
return [];
}, [unlockedAchievements]);
// Load achievements on mount
useEffect(() => {
loadAchievements();
}, [loadAchievements]);
return {
achievements,
unlockedAchievements,
isLoading,
checkAchievements,
loadAchievements,
};
};
/**
* Hook for managing game preferences and settings
*/
export const useGameSettings = () => {
const [settings, setSettings] = useState({
soundEnabled: true,
musicEnabled: true,
vibrationEnabled: true,
difficulty: 'medium' as 'easy' | 'medium' | 'hard',
language: 'he',
theme: 'light' as 'light' | 'dark',
notifications: true,
analytics: true
});
// Load settings from storage
const loadSettings = useCallback(async () => {
try {
// In a real implementation, this would load from AsyncStorage
const savedSettings = localStorage.getItem('gameSettings');
if (savedSettings) {
setSettings(JSON.parse(savedSettings));
}
} catch (err) {
console.warn('Failed to load settings:', err);
}
}, []);
// Save settings to storage
const saveSettings = useCallback(async (newSettings: Partial<typeof settings>) => {
try {
const updatedSettings = { ...settings, ...newSettings };
setSettings(updatedSettings);
localStorage.setItem('gameSettings', JSON.stringify(updatedSettings));
} catch (err) {
console.warn('Failed to save settings:', err);
}
}, [settings]);
// Update specific setting
const updateSetting = useCallback((key: keyof typeof settings, value: any) => {
saveSettings({ [key]: value });
}, [saveSettings]);
// Reset to defaults
const resetSettings = useCallback(() => {
const defaultSettings = {
soundEnabled: true,
musicEnabled: true,
vibrationEnabled: true,
difficulty: 'medium' as const,
language: 'he',
theme: 'light' as const,
notifications: true,
analytics: true
};
saveSettings(defaultSettings);
}, [saveSettings]);
// Load settings on mount
useEffect(() => {
loadSettings();
}, [loadSettings]);
return {
settings,
updateSetting,
saveSettings,
resetSettings,
loadSettings,
};
};