diff --git a/app/src/main/java/com/mintris/game/GameView.kt b/app/src/main/java/com/mintris/game/GameView.kt index 7390bf6..fe388b5 100644 --- a/app/src/main/java/com/mintris/game/GameView.kt +++ b/app/src/main/java/com/mintris/game/GameView.kt @@ -133,6 +133,10 @@ class GameView @JvmOverloads constructor( private var lastTapTime = 0L private var lastRotationTime = 0L private var lastMoveTime = 0L + private var lastHardDropTime = 0L // Track when the last hard drop occurred + private val hardDropCooldown = 250L // Reduced from 500ms to 250ms + private var touchFreezeUntil = 0L // Time until which touch events should be ignored + private val pieceLockFreezeTime = 300L // Time to freeze touch events after piece locks private var minSwipeVelocity = 1200 // Increased from 800 to require more deliberate swipes private val maxTapMovement = 20f // Maximum movement allowed for a tap (in pixels) private val minTapTime = 100L // Minimum time for a tap (in milliseconds) @@ -171,7 +175,12 @@ class GameView @JvmOverloads constructor( // Connect our callbacks to the GameBoard gameBoard.onPieceMove = { onPieceMove?.invoke() } - gameBoard.onPieceLock = { onPieceLock?.invoke() } + gameBoard.onPieceLock = { + // Freeze touch events for a brief period after a piece locks + touchFreezeUntil = System.currentTimeMillis() + pieceLockFreezeTime + Log.d(TAG, "Piece locked - freezing touch events until ${touchFreezeUntil}") + onPieceLock?.invoke() + } gameBoard.onLineClear = { lineCount, clearedLines -> Log.d(TAG, "Received line clear from GameBoard: $lineCount lines") try { @@ -697,6 +706,13 @@ class GameView @JvmOverloads constructor( return true } + // Ignore touch events during the freeze period after a piece locks + val currentTime = System.currentTimeMillis() + if (currentTime < touchFreezeUntil) { + Log.d(TAG, "Ignoring touch event - freeze active for ${touchFreezeUntil - currentTime}ms more") + return true + } + when (event.action) { MotionEvent.ACTION_DOWN -> { // Record start of touch @@ -781,21 +797,34 @@ class GameView @JvmOverloads constructor( val moveTime = System.currentTimeMillis() - lastTapTime val deltaY = event.y - startY val deltaX = event.x - startX + val currentTime = System.currentTimeMillis() - // Only allow hard drops with a deliberate downward swipe - // Requires: predominantly vertical movement, minimum distance, and minimum velocity - if (moveTime > 0 && - deltaY > blockSize * minHardDropDistance && // Require longer swipe for hard drop + // Check if this might have been a hard drop gesture + val isVerticalSwipe = moveTime > 0 && + deltaY > blockSize * minHardDropDistance && (deltaY / moveTime) * 1000 > minSwipeVelocity && - abs(deltaX) < abs(deltaY) * 0.3f) { // Require more purely vertical movement (reduced from 0.5f to 0.3f) - gameBoard.hardDrop() - invalidate() + abs(deltaX) < abs(deltaY) * 0.3f + + // Check cooldown separately for better logging + val isCooldownActive = currentTime - lastHardDropTime <= hardDropCooldown + + if (isVerticalSwipe) { + if (isCooldownActive) { + // Log when we're blocking a hard drop due to cooldown + Log.d("GameView", "Hard drop blocked by cooldown - time since last: ${currentTime - lastHardDropTime}ms, cooldown: ${hardDropCooldown}ms") + } else { + // Process the hard drop + Log.d("GameView", "Hard drop detected - deltaY: $deltaY, velocity: ${(deltaY / moveTime) * 1000}, ratio: ${abs(deltaX) / abs(deltaY)}") + gameBoard.hardDrop() + lastHardDropTime = currentTime // Update the last hard drop time + invalidate() + } } else if (moveTime < minTapTime && abs(deltaY) < maxTapMovement && abs(deltaX) < maxTapMovement) { // Quick tap with minimal movement (rotation) - val currentTime = System.currentTimeMillis() if (currentTime - lastRotationTime >= rotationCooldown) { + Log.d("GameView", "Rotation detected") gameBoard.rotate() lastRotationTime = currentTime invalidate() diff --git a/app/src/main/java/com/mintris/model/GameBoard.kt b/app/src/main/java/com/mintris/model/GameBoard.kt index d871e4b..ce26763 100644 --- a/app/src/main/java/com/mintris/model/GameBoard.kt +++ b/app/src/main/java/com/mintris/model/GameBoard.kt @@ -63,6 +63,10 @@ class GameBoard( // Store the last cleared lines private val lastClearedLines = mutableListOf() + // Add spawn protection variables + private var pieceSpawnTime = 0L + private val spawnGracePeriod = 250L // Changed from 150ms to 250ms + init { spawnNextPiece() spawnPiece() @@ -122,6 +126,8 @@ class GameBoard( * Spawns the current tetromino at the top of the board */ fun spawnPiece() { + Log.d(TAG, "spawnPiece() started - current states: isHardDropInProgress=$isHardDropInProgress, isPieceLocking=$isPieceLocking") + currentPiece = nextPiece spawnNextPiece() @@ -130,9 +136,15 @@ class GameBoard( x = (width - getWidth()) / 2 y = 0 + Log.d(TAG, "spawnPiece() - new piece spawned at position (${x},${y}), type=${type}") + + // Set the spawn time for the grace period + pieceSpawnTime = System.currentTimeMillis() + // Check if the piece can be placed (Game Over condition) if (!canMove(0, 0)) { isGameOver = true + Log.d(TAG, "spawnPiece() - Game Over condition detected") } } } @@ -173,6 +185,13 @@ class GameBoard( onPieceMove?.invoke() true } else { + // Check if we're within the spawn grace period + val currentTime = System.currentTimeMillis() + if (currentTime - pieceSpawnTime < spawnGracePeriod) { + Log.d(TAG, "moveDown() - not locking piece due to spawn grace period (${currentTime - pieceSpawnTime}ms < ${spawnGracePeriod}ms)") + return false + } + lockPiece() false } @@ -191,8 +210,19 @@ class GameBoard( * Hard drop the current piece */ fun hardDrop() { - if (isHardDropInProgress || isPieceLocking) return // Prevent multiple hard drops + if (isHardDropInProgress || isPieceLocking) { + Log.d(TAG, "hardDrop() called but blocked: isHardDropInProgress=$isHardDropInProgress, isPieceLocking=$isPieceLocking") + return // Prevent multiple hard drops + } + // Check if we're within the spawn grace period + val currentTime = System.currentTimeMillis() + if (currentTime - pieceSpawnTime < spawnGracePeriod) { + Log.d(TAG, "hardDrop() - blocked due to spawn grace period (${currentTime - pieceSpawnTime}ms < ${spawnGracePeriod}ms)") + return + } + + Log.d(TAG, "hardDrop() started - setting isHardDropInProgress=true") isHardDropInProgress = true val piece = currentPiece ?: return @@ -202,12 +232,16 @@ class GameBoard( dropDistance++ } + Log.d(TAG, "hardDrop() - piece will drop $dropDistance cells, position before: (${piece.x},${piece.y})") + // Move piece down until it can't move anymore while (canMove(0, 1)) { piece.y++ onPieceMove?.invoke() } + Log.d(TAG, "hardDrop() - piece final position: (${piece.x},${piece.y})") + // Add hard drop points (2 points per cell) score += dropDistance * 2 @@ -298,7 +332,12 @@ class GameBoard( * Lock the current piece in place */ private fun lockPiece() { - if (isPieceLocking) return // Prevent recursive locking + if (isPieceLocking) { + Log.d(TAG, "lockPiece() called but blocked: isPieceLocking=$isPieceLocking") + return // Prevent recursive locking + } + + Log.d(TAG, "lockPiece() started - setting isPieceLocking=true, current isHardDropInProgress=$isHardDropInProgress") isPieceLocking = true val piece = currentPiece ?: return @@ -324,15 +363,25 @@ class GameBoard( // Find and clear lines immediately findAndClearLines() + // IMPORTANT: Reset the hard drop flag before spawning a new piece + // This prevents the immediate hard drop of the next piece + if (isHardDropInProgress) { + Log.d(TAG, "lockPiece() - resetting isHardDropInProgress=false BEFORE spawning new piece") + isHardDropInProgress = false + } + + // Log piece position before spawning new piece + Log.d(TAG, "lockPiece() - about to spawn new piece at y=${piece.y}, isHardDropInProgress=$isHardDropInProgress") + // Spawn new piece immediately spawnPiece() // Allow holding piece again after locking canHold = true - // Reset both states after everything is done + // Reset locking state isPieceLocking = false - isHardDropInProgress = false + Log.d(TAG, "lockPiece() completed - reset flags: isPieceLocking=false, isHardDropInProgress=$isHardDropInProgress") } /**