UNPKG

react-native-games

Version:

Free games for your react native projects.

1 lines 7.94 kB
"use strict";import{Animated}from 'react-native';import{GAME_2048_SETTINGS,GAME_2048_GESTURES,GAME_CONFIG}from "./Game2048Constants.js";export class Game2048Service{getDifficultySettings(difficulty){return GAME_2048_SETTINGS.DIFFICULTY_SETTINGS[difficulty];}calculateMergeScore(tileValue,difficulty){const multiplier = GAME_2048_SETTINGS.SCORE_MULTIPLIER[difficulty];return tileValue * multiplier;}formatTime(seconds){const minutes = Math.floor(seconds / 60);const remainingSeconds = seconds % 60;return `${minutes.toString().padStart(2,'0')}:${remainingSeconds.toString().padStart(2,'0')}`;}detectSwipeDirection(startX,startY,endX,endY,velocity){const deltaX = endX - startX;const deltaY = endY - startY;const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);if(distance < GAME_2048_GESTURES.MIN_SWIPE_DISTANCE){return null;}if(velocity){const velocityMagnitude = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y);if(velocityMagnitude < GAME_2048_GESTURES.MIN_VELOCITY){return null;}}const absDeltaX = Math.abs(deltaX);const absDeltaY = Math.abs(deltaY);if(absDeltaX > absDeltaY){return deltaX > 0 ? 'right':'left';}else{return deltaY > 0 ? 'down':'up';}}calculateTilePosition(row,col,gridSize,containerSize){const tileSize = GAME_2048_SETTINGS.TILE_SIZE;const margin = GAME_2048_SETTINGS.TILE_MARGIN;const totalGridSize = tileSize * gridSize + margin *(gridSize + 1);const startX =(containerSize - totalGridSize)/ 2;const startY =(containerSize - totalGridSize)/ 2;const x = startX + margin + col *(tileSize + margin);const y = startY + margin + row *(tileSize + margin);return{x,y};}generateHapticFeedback(type){const patterns ={move:'impactLight',merge:'impactMedium',win:'notificationSuccess',gameOver:'notificationError'};return patterns[type];}generateSoundEffect(type){const sounds ={move:'tile_move.mp3',merge:'tile_merge.mp3',win:'game_win.mp3',gameOver:'game_over.mp3',newTile:'new_tile.mp3'};return sounds[type];}animateTileMovement(fromPosition,toPosition,duration = GAME_2048_SETTINGS.ANIMATION_DURATION){return{from:fromPosition,to:toPosition,duration,easing:'easeOutCubic'};}animateTileMerge(position,duration = GAME_2048_SETTINGS.MERGE_ANIMATION_DURATION){return{position,duration,scaleFrom:1,scaleTo:1.1,scaleBack:1,easing:'easeInOutCubic'};}animateNewTileSpawn(position,duration = GAME_2048_SETTINGS.SPAWN_ANIMATION_DURATION){return{position,duration,scaleFrom:0,scaleTo:1,easing:'easeOutBack'};}isValidPosition(row,col,gridSize){return row >= 0 && row < gridSize && col >= 0 && col < gridSize;}getAdjacentPositions(row,col,gridSize){const directions = [{row:-1,col:0,direction:'up'},{row:1,col:0,direction:'down'},{row:0,col:-1,direction:'left'},{row:0,col:1,direction:'right'}];return directions.map(dir =>({row:row + dir.row,col:col + dir.col,direction:dir.direction})).filter(pos => this.isValidPosition(pos.row,pos.col,gridSize));}calculateGameStats(score,moves,timeElapsed){const averageScorePerMove = moves > 0 ? Math.round(score / moves):0;const scorePerSecond = timeElapsed > 0 ? Math.round(score / timeElapsed):0;return{averageScorePerMove,scorePerSecond,efficiency:moves > 0 ? Math.round(score / moves * 100)/ 100:0};}async saveGameState(gameState){try{JSON.stringify(gameState);return true;}catch(error){console.error('Failed to save game state:',error);return false;}}async loadGameState(){try{return null;}catch(error){console.error('Failed to load game state:',error);return null;}}cleanup(){}createGrid(){return Array(GAME_CONFIG.GRID_SIZE).fill(null).map(()=> Array(GAME_CONFIG.GRID_SIZE).fill(null));}addRandomTile(grid,tileId){const emptyCells = [];for(let row = 0;row < GAME_CONFIG.GRID_SIZE;row++){for(let col = 0;col < GAME_CONFIG.GRID_SIZE;col++){const gridRow = grid[row];if(gridRow && !gridRow[col]){emptyCells.push({row,col});}}}if(emptyCells.length === 0)return null;const randomCell = emptyCells[Math.floor(Math.random()* emptyCells.length)];if(!randomCell)return null;const newTile ={id:tileId,value:Math.random()< GAME_CONFIG.NEW_TILE_PROBABILITY_4 ? 4:2,row:randomCell.row,col:randomCell.col,animatedValue:new Animated.Value(0),scaleValue:new Animated.Value(0)};const targetRow = grid[randomCell.row];if(targetRow){targetRow[randomCell.col] = newTile;}return newTile;}moveTiles(grid,direction){let moved = false;let score = 0;const isHorizontal = direction === 'left' || direction === 'right';const isReverse = direction === 'right' || direction === 'down';const gridSize = GAME_CONFIG.GRID_SIZE;const newGrid = this.createGrid();for(let i = 0;i < gridSize;i++){const tiles = [];for(let j = 0;j < gridSize;j++){const index = isReverse ? gridSize - 1 - j:j;const row = isHorizontal ? grid[i]:grid[index];const tile = row ? isHorizontal ? row[index]:row[i]:null;if(tile)tiles.push(tile);}const merged = [];let j = 0;while(j < tiles.length){const currentTile = tiles[j];const nextTile = tiles[j + 1];if(currentTile && nextTile && j < tiles.length - 1 && currentTile.value === nextTile.value){const mergedTile ={...currentTile,value:currentTile.value * 2,scaleValue:currentTile.scaleValue || new Animated.Value(1)};merged.push(mergedTile);score += mergedTile.value;j += 2;}else{const tile = tiles[j];merged.push(tile || null);j++;}}while(merged.length < gridSize){merged.push(null);}for(let j = 0;j < gridSize;j++){const tile = merged[j];const index = isReverse ? gridSize - 1 - j:j;const newRow = isHorizontal ? i:index;const newCol = isHorizontal ? index:i;const originalRow = isHorizontal ? grid[i]:grid[index];const originalTile = originalRow ? isHorizontal ? originalRow[index]:originalRow[i]:null;if(tile !== originalTile || tile &&(tile.row !== newRow || tile.col !== newCol)){moved = true;}if(tile){const updatedTile ={...tile,row:newRow,col:newCol};const targetRow = newGrid[newRow];if(targetRow){targetRow[newCol] = updatedTile;}}else{const targetRow = newGrid[newRow];if(targetRow){targetRow[newCol] = null;}}}}for(let row = 0;row < gridSize;row++){for(let col = 0;col < gridSize;col++){const sourceRow = newGrid[row];const targetRow = grid[row];if(sourceRow && targetRow){targetRow[col] = sourceRow[col] || null;}}}return{moved,score};}checkGameOver(grid){const gridSize = GAME_CONFIG.GRID_SIZE;for(let row = 0;row < gridSize;row++){for(let col = 0;col < gridSize;col++){const currentRow = grid[row];if(!currentRow)continue;const tile = currentRow[col];if(!tile)return false;if(col < gridSize - 1){const rightTile = currentRow[col + 1];if(rightTile && rightTile.value === tile.value)return false;}if(row < gridSize - 1){const nextRow = grid[row + 1];const downTile = nextRow ? nextRow[col]:null;if(downTile && downTile.value === tile.value)return false;}}}return true;}hasWon(grid,targetValue){for(let row = 0;row < GAME_CONFIG.GRID_SIZE;row++){const currentRow = grid[row];if(!currentRow)continue;for(let col = 0;col < GAME_CONFIG.GRID_SIZE;col++){const tile = currentRow[col];if(tile && tile.value >= targetValue)return true;}}return false;}getTileBackgroundColor(value){const colors ={2:'#eee4da',4:'#ede0c8',8:'#f2b179',16:'#f59563',32:'#f67c5f',64:'#f65e3b',128:'#edcf72',256:'#edcc61',512:'#edc850',1024:'#edc53f',2048:'#edc22e',4096:'#ff6b6b',8192:'#ee5a52'};if(value > 8192)return '#ff4757';return colors[value] || '#3c3a32';}getTileTextColor(value){return value <= 4 ? '#776e65':'#f9f6f2';}getTileTextSize(value){if(value < 100)return 28;if(value < 1000)return 24;if(value < 10000)return 20;return 16;}getTileAnimationDelay(row,col,direction){const baseDelay = 50;switch(direction){case 'up':return row * baseDelay;case 'down':return(3 - row)* baseDelay;case 'left':return col * baseDelay;case 'right':return(3 - col)* baseDelay;default:return 0;}}interpolate(from,to,progress){return from +(to - from)* progress;}easeOutCubic(t){return 1 - Math.pow(1 - t,3);}easeInOutCubic(t){return t < 0.5 ? 4 * t * t * t:1 - Math.pow(-2 * t + 2,3)/ 2;}easeOutBack(t){const c1 = 1.70158;const c3 = c1 + 1;return 1 + c3 * Math.pow(t - 1,3)+ c1 * Math.pow(t - 1,2);}}