mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-22 12:45:23 +01:00
Compare commits
No commits in common. "53c46c9864042dd38d43a019b81cd85e9e91c850" and "103a21d9b74b401694f517fa2618d43d1a51fc36" have entirely different histories.
53c46c9864
...
103a21d9b7
5 changed files with 55 additions and 235 deletions
|
@ -172,15 +172,6 @@ class MainActivity : AppCompatActivity() {
|
||||||
binding.nextPieceView.invalidate()
|
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
|
// Set up music toggle
|
||||||
binding.musicToggle.setOnClickListener {
|
binding.musicToggle.setOnClickListener {
|
||||||
isMusicEnabled = !isMusicEnabled
|
isMusicEnabled = !isMusicEnabled
|
||||||
|
|
|
@ -140,21 +140,15 @@ class GameView @JvmOverloads constructor(
|
||||||
private var touchFreezeUntil = 0L // Time until which touch events should be ignored
|
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 val pieceLockFreezeTime = 300L // Time to freeze touch events after piece locks
|
||||||
private var minSwipeVelocity = 1200 // Increased from 800 to require more deliberate swipes
|
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 minTapTime = 100L // Minimum time for a tap (in milliseconds)
|
||||||
private val rotationCooldown = 150L // Minimum time between rotations (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 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 var lockedDirection: Direction? = null // Track the locked movement direction
|
||||||
private val minMovementThreshold = 0.5f // Reduced from 0.75f for more sensitive movement
|
private val minMovementThreshold = 0.75f // Minimum movement threshold relative to block size
|
||||||
private val directionLockThreshold = 1.5f // Reduced from 2.5f to make direction locking less aggressive
|
private val directionLockThreshold = 2.5f // Increased from 1.5f to make direction locking more aggressive
|
||||||
private val isStrictDirectionLock = true // Re-enabled strict direction locking to prevent diagonal inputs
|
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 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
|
// Block skin
|
||||||
private var currentBlockSkin: String = "block_skin_1"
|
private var currentBlockSkin: String = "block_skin_1"
|
||||||
|
@ -809,33 +803,46 @@ class GameView @JvmOverloads constructor(
|
||||||
|
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
// Record start of touch
|
||||||
startX = event.x
|
startX = event.x
|
||||||
startY = event.y
|
startY = event.y
|
||||||
lastTouchX = event.x
|
lastTouchX = event.x
|
||||||
lastTouchY = event.y
|
lastTouchY = event.y
|
||||||
lastTapTime = currentTime // Set the tap time when touch starts
|
lockedDirection = null // Reset direction lock
|
||||||
|
|
||||||
// Reset direction lock
|
// Check for double tap (rotate)
|
||||||
lockedDirection = null
|
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 -> {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
val deltaX = event.x - lastTouchX
|
val deltaX = event.x - lastTouchX
|
||||||
val deltaY = event.y - lastTouchY
|
val deltaY = event.y - lastTouchY
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
|
||||||
// Check if we should lock direction
|
// Determine movement direction if not locked
|
||||||
if (lockedDirection == null) {
|
if (lockedDirection == null) {
|
||||||
val absDeltaX = abs(deltaX)
|
val absDeltaX = abs(deltaX)
|
||||||
val absDeltaY = abs(deltaY)
|
val absDeltaY = abs(deltaY)
|
||||||
|
|
||||||
if (absDeltaX > blockSize * directionLockThreshold ||
|
// Check if movement exceeds threshold
|
||||||
absDeltaY > blockSize * directionLockThreshold) {
|
if (absDeltaX > blockSize * minMovementThreshold || absDeltaY > blockSize * minMovementThreshold) {
|
||||||
// Lock to the dominant direction
|
// Determine dominant direction with stricter criteria
|
||||||
lockedDirection = if (absDeltaX > absDeltaY) {
|
if (absDeltaX > absDeltaY * directionLockThreshold) {
|
||||||
Direction.HORIZONTAL
|
lockedDirection = Direction.HORIZONTAL
|
||||||
} else {
|
} else if (absDeltaY > absDeltaX * directionLockThreshold) {
|
||||||
Direction.VERTICAL
|
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 -> {
|
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 deltaY = event.y - startY
|
||||||
val moveTime = currentTime - lastTapTime
|
val deltaX = event.x - startX
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
|
||||||
// Check for hold gesture (swipe up)
|
// Check if this might have been a hard drop gesture
|
||||||
if (deltaY < -blockSize * minHoldDistance &&
|
val isVerticalSwipe = moveTime > 0 &&
|
||||||
abs(deltaX) / abs(deltaY) < 0.5f) {
|
deltaY > blockSize * minHardDropDistance &&
|
||||||
if (currentTime - lastHoldTime < holdCooldown) {
|
(deltaY / moveTime) * 1000 > minSwipeVelocity &&
|
||||||
Log.d(TAG, "Hold blocked by cooldown - time since last: ${currentTime - lastHoldTime}ms, cooldown: ${holdCooldown}ms")
|
abs(deltaX) < abs(deltaY) * 0.3f
|
||||||
} else {
|
|
||||||
// Process the hold
|
// Check cooldown separately for better logging
|
||||||
Log.d(TAG, "Hold detected - deltaY: $deltaY, ratio: ${abs(deltaX) / abs(deltaY)}")
|
val isCooldownActive = currentTime - lastHardDropTime <= hardDropCooldown
|
||||||
gameBoard.holdPiece()
|
|
||||||
lastHoldTime = currentTime
|
if (isVerticalSwipe) {
|
||||||
gameHaptics?.vibrateForPieceMove()
|
if (isCooldownActive) {
|
||||||
invalidate()
|
// 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")
|
||||||
}
|
|
||||||
// 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")
|
|
||||||
} else {
|
} else {
|
||||||
// Process the hard drop
|
// 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()
|
gameBoard.hardDrop()
|
||||||
lastHardDropTime = currentTime
|
lastHardDropTime = currentTime // Update the last hard drop time
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
}
|
} else if (moveTime < minTapTime &&
|
||||||
// Check for rotation (quick tap with minimal movement)
|
|
||||||
else if (moveTime < minTapTime &&
|
|
||||||
abs(deltaY) < maxTapMovement &&
|
abs(deltaY) < maxTapMovement &&
|
||||||
abs(deltaX) < maxTapMovement) {
|
abs(deltaX) < maxTapMovement) {
|
||||||
|
// Quick tap with minimal movement (rotation)
|
||||||
if (currentTime - lastRotationTime >= rotationCooldown) {
|
if (currentTime - lastRotationTime >= rotationCooldown) {
|
||||||
Log.d(TAG, "Rotation detected - moveTime: $moveTime, deltaX: $deltaX, deltaY: $deltaY")
|
Log.d("GameView", "Rotation detected")
|
||||||
gameBoard.rotate()
|
gameBoard.rotate()
|
||||||
lastRotationTime = currentTime
|
lastRotationTime = currentTime
|
||||||
invalidate()
|
invalidate()
|
||||||
|
@ -952,11 +954,6 @@ class GameView @JvmOverloads constructor(
|
||||||
return gameBoard.getNextPiece()
|
return gameBoard.getNextPiece()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the game board instance
|
|
||||||
*/
|
|
||||||
fun getGameBoard(): GameBoard = gameBoard
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up resources when view is detached
|
* Clean up resources when view is detached
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:shape="rectangle">
|
|
||||||
<stroke
|
|
||||||
android:width="2dp"
|
|
||||||
android:color="#FFFFFF" />
|
|
||||||
<solid android:color="#00000000" />
|
|
||||||
</shape>
|
|
|
@ -99,28 +99,12 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Next Piece Preview -->
|
<!-- Next Piece Preview -->
|
||||||
<LinearLayout
|
<com.mintris.game.NextPieceView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/nextPieceView"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="80dp"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end" />
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="NEXT"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:fontFamily="sans-serif"
|
|
||||||
android:layout_marginBottom="4dp" />
|
|
||||||
|
|
||||||
<com.mintris.game.NextPieceView
|
|
||||||
android:id="@+id/nextPieceView"
|
|
||||||
android:layout_width="80dp"
|
|
||||||
android:layout_height="80dp" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- Settings button -->
|
<!-- Settings button -->
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -135,16 +119,6 @@
|
||||||
android:src="@drawable/ic_pause" />
|
android:src="@drawable/ic_pause" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Hold Piece Preview -->
|
|
||||||
<com.mintris.game.HoldPieceView
|
|
||||||
android:id="@+id/holdPieceView"
|
|
||||||
android:layout_width="60dp"
|
|
||||||
android:layout_height="60dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<!-- Game Over overlay -->
|
<!-- Game Over overlay -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gameOverContainer"
|
android:id="@+id/gameOverContainer"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue