diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index aaa37f3..bc5761a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -28,12 +28,7 @@
-
-
+ android:theme="@style/Theme.AppCompat.NoActionBar"
+ android:exported="false" />
\ No newline at end of file
diff --git a/app/src/main/java/com/mintris/MainActivity.kt b/app/src/main/java/com/mintris/MainActivity.kt
index fd49615..d6eac7e 100644
--- a/app/src/main/java/com/mintris/MainActivity.kt
+++ b/app/src/main/java/com/mintris/MainActivity.kt
@@ -21,9 +21,6 @@ import com.mintris.model.GameBoard
import com.mintris.audio.GameMusic
import com.mintris.model.HighScoreManager
import android.content.Intent
-import com.mintris.model.StatsManager
-import java.text.SimpleDateFormat
-import java.util.*
class MainActivity : AppCompatActivity() {
@@ -35,7 +32,6 @@ class MainActivity : AppCompatActivity() {
private lateinit var gameMusic: GameMusic
private lateinit var titleScreen: TitleScreen
private lateinit var highScoreManager: HighScoreManager
- private lateinit var statsManager: StatsManager
// Game state
private var isSoundEnabled = true
@@ -44,8 +40,6 @@ class MainActivity : AppCompatActivity() {
private val maxLevel = 20
private var currentScore = 0
private var currentLevel = 1
- private var gameStartTime: Long = 0
- private var piecesPlaced: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -59,7 +53,6 @@ class MainActivity : AppCompatActivity() {
titleScreen = binding.titleScreen
gameMusic = GameMusic(this)
highScoreManager = HighScoreManager(this)
- statsManager = StatsManager(this)
// Set up game view
gameView.setGameBoard(gameBoard)
@@ -124,8 +117,6 @@ class MainActivity : AppCompatActivity() {
} else {
android.util.Log.d("MainActivity", "Sound is disabled, skipping haptic feedback")
}
- // Record line clear in stats
- statsManager.recordLineClear(lineCount)
}
// Add callbacks for piece movement and locking
@@ -139,7 +130,6 @@ class MainActivity : AppCompatActivity() {
if (isSoundEnabled) {
gameHaptics.vibrateForPieceLock()
}
- piecesPlaced++
}
// Set up button click listeners with haptic feedback
@@ -197,13 +187,6 @@ class MainActivity : AppCompatActivity() {
}
}
- // Set up stats button
- binding.statsButton.setOnClickListener {
- gameHaptics.performHapticFeedback(it, HapticFeedbackConstants.VIRTUAL_KEY)
- val intent = Intent(this, StatsActivity::class.java)
- startActivity(intent)
- }
-
// Initialize level selector
updateLevelSelector()
@@ -222,9 +205,6 @@ class MainActivity : AppCompatActivity() {
binding.linesText.text = lines.toString()
binding.comboText.text = gameBoard.getCombo().toString()
- // Update current level for stats
- currentLevel = level
-
// Force redraw of next piece preview
binding.nextPieceView.invalidate()
}
@@ -233,35 +213,7 @@ class MainActivity : AppCompatActivity() {
* Show game over screen
*/
private fun showGameOver(score: Int) {
- val gameTime = System.currentTimeMillis() - gameStartTime
-
- // Update session stats
- statsManager.updateSessionStats(
- score = score,
- lines = gameBoard.lines,
- pieces = piecesPlaced,
- time = gameTime,
- level = currentLevel
- )
-
- // End session and save stats
- statsManager.endSession()
-
- // Update session stats display
- val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
- timeFormat.timeZone = TimeZone.getTimeZone("UTC")
-
- binding.sessionScoreText.text = getString(R.string.session_score, score)
- binding.sessionLinesText.text = getString(R.string.session_lines, gameBoard.lines)
- binding.sessionPiecesText.text = getString(R.string.session_pieces, piecesPlaced)
- binding.sessionTimeText.text = getString(R.string.session_time, timeFormat.format(gameTime))
- binding.sessionLevelText.text = getString(R.string.session_level, currentLevel)
-
- // Update session line clear stats
- binding.sessionSinglesText.text = getString(R.string.singles, statsManager.getSessionSingles())
- binding.sessionDoublesText.text = getString(R.string.doubles, statsManager.getSessionDoubles())
- binding.sessionTriplesText.text = getString(R.string.triples, statsManager.getSessionTriples())
- binding.sessionTetrisesText.text = getString(R.string.tetrises, statsManager.getSessionTetrises())
+ binding.finalScoreText.text = getString(R.string.score) + ": " + score
// Check if this is a high score
if (highScoreManager.isHighScore(score)) {
@@ -339,13 +291,10 @@ class MainActivity : AppCompatActivity() {
private fun startGame() {
gameView.start()
- gameMusic.setEnabled(isMusicEnabled)
+ gameMusic.setEnabled(isMusicEnabled) // Explicitly set enabled state
if (isMusicEnabled) {
gameMusic.start()
}
- gameStartTime = System.currentTimeMillis()
- piecesPlaced = 0
- statsManager.startNewSession()
}
private fun restartGame() {
diff --git a/app/src/main/java/com/mintris/StatsActivity.kt b/app/src/main/java/com/mintris/StatsActivity.kt
deleted file mode 100644
index 269adb0..0000000
--- a/app/src/main/java/com/mintris/StatsActivity.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.mintris
-
-import android.os.Bundle
-import android.widget.Button
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import com.mintris.databinding.ActivityStatsBinding
-import com.mintris.model.StatsManager
-import java.text.SimpleDateFormat
-import java.util.*
-
-class StatsActivity : AppCompatActivity() {
- private lateinit var binding: ActivityStatsBinding
- private lateinit var statsManager: StatsManager
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityStatsBinding.inflate(layoutInflater)
- setContentView(binding.root)
-
- statsManager = StatsManager(this)
-
- // Set up back button
- binding.backButton.setOnClickListener {
- finish()
- }
-
- updateStats()
- }
-
- private fun updateStats() {
- // Format time duration
- val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
- timeFormat.timeZone = TimeZone.getTimeZone("UTC")
-
- // Update lifetime stats
- binding.totalGamesText.text = getString(R.string.total_games, statsManager.getTotalGames())
- binding.totalScoreText.text = getString(R.string.total_score, statsManager.getTotalScore())
- binding.totalLinesText.text = getString(R.string.total_lines, statsManager.getTotalLines())
- binding.totalPiecesText.text = getString(R.string.total_pieces, statsManager.getTotalPieces())
- binding.totalTimeText.text = getString(R.string.total_time, timeFormat.format(statsManager.getTotalTime()))
-
- // Update line clear stats
- binding.totalSinglesText.text = getString(R.string.singles, statsManager.getTotalSingles())
- binding.totalDoublesText.text = getString(R.string.doubles, statsManager.getTotalDoubles())
- binding.totalTriplesText.text = getString(R.string.triples, statsManager.getTotalTriples())
- binding.totalTetrisesText.text = getString(R.string.tetrises, statsManager.getTotalTetrises())
-
- // Update best performance stats
- binding.maxLevelText.text = getString(R.string.max_level, statsManager.getMaxLevel())
- binding.maxScoreText.text = getString(R.string.max_score, statsManager.getMaxScore())
- binding.maxLinesText.text = getString(R.string.max_lines, statsManager.getMaxLines())
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/mintris/game/TitleScreen.kt b/app/src/main/java/com/mintris/game/TitleScreen.kt
index 3a8978d..379caaf 100644
--- a/app/src/main/java/com/mintris/game/TitleScreen.kt
+++ b/app/src/main/java/com/mintris/game/TitleScreen.kt
@@ -12,10 +12,6 @@ import java.util.Random
import android.util.Log
import com.mintris.model.HighScoreManager
import com.mintris.model.HighScore
-import kotlin.math.abs
-import androidx.core.graphics.withTranslation
-import androidx.core.graphics.withScale
-import androidx.core.graphics.withRotation
class TitleScreen @JvmOverloads constructor(
context: Context,
@@ -33,14 +29,6 @@ class TitleScreen @JvmOverloads constructor(
private var width = 0
private var height = 0
private val tetrominosToAdd = mutableListOf()
- private val highScoreManager = HighScoreManager(context) // Pre-allocate HighScoreManager
-
- // Touch handling variables
- private var startX = 0f
- private var startY = 0f
- private var lastTouchX = 0f
- private var lastTouchY = 0f
- private val maxTapMovement = 20f // Maximum movement allowed for a tap (in pixels)
// Callback for when the user touches the screen
var onStartGame: (() -> Unit)? = null
@@ -199,31 +187,58 @@ class TitleScreen @JvmOverloads constructor(
tetrominosToAdd.add(createRandomTetromino())
} else {
try {
+ // Save canvas state before rotation
+ canvas.save()
+
+ // Translate to the tetromino's position
+ canvas.translate(tetromino.x, tetromino.y)
+
+ // Scale according to the tetromino's scale factor
+ canvas.scale(tetromino.scale, tetromino.scale)
+
+ // Rotate around the center of the tetromino
+ val centerX = tetromino.shape.size * cellSize / 2
+ val centerY = tetromino.shape.size * cellSize / 2
+ canvas.rotate(tetromino.rotation.toFloat(), centerX, centerY)
+
// Draw the tetromino
- for (y in 0 until tetromino.shape.size) {
- for (x in 0 until tetromino.shape.size) {
- if (tetromino.shape[y][x] == 1) {
- val left = x * cellSize
- val top = y * cellSize
- val right = left + cellSize
- val bottom = top + cellSize
+ for (row in tetromino.shape.indices) {
+ for (col in 0 until tetromino.shape[row].size) {
+ if (tetromino.shape[row][col] == 1) {
+ // Draw larger glow effect
+ glowPaint.alpha = 30
+ canvas.drawRect(
+ col * cellSize - 8,
+ row * cellSize - 8,
+ (col + 1) * cellSize + 8,
+ (row + 1) * cellSize + 8,
+ glowPaint
+ )
- // Draw block with glow effect
- canvas.withTranslation(tetromino.x, tetromino.y) {
- withScale(tetromino.scale, tetromino.scale) {
- withRotation(tetromino.rotation.toFloat(),
- tetromino.shape.size * cellSize / 2,
- tetromino.shape.size * cellSize / 2) {
- // Draw glow
- canvas.drawRect(left - 8f, top - 8f, right + 8f, bottom + 8f, glowPaint)
- // Draw block
- canvas.drawRect(left, top, right, bottom, paint)
- }
- }
- }
+ // Draw medium glow
+ glowPaint.alpha = 60
+ canvas.drawRect(
+ col * cellSize - 4,
+ row * cellSize - 4,
+ (col + 1) * cellSize + 4,
+ (row + 1) * cellSize + 4,
+ glowPaint
+ )
+
+ // Draw main block
+ canvas.drawRect(
+ col * cellSize,
+ row * cellSize,
+ (col + 1) * cellSize,
+ (row + 1) * cellSize,
+ paint
+ )
}
}
}
+
+ // Restore canvas state
+ canvas.restore()
} catch (e: Exception) {
Log.e("TitleScreen", "Error drawing tetromino", e)
}
@@ -237,7 +252,8 @@ class TitleScreen @JvmOverloads constructor(
val titleY = height * 0.4f
canvas.drawText("mintris", width / 2f, titleY, titlePaint)
- // Draw high scores using pre-allocated manager
+ // Draw high scores
+ val highScoreManager = HighScoreManager(context)
val highScores: List = highScoreManager.getHighScores()
val highScoreY = height * 0.5f
if (highScores.isNotEmpty()) {
@@ -258,50 +274,10 @@ class TitleScreen @JvmOverloads constructor(
}
override fun onTouchEvent(event: MotionEvent): Boolean {
- when (event.action) {
- MotionEvent.ACTION_DOWN -> {
- startX = event.x
- startY = event.y
- lastTouchX = event.x
- lastTouchY = event.y
- return true
- }
- MotionEvent.ACTION_MOVE -> {
- val deltaX = event.x - lastTouchX
- val deltaY = event.y - lastTouchY
-
- // Update tetromino positions
- for (tetromino in tetrominos) {
- tetromino.x += deltaX * 0.5f
- tetromino.y += deltaY * 0.5f
- }
-
- lastTouchX = event.x
- lastTouchY = event.y
- invalidate()
- return true
- }
- MotionEvent.ACTION_UP -> {
- val deltaX = event.x - startX
- val deltaY = event.y - startY
-
- // If the movement was minimal, treat as a tap
- if (abs(deltaX) < maxTapMovement && abs(deltaY) < maxTapMovement) {
- performClick()
- }
-
- return true
- }
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ onStartGame?.invoke()
+ return true
}
return super.onTouchEvent(event)
}
-
- override fun performClick(): Boolean {
- // Call the superclass's performClick
- super.performClick()
-
- // Handle the click event
- onStartGame?.invoke()
- return true
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mintris/model/GameBoard.kt b/app/src/main/java/com/mintris/model/GameBoard.kt
index 42deaf3..3119971 100644
--- a/app/src/main/java/com/mintris/model/GameBoard.kt
+++ b/app/src/main/java/com/mintris/model/GameBoard.kt
@@ -31,8 +31,6 @@ class GameBoard(
var level = 1
var lines = 0
var isGameOver = false
- var isHardDropInProgress = false // Make public
- var isPieceLocking = false // Make public
// Scoring state
private var combo = 0
@@ -152,9 +150,6 @@ class GameBoard(
* Move the current piece down (soft drop)
*/
fun moveDown(): Boolean {
- // Don't allow movement if a hard drop is in progress or piece is locking
- if (isHardDropInProgress || isPieceLocking) return false
-
return if (canMove(0, 1)) {
currentPiece?.y = currentPiece?.y?.plus(1) ?: 0
onPieceMove?.invoke()
@@ -169,19 +164,9 @@ class GameBoard(
* Hard drop the current piece
*/
fun hardDrop() {
- if (isHardDropInProgress || isPieceLocking) return // Prevent multiple hard drops
-
- isHardDropInProgress = true
- val piece = currentPiece ?: return
-
- // Move piece down until it can't move anymore
- while (canMove(0, 1)) {
- piece.y++
- onPieceMove?.invoke()
+ while (moveDown()) {
+ // Keep moving down until blocked
}
-
- // Lock the piece immediately
- lockPiece()
}
/**
@@ -264,12 +249,9 @@ class GameBoard(
}
/**
- * Lock the current piece in place
+ * Lock the current piece in place and check for completed lines
*/
- private fun lockPiece() {
- if (isPieceLocking) return // Prevent recursive locking
- isPieceLocking = true
-
+ fun lockPiece() {
val piece = currentPiece ?: return
// Add the piece to the grid
@@ -293,15 +275,11 @@ class GameBoard(
// Find and clear lines immediately
findAndClearLines()
- // Spawn new piece immediately
+ // Spawn new piece
spawnPiece()
// Allow holding piece again after locking
canHold = true
-
- // Reset both states after everything is done
- isPieceLocking = false
- isHardDropInProgress = false
}
/**
diff --git a/app/src/main/java/com/mintris/model/StatsManager.kt b/app/src/main/java/com/mintris/model/StatsManager.kt
deleted file mode 100644
index 3a3eae7..0000000
--- a/app/src/main/java/com/mintris/model/StatsManager.kt
+++ /dev/null
@@ -1,175 +0,0 @@
-package com.mintris.model
-
-import android.content.Context
-import android.content.SharedPreferences
-
-class StatsManager(context: Context) {
- private val prefs: SharedPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
-
- // Lifetime stats
- private var totalGames: Int = 0
- private var totalScore: Long = 0
- private var totalLines: Int = 0
- private var totalPieces: Int = 0
- private var totalTime: Long = 0
- private var maxLevel: Int = 0
- private var maxScore: Int = 0
- private var maxLines: Int = 0
-
- // Line clear stats (lifetime)
- private var totalSingles: Int = 0
- private var totalDoubles: Int = 0
- private var totalTriples: Int = 0
- private var totalTetrises: Int = 0
-
- // Session stats
- private var sessionScore: Int = 0
- private var sessionLines: Int = 0
- private var sessionPieces: Int = 0
- private var sessionTime: Long = 0
- private var sessionLevel: Int = 0
-
- // Line clear stats (session)
- private var sessionSingles: Int = 0
- private var sessionDoubles: Int = 0
- private var sessionTriples: Int = 0
- private var sessionTetrises: Int = 0
-
- init {
- loadStats()
- }
-
- private fun loadStats() {
- totalGames = prefs.getInt(KEY_TOTAL_GAMES, 0)
- totalScore = prefs.getLong(KEY_TOTAL_SCORE, 0)
- totalLines = prefs.getInt(KEY_TOTAL_LINES, 0)
- totalPieces = prefs.getInt(KEY_TOTAL_PIECES, 0)
- totalTime = prefs.getLong(KEY_TOTAL_TIME, 0)
- maxLevel = prefs.getInt(KEY_MAX_LEVEL, 0)
- maxScore = prefs.getInt(KEY_MAX_SCORE, 0)
- maxLines = prefs.getInt(KEY_MAX_LINES, 0)
-
- // Load line clear stats
- totalSingles = prefs.getInt(KEY_TOTAL_SINGLES, 0)
- totalDoubles = prefs.getInt(KEY_TOTAL_DOUBLES, 0)
- totalTriples = prefs.getInt(KEY_TOTAL_TRIPLES, 0)
- totalTetrises = prefs.getInt(KEY_TOTAL_TETRISES, 0)
- }
-
- private fun saveStats() {
- prefs.edit()
- .putInt(KEY_TOTAL_GAMES, totalGames)
- .putLong(KEY_TOTAL_SCORE, totalScore)
- .putInt(KEY_TOTAL_LINES, totalLines)
- .putInt(KEY_TOTAL_PIECES, totalPieces)
- .putLong(KEY_TOTAL_TIME, totalTime)
- .putInt(KEY_MAX_LEVEL, maxLevel)
- .putInt(KEY_MAX_SCORE, maxScore)
- .putInt(KEY_MAX_LINES, maxLines)
- .putInt(KEY_TOTAL_SINGLES, totalSingles)
- .putInt(KEY_TOTAL_DOUBLES, totalDoubles)
- .putInt(KEY_TOTAL_TRIPLES, totalTriples)
- .putInt(KEY_TOTAL_TETRISES, totalTetrises)
- .apply()
- }
-
- fun startNewSession() {
- sessionScore = 0
- sessionLines = 0
- sessionPieces = 0
- sessionTime = 0
- sessionLevel = 0
- sessionSingles = 0
- sessionDoubles = 0
- sessionTriples = 0
- sessionTetrises = 0
- }
-
- fun updateSessionStats(score: Int, lines: Int, pieces: Int, time: Long, level: Int) {
- sessionScore = score
- sessionLines = lines
- sessionPieces = pieces
- sessionTime = time
- sessionLevel = level
- }
-
- fun recordLineClear(lineCount: Int) {
- when (lineCount) {
- 1 -> {
- sessionSingles++
- totalSingles++
- }
- 2 -> {
- sessionDoubles++
- totalDoubles++
- }
- 3 -> {
- sessionTriples++
- totalTriples++
- }
- 4 -> {
- sessionTetrises++
- totalTetrises++
- }
- }
- }
-
- fun endSession() {
- totalGames++
- totalScore += sessionScore
- totalLines += sessionLines
- totalPieces += sessionPieces
- totalTime += sessionTime
-
- if (sessionLevel > maxLevel) maxLevel = sessionLevel
- if (sessionScore > maxScore) maxScore = sessionScore
- if (sessionLines > maxLines) maxLines = sessionLines
-
- saveStats()
- }
-
- // Getters for lifetime stats
- fun getTotalGames(): Int = totalGames
- fun getTotalScore(): Long = totalScore
- fun getTotalLines(): Int = totalLines
- fun getTotalPieces(): Int = totalPieces
- fun getTotalTime(): Long = totalTime
- fun getMaxLevel(): Int = maxLevel
- fun getMaxScore(): Int = maxScore
- fun getMaxLines(): Int = maxLines
-
- // Getters for line clear stats (lifetime)
- fun getTotalSingles(): Int = totalSingles
- fun getTotalDoubles(): Int = totalDoubles
- fun getTotalTriples(): Int = totalTriples
- fun getTotalTetrises(): Int = totalTetrises
-
- // Getters for session stats
- fun getSessionScore(): Int = sessionScore
- fun getSessionLines(): Int = sessionLines
- fun getSessionPieces(): Int = sessionPieces
- fun getSessionTime(): Long = sessionTime
- fun getSessionLevel(): Int = sessionLevel
-
- // Getters for line clear stats (session)
- fun getSessionSingles(): Int = sessionSingles
- fun getSessionDoubles(): Int = sessionDoubles
- fun getSessionTriples(): Int = sessionTriples
- fun getSessionTetrises(): Int = sessionTetrises
-
- companion object {
- private const val PREFS_NAME = "mintris_stats"
- private const val KEY_TOTAL_GAMES = "total_games"
- private const val KEY_TOTAL_SCORE = "total_score"
- private const val KEY_TOTAL_LINES = "total_lines"
- private const val KEY_TOTAL_PIECES = "total_pieces"
- private const val KEY_TOTAL_TIME = "total_time"
- private const val KEY_MAX_LEVEL = "max_level"
- private const val KEY_MAX_SCORE = "max_score"
- private const val KEY_MAX_LINES = "max_lines"
- private const val KEY_TOTAL_SINGLES = "total_singles"
- private const val KEY_TOTAL_DOUBLES = "total_doubles"
- private const val KEY_TOTAL_TRIPLES = "total_triples"
- private const val KEY_TOTAL_TETRISES = "total_tetrises"
- }
-}
\ 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 ab63a51..7271d89 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -135,92 +135,10 @@
android:textStyle="bold" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -291,16 +209,6 @@
android:text="@string/high_scores"
android:textColor="@color/white"
android:textSize="18sp" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 41c0fc2..871a7af 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -20,28 +20,4 @@
New High Score!
Save
Back
-
-
- Lifetime Stats
- Best Performance
- Total Games: %d
- Total Score: %d
- Total Lines: %d
- Total Pieces: %d
- Total Time: %s
- Max Level: %d
- Max Score: %d
- Max Lines: %d
- Stats
- Session Stats
- Score: %d
- Lines: %d
- Pieces: %d
- Time: %s
- Level: %d
- Line Clears
- Singles: %d
- Doubles: %d
- Triples: %d
- Tetrises: %d
\ No newline at end of file