diff --git a/app/src/main/java/com/mintris/MainActivity.kt b/app/src/main/java/com/mintris/MainActivity.kt index 8b4602e..3e94bac 100644 --- a/app/src/main/java/com/mintris/MainActivity.kt +++ b/app/src/main/java/com/mintris/MainActivity.kt @@ -172,15 +172,6 @@ class MainActivity : AppCompatActivity() { binding.nextPieceView.invalidate() } - // Set up hold piece preview - binding.holdPieceView.setGameView(gameView) - gameBoard.onPieceLock = { - binding.holdPieceView.invalidate() - } - gameBoard.onPieceMove = { - binding.holdPieceView.invalidate() - } - // Set up music toggle binding.musicToggle.setOnClickListener { isMusicEnabled = !isMusicEnabled diff --git a/app/src/main/java/com/mintris/game/GameView.kt b/app/src/main/java/com/mintris/game/GameView.kt index f1608f4..1095af8 100644 --- a/app/src/main/java/com/mintris/game/GameView.kt +++ b/app/src/main/java/com/mintris/game/GameView.kt @@ -140,21 +140,15 @@ class GameView @JvmOverloads constructor( 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 = 30f // Increased from 20f to 30f for more lenient tap detection + private val maxTapMovement = 20f // Maximum movement allowed for a tap (in pixels) private val minTapTime = 100L // Minimum time for a tap (in milliseconds) private val rotationCooldown = 150L // Minimum time between rotations (in milliseconds) private val moveCooldown = 50L // Minimum time between move haptics (in milliseconds) - private val doubleTapTimeout = 400L // Increased from 300ms to 400ms for more lenient double tap detection - private var lastTapX = 0f // X coordinate of last tap - private var lastTapY = 0f // Y coordinate of last tap - 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.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 minMovementThreshold = 0.75f // Minimum movement threshold relative to block size + private val directionLockThreshold = 2.5f // Increased from 1.5f to make direction locking more aggressive + private val isStrictDirectionLock = true // Enable strict direction locking to prevent diagonal inputs 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 // Block skin private var currentBlockSkin: String = "block_skin_1" @@ -809,33 +803,46 @@ class GameView @JvmOverloads constructor( when (event.action) { MotionEvent.ACTION_DOWN -> { + // Record start of touch startX = event.x startY = event.y lastTouchX = event.x lastTouchY = event.y - lastTapTime = currentTime // Set the tap time when touch starts + lockedDirection = null // Reset direction lock - // Reset direction lock - lockedDirection = null + // Check for double tap (rotate) + val currentTime = System.currentTimeMillis() + if (currentTime - lastTapTime < 200) { // Reduced from 250ms for faster response + // Double tap detected, rotate the piece + if (currentTime - lastRotationTime >= rotationCooldown) { + gameBoard.rotate() + lastRotationTime = currentTime + invalidate() + } + } + lastTapTime = currentTime } MotionEvent.ACTION_MOVE -> { val deltaX = event.x - lastTouchX val deltaY = event.y - lastTouchY + val currentTime = System.currentTimeMillis() - // Check if we should lock direction + // Determine movement direction if not locked if (lockedDirection == null) { val absDeltaX = abs(deltaX) val absDeltaY = abs(deltaY) - if (absDeltaX > blockSize * directionLockThreshold || - absDeltaY > blockSize * directionLockThreshold) { - // Lock to the dominant direction - lockedDirection = if (absDeltaX > absDeltaY) { - Direction.HORIZONTAL - } else { - Direction.VERTICAL + // Check if movement exceeds threshold + if (absDeltaX > blockSize * minMovementThreshold || absDeltaY > blockSize * minMovementThreshold) { + // Determine dominant direction with stricter criteria + if (absDeltaX > absDeltaY * directionLockThreshold) { + lockedDirection = Direction.HORIZONTAL + } else if (absDeltaY > absDeltaX * directionLockThreshold) { + lockedDirection = Direction.VERTICAL } + // If strict direction lock is enabled and we couldn't determine a clear direction, don't set one + // This prevents diagonal movements from being recognized } } @@ -874,43 +881,38 @@ class GameView @JvmOverloads constructor( } MotionEvent.ACTION_UP -> { - val deltaX = event.x - startX + // Calculate movement speed for potential fling detection + val moveTime = System.currentTimeMillis() - lastTapTime val deltaY = event.y - startY - val moveTime = currentTime - lastTapTime + val deltaX = event.x - startX + val currentTime = System.currentTimeMillis() - // Check for hold gesture (swipe up) - if (deltaY < -blockSize * minHoldDistance && - abs(deltaX) / abs(deltaY) < 0.5f) { - if (currentTime - lastHoldTime < holdCooldown) { - Log.d(TAG, "Hold blocked by cooldown - time since last: ${currentTime - lastHoldTime}ms, cooldown: ${holdCooldown}ms") - } else { - // Process the hold - Log.d(TAG, "Hold detected - deltaY: $deltaY, ratio: ${abs(deltaX) / abs(deltaY)}") - gameBoard.holdPiece() - lastHoldTime = currentTime - gameHaptics?.vibrateForPieceMove() - invalidate() - } - } - // Check for hard drop - else if (deltaY > blockSize * minHardDropDistance && - 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") + // 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 + + // 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(TAG, "Hard drop detected - deltaY: $deltaY, velocity: ${(deltaY / moveTime) * 1000}, ratio: ${abs(deltaX) / abs(deltaY)}") + Log.d("GameView", "Hard drop detected - deltaY: $deltaY, velocity: ${(deltaY / moveTime) * 1000}, ratio: ${abs(deltaX) / abs(deltaY)}") gameBoard.hardDrop() - lastHardDropTime = currentTime + lastHardDropTime = currentTime // Update the last hard drop time invalidate() } - } - // Check for rotation (quick tap with minimal movement) - else if (moveTime < minTapTime && + } else if (moveTime < minTapTime && abs(deltaY) < maxTapMovement && abs(deltaX) < maxTapMovement) { + // Quick tap with minimal movement (rotation) if (currentTime - lastRotationTime >= rotationCooldown) { - Log.d(TAG, "Rotation detected - moveTime: $moveTime, deltaX: $deltaX, deltaY: $deltaY") + Log.d("GameView", "Rotation detected") gameBoard.rotate() lastRotationTime = currentTime invalidate() @@ -952,11 +954,6 @@ class GameView @JvmOverloads constructor( return gameBoard.getNextPiece() } - /** - * Get the game board instance - */ - fun getGameBoard(): GameBoard = gameBoard - /** * Clean up resources when view is detached */ diff --git a/app/src/main/java/com/mintris/game/HoldPieceView.kt b/app/src/main/java/com/mintris/game/HoldPieceView.kt deleted file mode 100644 index 6f51022..0000000 --- a/app/src/main/java/com/mintris/game/HoldPieceView.kt +++ /dev/null @@ -1,134 +0,0 @@ -package com.mintris.game - -import android.content.Context -import android.graphics.BlurMaskFilter -import android.graphics.Canvas -import android.graphics.Color -import android.graphics.Paint -import android.util.AttributeSet -import android.view.View -import com.mintris.model.GameBoard -import com.mintris.model.Tetromino -import kotlin.math.min - -/** - * View that displays the currently held piece - */ -class HoldPieceView @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : View(context, attrs, defStyleAttr) { - - private var gameView: GameView? = null - private var gameBoard: GameBoard? = null - - // Rendering - private val blockPaint = Paint().apply { - color = Color.WHITE - isAntiAlias = true - style = Paint.Style.FILL - } - - private val glowPaint = Paint().apply { - color = Color.WHITE - alpha = 40 - isAntiAlias = true - style = Paint.Style.STROKE - strokeWidth = 1.5f - maskFilter = BlurMaskFilter(8f, BlurMaskFilter.Blur.OUTER) - } - - private val blockGlowPaint = Paint().apply { - color = Color.WHITE - alpha = 60 - isAntiAlias = true - style = Paint.Style.FILL - maskFilter = BlurMaskFilter(12f, BlurMaskFilter.Blur.OUTER) - } - - /** - * Set the game view reference - */ - fun setGameView(view: GameView) { - gameView = view - gameBoard = view.getGameBoard() - } - - /** - * Get the game board reference - */ - private fun getGameBoard(): GameBoard? = gameBoard - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - - // Get the held piece from game board - gameBoard?.let { - it.getHoldPiece()?.let { piece -> - val width = piece.getWidth() - val height = piece.getHeight() - - // Calculate block size for the preview (smaller than main board) - val previewBlockSize = min( - canvas.width.toFloat() / (width + 2), - canvas.height.toFloat() / (height + 2) - ) - - // Center the piece in the preview area - val previewLeft = (canvas.width - width * previewBlockSize) / 2 - val previewTop = (canvas.height - height * previewBlockSize) / 2 - - // Draw subtle background glow - val glowPaint = Paint().apply { - color = Color.WHITE - alpha = 10 - maskFilter = BlurMaskFilter(previewBlockSize * 0.5f, BlurMaskFilter.Blur.OUTER) - } - canvas.drawRect( - previewLeft - previewBlockSize, - previewTop - previewBlockSize, - previewLeft + width * previewBlockSize + previewBlockSize, - previewTop + height * previewBlockSize + previewBlockSize, - glowPaint - ) - - // Draw the held piece - for (y in 0 until height) { - for (x in 0 until width) { - if (piece.isBlockAt(x, y)) { - val left = previewLeft + x * previewBlockSize - val top = previewTop + y * previewBlockSize - val right = left + previewBlockSize - val bottom = top + previewBlockSize - - // Draw outer glow - blockGlowPaint.color = Color.WHITE - canvas.drawRect( - left - 2f, - top - 2f, - right + 2f, - bottom + 2f, - blockGlowPaint - ) - - // Draw block - blockPaint.color = Color.WHITE - canvas.drawRect(left, top, right, bottom, blockPaint) - - // Draw inner glow - glowPaint.color = Color.WHITE - canvas.drawRect( - left + 1f, - top + 1f, - right - 1f, - bottom - 1f, - glowPaint - ) - } - } - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/res/drawable/preview_border.xml b/app/src/main/res/drawable/preview_border.xml deleted file mode 100644 index a28f95b..0000000 --- a/app/src/main/res/drawable/preview_border.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 9b2b84a..2224e92 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -99,28 +99,12 @@ - - - - - - + android:layout_gravity="end" /> - - -