diff --git a/app/src/main/java/com/mintris/MainActivity.kt b/app/src/main/java/com/mintris/MainActivity.kt index 754ec2d..8b4602e 100644 --- a/app/src/main/java/com/mintris/MainActivity.kt +++ b/app/src/main/java/com/mintris/MainActivity.kt @@ -29,8 +29,6 @@ import androidx.activity.result.contract.ActivityResultContracts import android.graphics.Rect import android.util.Log import android.view.KeyEvent -import android.os.Handler -import android.os.Looper class MainActivity : AppCompatActivity() { @@ -322,7 +320,6 @@ class MainActivity : AppCompatActivity() { * Show game over screen */ private fun showGameOver(score: Int) { - Log.d("MainActivity", "Showing game over screen with score: $score") val gameTime = System.currentTimeMillis() - gameStartTime // Update session stats @@ -369,40 +366,28 @@ class MainActivity : AppCompatActivity() { // Flag to track if high score screen will be shown var showingHighScore = false - // Play game over sound and trigger animation - if (isSoundEnabled) { - gameMusic.playGameOver() - } + // Show progression screen first with XP animation + showProgressionScreen(xpGained, newRewards) - // First trigger the animation in the game view - Log.d("MainActivity", "Triggering game over animation") - gameView.startGameOverAnimation() + // Override the continue button behavior if high score needs to be shown + val originalOnContinue = progressionScreen.onContinue - // Wait a moment before showing progression screen to let animation be visible - Handler(Looper.getMainLooper()).postDelayed({ - // Show progression screen first with XP animation - showProgressionScreen(xpGained, newRewards) - - // Override the continue button behavior if high score needs to be shown - val originalOnContinue = progressionScreen.onContinue - - progressionScreen.onContinue = { - // If this is a high score, show high score entry screen - if (highScoreManager.isHighScore(score)) { - showingHighScore = true - showHighScoreEntry(score) - } else { - // Just show game over screen normally - progressionScreen.visibility = View.GONE - binding.gameOverContainer.visibility = View.VISIBLE - - // Update theme selector if new themes were unlocked - if (newRewards.any { it.contains("Theme") }) { - updateThemeSelector() - } + progressionScreen.onContinue = { + // If this is a high score, show high score entry screen + if (highScoreManager.isHighScore(score)) { + showingHighScore = true + showHighScoreEntry(score) + } else { + // Just show game over screen normally + progressionScreen.visibility = View.GONE + binding.gameOverContainer.visibility = View.VISIBLE + + // Update theme selector if new themes were unlocked + if (newRewards.any { it.contains("Theme") }) { + updateThemeSelector() } } - }, 2000) // Increased from 1000ms (1 second) to 2000ms (2 seconds) + } // Vibrate to indicate game over vibrate(VibrationEffect.EFFECT_DOUBLE_CLICK) diff --git a/app/src/main/java/com/mintris/audio/GameMusic.kt b/app/src/main/java/com/mintris/audio/GameMusic.kt index 32c2f6e..fbb8abf 100644 --- a/app/src/main/java/com/mintris/audio/GameMusic.kt +++ b/app/src/main/java/com/mintris/audio/GameMusic.kt @@ -9,14 +9,12 @@ import com.mintris.R class GameMusic(private val context: Context) { private var mediaPlayer: MediaPlayer? = null - private var gameOverPlayer: MediaPlayer? = null private var isEnabled = true private var isPrepared = false init { try { setupMediaPlayer() - setupGameOverPlayer() } catch (e: Exception) { Log.e("GameMusic", "Error initializing: ${e.message}") } @@ -48,49 +46,6 @@ class GameMusic(private val context: Context) { } } - private fun setupGameOverPlayer() { - try { - Log.d("GameMusic", "Setting up GameOver MediaPlayer") - gameOverPlayer = MediaPlayer.create(context, R.raw.game_over).apply { - setVolume(1.0f, 1.0f) // Increased from 0.7f to 1.0f for maximum volume - - // Set audio attributes for better performance - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setAudioAttributes( - AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_GAME) - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .build() - ) - } - } - Log.d("GameMusic", "GameOver MediaPlayer setup complete") - } catch (e: Exception) { - Log.e("GameMusic", "Error setting up GameOver MediaPlayer", e) - gameOverPlayer = null - } - } - - fun playGameOver() { - if (isEnabled && gameOverPlayer != null) { - try { - Log.d("GameMusic", "Playing game over sound") - // Temporarily lower background music volume - mediaPlayer?.setVolume(0.2f, 0.2f) - - // Play game over sound - gameOverPlayer?.start() - - // Restore background music volume after a delay - gameOverPlayer?.setOnCompletionListener { - mediaPlayer?.setVolume(0.5f, 0.5f) - } - } catch (e: Exception) { - Log.e("GameMusic", "Error playing game over sound: ${e.message}") - } - } - } - fun start() { if (isEnabled && mediaPlayer != null && isPrepared) { try { @@ -152,9 +107,7 @@ class GameMusic(private val context: Context) { try { Log.d("GameMusic", "Releasing MediaPlayer") mediaPlayer?.release() - gameOverPlayer?.release() mediaPlayer = null - gameOverPlayer = null isPrepared = false } catch (e: Exception) { Log.e("GameMusic", "Error releasing music: ${e.message}") diff --git a/app/src/main/java/com/mintris/game/GameHaptics.kt b/app/src/main/java/com/mintris/game/GameHaptics.kt index d6869c0..44e5011 100644 --- a/app/src/main/java/com/mintris/game/GameHaptics.kt +++ b/app/src/main/java/com/mintris/game/GameHaptics.kt @@ -91,26 +91,4 @@ class GameHaptics(private val context: Context) { vibrator.vibrate(vibrationEffect) } } - - fun vibrateForGameOver() { - Log.d(TAG, "Attempting to vibrate for game over") - - // Only proceed if the device has a vibrator and it's available - if (!vibrator.hasVibrator()) return - - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - // Create a strong, long vibration effect - val vibrationEffect = VibrationEffect.createOneShot(300L, VibrationEffect.DEFAULT_AMPLITUDE) - vibrator.vibrate(vibrationEffect) - Log.d(TAG, "Game over vibration triggered successfully") - } else { - @Suppress("DEPRECATION") - vibrator.vibrate(300L) - Log.w(TAG, "Device does not support vibration effects (Android < 8.0)") - } - } catch (e: Exception) { - Log.e(TAG, "Error triggering game over vibration", e) - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/mintris/game/GameView.kt b/app/src/main/java/com/mintris/game/GameView.kt index 24e8f0c..f1608f4 100644 --- a/app/src/main/java/com/mintris/game/GameView.kt +++ b/app/src/main/java/com/mintris/game/GameView.kt @@ -57,15 +57,6 @@ class GameView @JvmOverloads constructor( isAntiAlias = true } - private val borderGlowPaint = Paint().apply { - color = Color.WHITE - alpha = 60 - isAntiAlias = true - style = Paint.Style.STROKE - strokeWidth = 2f - maskFilter = BlurMaskFilter(8f, BlurMaskFilter.Blur.OUTER) - } - private val ghostBlockPaint = Paint().apply { color = Color.WHITE alpha = 80 // 30% opacity @@ -98,6 +89,15 @@ class GameView @JvmOverloads constructor( maskFilter = BlurMaskFilter(12f, BlurMaskFilter.Blur.OUTER) } + private val borderGlowPaint = Paint().apply { + color = Color.WHITE + alpha = 60 + isAntiAlias = true + style = Paint.Style.STROKE + strokeWidth = 2f + maskFilter = BlurMaskFilter(8f, BlurMaskFilter.Blur.OUTER) + } + // Add a new paint for the pulse effect private val pulsePaint = Paint().apply { color = Color.CYAN @@ -150,12 +150,11 @@ class GameView @JvmOverloads constructor( private var lastHoldTime = 0L // Track when the last hold occurred private val holdCooldown = 250L // Minimum time between holds private var lockedDirection: Direction? = null // Track the locked movement direction - private val minMovementThreshold = 0.3f // Reduced from 0.5f for more sensitive horizontal movement - private val directionLockThreshold = 1.0f // Reduced from 1.5f to make direction locking less aggressive + private val minMovementThreshold = 0.5f // Reduced from 0.75f for more sensitive movement + private val directionLockThreshold = 1.5f // Reduced from 2.5f to make direction locking less aggressive private val isStrictDirectionLock = true // Re-enabled strict direction locking to prevent diagonal inputs - private val minHardDropDistance = 2.5f // Increased from 1.5f to require more deliberate hard drops + private val minHardDropDistance = 1.5f // Minimum distance (in blocks) for hard drop gesture private val minHoldDistance = 2.0f // Minimum distance (in blocks) for hold gesture - private val maxSoftDropDistance = 1.5f // Maximum distance for soft drop before considering hard drop // Block skin private var currentBlockSkin: String = "block_skin_1" @@ -178,38 +177,6 @@ class GameView @JvmOverloads constructor( private var pulseAlpha = 0f private var isPulsing = false private var linesToPulse = mutableListOf() // Track which lines are being cleared - private var gameOverAnimator: ValueAnimator? = null - private var gameOverAlpha = 0f - private var isGameOverAnimating = false - // Add new game over animation properties - private var gameOverBlocksY = mutableListOf() - private var gameOverBlocksX = mutableListOf() - private var gameOverBlocksRotation = mutableListOf() - private var gameOverBlocksSpeed = mutableListOf() - private var gameOverBlocksSize = mutableListOf() - private var gameOverColorTransition = 0f - private var gameOverShakeAmount = 0f - private var gameOverFinalAlpha = 0.8f - - private val ghostPaint = Paint().apply { - style = Paint.Style.STROKE - strokeWidth = 2f - color = Color.WHITE - alpha = 180 // Increased from 100 for better visibility - } - - private val ghostBackgroundPaint = Paint().apply { - style = Paint.Style.FILL - color = Color.WHITE - alpha = 30 // Very light background for better contrast - } - - private val ghostBorderPaint = Paint().apply { - style = Paint.Style.STROKE - strokeWidth = 1f - color = Color.WHITE - alpha = 100 // Subtle border for better definition - } init { // Start with paused state @@ -330,17 +297,6 @@ class GameView @JvmOverloads constructor( * Start the game */ fun start() { - // Reset game over animation state - isGameOverAnimating = false - gameOverAlpha = 0f - gameOverBlocksY.clear() - gameOverBlocksX.clear() - gameOverBlocksRotation.clear() - gameOverBlocksSpeed.clear() - gameOverBlocksSize.clear() - gameOverColorTransition = 0f - gameOverShakeAmount = 0f - isPaused = false isRunning = true gameBoard.startGame() // Add this line to ensure a new piece is spawned @@ -363,18 +319,6 @@ class GameView @JvmOverloads constructor( fun reset() { isRunning = false isPaused = true - - // Reset game over animation state - isGameOverAnimating = false - gameOverAlpha = 0f - gameOverBlocksY.clear() - gameOverBlocksX.clear() - gameOverBlocksRotation.clear() - gameOverBlocksSpeed.clear() - gameOverBlocksSize.clear() - gameOverColorTransition = 0f - gameOverShakeAmount = 0f - gameBoard.reset() gameBoard.startGame() // Add this line to ensure a new piece is spawned handler.removeCallbacks(gameLoopRunnable) @@ -386,17 +330,9 @@ class GameView @JvmOverloads constructor( */ private fun update() { if (gameBoard.isGameOver) { - // Only trigger game over handling once when transitioning to game over state - if (isRunning) { - Log.d(TAG, "Game has ended - transitioning to game over state") - isRunning = false - isPaused = true - - // Always trigger animation for each game over - Log.d(TAG, "Triggering game over animation from update()") - startGameOverAnimation() - onGameOver?.invoke(gameBoard.score) - } + isRunning = false + isPaused = true + onGameOver?.invoke(gameBoard.score) return } @@ -450,6 +386,12 @@ class GameView @JvmOverloads constructor( } override fun onDraw(canvas: Canvas) { + // Skip drawing if paused or game over - faster return + if (isPaused || gameBoard.isGameOver) { + super.onDraw(canvas) + return + } + // Set hardware layer type during draw for better performance val wasHardwareAccelerated = isHardwareAccelerated if (!wasHardwareAccelerated) { @@ -476,132 +418,6 @@ class GameView @JvmOverloads constructor( // Draw active piece drawActivePiece(canvas) } - - // Draw game over effect if animating - if (isGameOverAnimating) { - // First layer - full screen glow - val gameOverPaint = Paint().apply { - color = Color.RED // Change to red for more striking game over indication - alpha = (230 * gameOverAlpha).toInt() // Increased opacity - isAntiAlias = true - style = Paint.Style.FILL - // Only apply blur if alpha is greater than 0 - if (gameOverAlpha > 0) { - maskFilter = BlurMaskFilter(64f * gameOverAlpha, BlurMaskFilter.Blur.OUTER) - } - } - - // Apply screen shake if active - if (gameOverShakeAmount > 0) { - canvas.save() - val shakeOffsetX = (Math.random() * 2 - 1) * gameOverShakeAmount * 20 // Doubled for more visible shake - val shakeOffsetY = (Math.random() * 2 - 1) * gameOverShakeAmount * 20 - canvas.translate(shakeOffsetX.toFloat(), shakeOffsetY.toFloat()) - } - - canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gameOverPaint) - - // Second layer - color transition effect - val gameOverPaint2 = Paint().apply { - // Transition from bright red to theme color - val transitionColor = if (gameOverColorTransition < 0.5f) { - Color.RED - } else { - val transition = (gameOverColorTransition - 0.5f) * 2f - val red = Color.red(currentThemeColor) - val green = Color.green(currentThemeColor) - val blue = Color.blue(currentThemeColor) - Color.argb( - (150 * gameOverAlpha).toInt(), // Increased opacity - (255 - (255-red) * transition).toInt(), - (green * transition).toInt(), // Transition from 0 (red) to theme green - (blue * transition).toInt() // Transition from 0 (red) to theme blue - ) - } - color = transitionColor - alpha = (150 * gameOverAlpha).toInt() // Increased opacity - isAntiAlias = true - style = Paint.Style.FILL - // Only apply blur if alpha is greater than 0 - if (gameOverAlpha > 0) { - maskFilter = BlurMaskFilter(48f * gameOverAlpha, BlurMaskFilter.Blur.OUTER) // Increased blur - } - } - canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gameOverPaint2) - - // Draw "GAME OVER" text - if (gameOverAlpha > 0.5f) { - val textPaint = Paint().apply { - color = Color.WHITE - alpha = (255 * Math.min(1f, (gameOverAlpha - 0.5f) * 2)).toInt() - isAntiAlias = true - textSize = blockSize * 1.5f // Reduced from 2f to 1.5f to fit on screen - textAlign = Paint.Align.CENTER - typeface = android.graphics.Typeface.DEFAULT_BOLD - style = Paint.Style.FILL_AND_STROKE - strokeWidth = blockSize * 0.08f // Proportionally reduced from 0.1f - } - - // Draw text with glow - val glowPaint = Paint(textPaint).apply { - maskFilter = BlurMaskFilter(blockSize * 0.4f, BlurMaskFilter.Blur.NORMAL) // Reduced from 0.5f - alpha = (200 * Math.min(1f, (gameOverAlpha - 0.5f) * 2)).toInt() - color = Color.RED - strokeWidth = blockSize * 0.15f // Reduced from 0.2f - } - - val xPos = width / 2f - val yPos = height / 3f - - // Measure text width to check if it fits - val textWidth = textPaint.measureText("GAME OVER") - - // If text would still be too wide, scale it down further - if (textWidth > width * 0.9f) { - val scaleFactor = width * 0.9f / textWidth - textPaint.textSize *= scaleFactor - glowPaint.textSize *= scaleFactor - } - - canvas.drawText("GAME OVER", xPos, yPos, glowPaint) - canvas.drawText("GAME OVER", xPos, yPos, textPaint) - } - - // Draw falling blocks - if (gameOverBlocksY.isNotEmpty()) { - for (i in gameOverBlocksY.indices) { - val x = gameOverBlocksX[i] - val y = gameOverBlocksY[i] - val rotation = gameOverBlocksRotation[i] - val size = gameOverBlocksSize[i] * blockSize - - // Skip blocks that have fallen off the screen - if (y > height) continue - - // Draw each falling block with rotation - canvas.save() - canvas.translate(x, y) - canvas.rotate(rotation) - - // Create a pulsing effect for the falling blocks - val blockPaint = Paint(blockPaint) - blockPaint.alpha = (255 * gameOverAlpha * (1.0f - y / height.toFloat() * 0.7f)).toInt() - - // Draw block with glow effect - val blockGlowPaint = Paint(blockGlowPaint) - blockGlowPaint.alpha = (200 * gameOverAlpha * (1.0f - y / height.toFloat() * 0.5f)).toInt() - canvas.drawRect(-size/2, -size/2, size/2, size/2, blockGlowPaint) - canvas.drawRect(-size/2, -size/2, size/2, size/2, blockPaint) - - canvas.restore() - } - } - - // Reset any transformations from screen shake - if (gameOverShakeAmount > 0) { - canvas.restore() - } - } } /** @@ -761,43 +577,15 @@ class GameView @JvmOverloads constructor( val piece = gameBoard.getCurrentPiece() ?: return val ghostY = gameBoard.getGhostY() - // Draw semi-transparent background for each block for (y in 0 until piece.getHeight()) { for (x in 0 until piece.getWidth()) { if (piece.isBlockAt(x, y)) { val boardX = piece.x + x val boardY = ghostY + y + // Draw ghost piece regardless of vertical position if (boardX >= 0 && boardX < gameBoard.width) { - val screenX = boardLeft + boardX * blockSize - val screenY = boardTop + boardY * blockSize - - // Draw background - canvas.drawRect( - screenX + 1f, - screenY + 1f, - screenX + blockSize - 1f, - screenY + blockSize - 1f, - ghostBackgroundPaint - ) - - // Draw border - canvas.drawRect( - screenX + 1f, - screenY + 1f, - screenX + blockSize - 1f, - screenY + blockSize - 1f, - ghostBorderPaint - ) - - // Draw outline - canvas.drawRect( - screenX + 1f, - screenY + 1f, - screenX + blockSize - 1f, - screenY + blockSize - 1f, - ghostPaint - ) + drawBlock(canvas, boardX, boardY, true, false) } } } @@ -1104,10 +892,9 @@ class GameView @JvmOverloads constructor( invalidate() } } - // Check for hard drop (must be faster and longer than soft drop) + // Check for hard drop else if (deltaY > blockSize * minHardDropDistance && - abs(deltaX) / abs(deltaY) < 0.5f && - (deltaY / moveTime) * 1000 > minSwipeVelocity) { + abs(deltaX) / abs(deltaY) < 0.5f) { if (currentTime - lastHardDropTime < hardDropCooldown) { Log.d(TAG, "Hard drop blocked by cooldown - time since last: ${currentTime - lastHardDropTime}ms, cooldown: ${hardDropCooldown}ms") } else { @@ -1118,17 +905,10 @@ class GameView @JvmOverloads constructor( invalidate() } } - // Check for soft drop (slower and shorter than hard drop) - else if (deltaY > blockSize * minMovementThreshold && - deltaY < blockSize * maxSoftDropDistance && - (deltaY / moveTime) * 1000 < minSwipeVelocity) { - gameBoard.softDrop() - invalidate() - } // Check for rotation (quick tap with minimal movement) - else if (moveTime < minTapTime * 1.5 && // Increased from 1.0 to 1.5 for more lenient timing - abs(deltaY) < maxTapMovement * 1.5 && // Increased from 1.0 to 1.5 for more lenient movement - abs(deltaX) < maxTapMovement * 1.5) { // Increased from 1.0 to 1.5 for more lenient movement + else if (moveTime < minTapTime && + abs(deltaY) < maxTapMovement && + abs(deltaX) < maxTapMovement) { if (currentTime - lastRotationTime >= rotationCooldown) { Log.d(TAG, "Rotation detected - moveTime: $moveTime, deltaX: $deltaX, deltaY: $deltaY") gameBoard.rotate() @@ -1296,125 +1076,4 @@ class GameView @JvmOverloads constructor( super.setBackgroundColor(color) invalidate() } - - /** - * Start the game over animation - */ - fun startGameOverAnimation() { - Log.d(TAG, "Starting game over animation") - - // Check if game over already showing - if (isGameOverAnimating && gameOverAlpha > 0.5f) { - Log.d(TAG, "Game over animation already active - skipping") - return - } - - // Cancel any existing animations - pulseAnimator?.cancel() - gameOverAnimator?.cancel() - - // Trigger haptic feedback - gameHaptics?.vibrateForGameOver() - - // Force immediate visual feedback - isGameOverAnimating = true - gameOverAlpha = 0.3f - invalidate() - - // Generate falling blocks based on current board state - generateGameOverBlocks() - - // Create new game over animation - gameOverAnimator = ValueAnimator.ofFloat(0f, 1f).apply { - duration = 3000L // Increased from 2000L (2 seconds) to 3000L (3 seconds) - interpolator = LinearInterpolator() - - addUpdateListener { animation -> - val progress = animation.animatedValue as Float - - // Main alpha transition for overlay - gameOverAlpha = when { - progress < 0.2f -> progress * 5f // Quick fade in (first 20% of animation) - else -> 1f // Hold at full opacity - } - - // Color transition effect (start after 40% of animation) - gameOverColorTransition = when { - progress < 0.4f -> 0f - progress < 0.8f -> (progress - 0.4f) * 2.5f // Transition during 40%-80% - else -> 1f - } - - // Screen shake effect (strongest at beginning, fades out) - gameOverShakeAmount = when { - progress < 0.3f -> progress * 3.33f // Ramp up - progress < 0.6f -> 1f - (progress - 0.3f) * 3.33f // Ramp down - else -> 0f // No shake - } - - // Update falling blocks - updateGameOverBlocks() - - isGameOverAnimating = true - invalidate() - Log.d(TAG, "Game over animation update: alpha = $gameOverAlpha, progress = $progress") - } - - addListener(object : android.animation.AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: android.animation.Animator) { - Log.d(TAG, "Game over animation ended - Final alpha: $gameOverFinalAlpha") - isGameOverAnimating = true // Keep true to maintain visibility - gameOverAlpha = gameOverFinalAlpha // Keep at 80% opacity - invalidate() - } - }) - } - gameOverAnimator?.start() - } - - /** - * Generate falling blocks for the game over animation based on current board state - */ - private fun generateGameOverBlocks() { - // Clear existing blocks - gameOverBlocksY.clear() - gameOverBlocksX.clear() - gameOverBlocksRotation.clear() - gameOverBlocksSpeed.clear() - gameOverBlocksSize.clear() - - // Generate 30-40 blocks across the board - val numBlocks = (30 + Math.random() * 10).toInt() - - for (i in 0 until numBlocks) { - // Start positions - distribute across the board width but clustered near the top - gameOverBlocksX.add(boardLeft + (Math.random() * gameBoard.width * blockSize).toFloat()) - gameOverBlocksY.add((boardTop - blockSize * 2 + Math.random() * height * 0.3f).toFloat()) - - // Random rotation - gameOverBlocksRotation.add((Math.random() * 360).toFloat()) - - // Random fall speed (some faster, some slower) - gameOverBlocksSpeed.add((5 + Math.random() * 15).toFloat()) - - // Slightly varied block sizes - gameOverBlocksSize.add((0.8f + Math.random() * 0.4f).toFloat()) - } - } - - /** - * Update the position of falling blocks in the game over animation - */ - private fun updateGameOverBlocks() { - for (i in gameOverBlocksY.indices) { - // Update Y position based on speed - gameOverBlocksY[i] += gameOverBlocksSpeed[i] - - // Update rotation - gameOverBlocksRotation[i] += gameOverBlocksSpeed[i] * 0.5f - - // Accelerate falling - gameOverBlocksSpeed[i] *= 1.03f - } - } } diff --git a/app/src/main/java/com/mintris/model/GameBoard.kt b/app/src/main/java/com/mintris/model/GameBoard.kt index 31f03aa..ce26763 100644 --- a/app/src/main/java/com/mintris/model/GameBoard.kt +++ b/app/src/main/java/com/mintris/model/GameBoard.kt @@ -97,13 +97,8 @@ class GameBoard( if (holdPiece == null) { // If no piece is held, hold current piece and spawn new one holdPiece = current - currentPiece = nextPiece spawnNextPiece() - // Reset position of new piece - currentPiece?.apply { - x = (width - getWidth()) / 2 - y = 0 - } + spawnPiece() } else { // Swap current piece with held piece currentPiece = holdPiece @@ -136,10 +131,10 @@ class GameBoard( currentPiece = nextPiece spawnNextPiece() - // Center the piece horizontally and spawn one unit higher + // Center the piece horizontally currentPiece?.apply { x = (width - getWidth()) / 2 - y = -1 // Spawn one unit above the top of the screen + y = 0 Log.d(TAG, "spawnPiece() - new piece spawned at position (${x},${y}), type=${type}") @@ -326,11 +321,6 @@ class GameBoard( if (boardY >= 0 && grid[boardY][boardX]) { return false } - - // Check if the position is more than one unit above the top of the screen - if (boardY < -1) { - return false - } } } } diff --git a/app/src/main/res/raw/game_over.mp3 b/app/src/main/res/raw/game_over.mp3 deleted file mode 100644 index d189281..0000000 Binary files a/app/src/main/res/raw/game_over.mp3 and /dev/null differ