mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-17 23:45:22 +01:00
Refactor: Introduce ViewModel for score/level, fix game over flow
This commit is contained in:
parent
5952cac760
commit
0a5bf6bb7e
5 changed files with 151 additions and 168 deletions
|
@ -19,7 +19,7 @@ android {
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ dependencies {
|
||||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
|
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
|
||||||
|
implementation "androidx.activity:activity-ktx:1.9.0"
|
||||||
implementation 'androidx.window:window:1.2.0' // For better display support
|
implementation 'androidx.window:window:1.2.0' // For better display support
|
||||||
implementation 'androidx.window:window-java:1.2.0'
|
implementation 'androidx.window:window-java:1.2.0'
|
||||||
implementation 'com.google.code.gson:gson:2.10.1'
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<!-- Add permission to handle system gestures if needed on some devices -->
|
<!-- Add permission to handle system gestures if needed on some devices -->
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
|
@ -10,6 +10,8 @@ import android.os.VibratorManager
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.HapticFeedbackConstants
|
import android.view.HapticFeedbackConstants
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.activity.viewModels // Added import
|
||||||
|
import androidx.lifecycle.Observer // Added import
|
||||||
import com.pixelmintdrop.databinding.ActivityMainBinding
|
import com.pixelmintdrop.databinding.ActivityMainBinding
|
||||||
import com.pixelmintdrop.game.GameHaptics
|
import com.pixelmintdrop.game.GameHaptics
|
||||||
import com.pixelmintdrop.game.GameView
|
import com.pixelmintdrop.game.GameView
|
||||||
|
@ -50,6 +52,9 @@ import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(),
|
class MainActivity : AppCompatActivity(),
|
||||||
GamepadController.GamepadConnectionListener,
|
GamepadController.GamepadConnectionListener,
|
||||||
|
@ -60,6 +65,9 @@ class MainActivity : AppCompatActivity(),
|
||||||
private const val TAG = "MainActivity"
|
private const val TAG = "MainActivity"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ViewModel
|
||||||
|
private val viewModel: MainActivityViewModel by viewModels() // Added ViewModel
|
||||||
|
|
||||||
// UI components
|
// UI components
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
private lateinit var gameView: GameView
|
private lateinit var gameView: GameView
|
||||||
|
@ -78,8 +86,6 @@ class MainActivity : AppCompatActivity(),
|
||||||
// Game state
|
// Game state
|
||||||
private var isSoundEnabled = true
|
private var isSoundEnabled = true
|
||||||
private var isMusicEnabled = true
|
private var isMusicEnabled = true
|
||||||
private var currentScore = 0L
|
|
||||||
private var currentLevel = 1
|
|
||||||
private var piecesPlaced = 0
|
private var piecesPlaced = 0
|
||||||
private var gameStartTime = 0L
|
private var gameStartTime = 0L
|
||||||
private var selectedLevel = 1
|
private var selectedLevel = 1
|
||||||
|
@ -215,6 +221,17 @@ class MainActivity : AppCompatActivity(),
|
||||||
blockSkinSelector = binding.customizationBlockSkinSelector!!
|
blockSkinSelector = binding.customizationBlockSkinSelector!!
|
||||||
pauseMenuScrollView = binding.pauseMenuScrollView
|
pauseMenuScrollView = binding.pauseMenuScrollView
|
||||||
|
|
||||||
|
// Observe ViewModel LiveData
|
||||||
|
viewModel.currentScore.observe(this, Observer { newScore ->
|
||||||
|
// Use actual ID from layout - display only the number
|
||||||
|
binding.scoreText.text = newScore.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.currentLevel.observe(this, Observer { newLevel ->
|
||||||
|
// Use actual ID from layout - display only the number
|
||||||
|
binding.currentLevelText.text = newLevel.toString()
|
||||||
|
})
|
||||||
|
|
||||||
// Load random mode setting
|
// Load random mode setting
|
||||||
isRandomModeEnabled = getSharedPreferences("com.com.pixelmintgames.pixelmintdrop.preferences", Context.MODE_PRIVATE)
|
isRandomModeEnabled = getSharedPreferences("com.com.pixelmintgames.pixelmintdrop.preferences", Context.MODE_PRIVATE)
|
||||||
.getBoolean("random_mode_enabled", false)
|
.getBoolean("random_mode_enabled", false)
|
||||||
|
@ -348,28 +365,17 @@ class MainActivity : AppCompatActivity(),
|
||||||
}
|
}
|
||||||
|
|
||||||
gameView.onGameOver = { finalScore ->
|
gameView.onGameOver = { finalScore ->
|
||||||
// Pause music on game over
|
// Start animation & pause music
|
||||||
|
gameView.startGameOverAnimation()
|
||||||
gameMusic.pause()
|
gameMusic.pause()
|
||||||
|
|
||||||
// Update high scores
|
// Calculate final stats, XP, and high score
|
||||||
val timePlayedMs = System.currentTimeMillis() - gameStartTime
|
val timePlayedMs = System.currentTimeMillis() - gameStartTime
|
||||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
statsManager.updateSessionStats(finalScore, gameBoard.lines, piecesPlaced, timePlayedMs, viewModel.currentLevel.value ?: 1)
|
||||||
val currentDate = dateFormat.format(Date())
|
|
||||||
|
|
||||||
// Track if this is a high score
|
|
||||||
val isHighScore = highScoreManager.isHighScore(finalScore)
|
|
||||||
|
|
||||||
// Show game over screen
|
|
||||||
showGameOver(finalScore)
|
|
||||||
|
|
||||||
// Save player stats to track game history
|
|
||||||
statsManager.updateSessionStats(finalScore, gameBoard.lines, piecesPlaced, timePlayedMs, currentLevel)
|
|
||||||
|
|
||||||
// Handle progression - XP earned, potential level up
|
|
||||||
val xpGained = progressionManager.calculateGameXP(
|
val xpGained = progressionManager.calculateGameXP(
|
||||||
score = finalScore,
|
score = finalScore,
|
||||||
linesCleared = gameBoard.lines,
|
linesCleared = gameBoard.lines,
|
||||||
level = currentLevel,
|
level = viewModel.currentLevel.value ?: 1,
|
||||||
gameTime = timePlayedMs,
|
gameTime = timePlayedMs,
|
||||||
tSpins = statsManager.getSessionTSpins(),
|
tSpins = statsManager.getSessionTSpins(),
|
||||||
combos = statsManager.getSessionMaxCombo(),
|
combos = statsManager.getSessionMaxCombo(),
|
||||||
|
@ -377,13 +383,22 @@ class MainActivity : AppCompatActivity(),
|
||||||
perfectClearCount = statsManager.getSessionPerfectClears()
|
perfectClearCount = statsManager.getSessionPerfectClears()
|
||||||
)
|
)
|
||||||
val newRewards = progressionManager.addXP(xpGained)
|
val newRewards = progressionManager.addXP(xpGained)
|
||||||
|
val newHighScore = highScoreManager.isHighScore(finalScore)
|
||||||
|
statsManager.endSession() // End session after calculations
|
||||||
|
|
||||||
// Show progression screen if player earned XP
|
Log.d(TAG, "Game Over. Score: $finalScore, Level: ${viewModel.currentLevel.value}, Lines: ${gameBoard.lines}, Start Level: $selectedLevel, New High Score: $newHighScore, XP Gained: $xpGained")
|
||||||
if (xpGained > 0) {
|
|
||||||
// Delay showing progression screen for a moment
|
// Show appropriate screen: Progression or Game Over directly
|
||||||
|
if (xpGained > 0 || newHighScore) {
|
||||||
|
// Delay showing progression slightly to let animation play
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
showProgressionScreen(xpGained, newRewards)
|
showProgressionScreen(xpGained, newRewards, newHighScore, finalScore)
|
||||||
}, 2000)
|
}, 1500) // Delay can be adjusted
|
||||||
|
} else {
|
||||||
|
// No XP, no high score -> show game over screen directly after animation
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
showGameOverScreenDirectly(finalScore)
|
||||||
|
}, 1500) // Delay to match progression path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,126 +530,53 @@ class MainActivity : AppCompatActivity(),
|
||||||
binding.linesText.text = lines.toString()
|
binding.linesText.text = lines.toString()
|
||||||
binding.comboText.text = gameBoard.getCombo().toString()
|
binding.comboText.text = gameBoard.getCombo().toString()
|
||||||
|
|
||||||
// Update current level for stats
|
|
||||||
currentLevel = level
|
|
||||||
|
|
||||||
// Force redraw of next piece preview
|
// Force redraw of next piece preview
|
||||||
binding.nextPieceView.invalidate()
|
binding.nextPieceView.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show game over screen
|
* Shows the final game over screen with stats.
|
||||||
*/
|
*/
|
||||||
private fun showGameOver(score: Int) {
|
private fun showGameOverScreenDirectly(score: Int) {
|
||||||
Log.d("MainActivity", "Showing game over screen with score: $score")
|
Log.d(TAG, "Showing final game over screen with score: $score")
|
||||||
val gameTime = System.currentTimeMillis() - gameStartTime
|
// Ensure game UI is hidden
|
||||||
|
|
||||||
// Hide all game UI elements
|
|
||||||
binding.gameControlsContainer.visibility = View.GONE
|
binding.gameControlsContainer.visibility = View.GONE
|
||||||
binding.holdPieceView.visibility = View.GONE
|
binding.holdPieceView.visibility = View.GONE
|
||||||
binding.nextPieceView.visibility = View.GONE
|
binding.nextPieceView.visibility = View.GONE
|
||||||
binding.pauseButton.visibility = View.GONE
|
binding.pauseButton.visibility = View.GONE
|
||||||
|
|
||||||
// Hide landscape panels if they exist
|
|
||||||
binding.leftControlsPanel?.visibility = View.GONE
|
binding.leftControlsPanel?.visibility = View.GONE
|
||||||
binding.rightControlsPanel?.visibility = View.GONE
|
binding.rightControlsPanel?.visibility = View.GONE
|
||||||
|
progressionScreen.visibility = View.GONE // Ensure progression is hidden
|
||||||
// Update session stats
|
|
||||||
statsManager.updateSessionStats(
|
// Update session stats display in the gameOverContainer
|
||||||
score = score,
|
|
||||||
lines = gameBoard.lines,
|
|
||||||
pieces = piecesPlaced,
|
|
||||||
time = gameTime,
|
|
||||||
level = currentLevel
|
|
||||||
)
|
|
||||||
|
|
||||||
// Calculate XP earned
|
|
||||||
val xpGained = progressionManager.calculateGameXP(
|
|
||||||
score = statsManager.getSessionScore(),
|
|
||||||
linesCleared = statsManager.getSessionLines(),
|
|
||||||
level = currentLevel,
|
|
||||||
gameTime = gameTime,
|
|
||||||
tSpins = statsManager.getSessionTSpins(),
|
|
||||||
combos = statsManager.getSessionMaxCombo(),
|
|
||||||
quadCount = statsManager.getSessionQuads(),
|
|
||||||
perfectClearCount = statsManager.getSessionPerfectClears()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add XP and check for rewards
|
|
||||||
val newRewards = progressionManager.addXP(xpGained)
|
|
||||||
|
|
||||||
// End session and save stats
|
|
||||||
statsManager.endSession()
|
|
||||||
|
|
||||||
// Update session stats display
|
|
||||||
val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
||||||
timeFormat.timeZone = TimeZone.getTimeZone("UTC")
|
timeFormat.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
val gameTime = System.currentTimeMillis() - gameStartTime // Recalculate or pass from onGameOver?
|
||||||
|
// Let's recalculate for simplicity here.
|
||||||
|
|
||||||
binding.sessionScoreText.text = getString(R.string.session_score, score)
|
binding.sessionScoreText.text = getString(R.string.session_score, score)
|
||||||
binding.sessionLinesText.text = getString(R.string.session_lines, gameBoard.lines)
|
binding.sessionLinesText.text = getString(R.string.session_lines, gameBoard.lines)
|
||||||
binding.sessionPiecesText.text = getString(R.string.session_pieces, piecesPlaced)
|
binding.sessionPiecesText.text = getString(R.string.session_pieces, piecesPlaced)
|
||||||
binding.sessionTimeText.text = getString(R.string.session_time, timeFormat.format(gameTime))
|
binding.sessionTimeText.text = getString(R.string.session_time, timeFormat.format(gameTime))
|
||||||
binding.sessionLevelText.text = getString(R.string.session_level, currentLevel)
|
binding.sessionLevelText.text = getString(R.string.session_level, viewModel.currentLevel.value ?: 1)
|
||||||
|
|
||||||
// Update session line clear stats
|
|
||||||
binding.sessionSinglesText.text = getString(R.string.singles, statsManager.getSessionSingles())
|
binding.sessionSinglesText.text = getString(R.string.singles, statsManager.getSessionSingles())
|
||||||
binding.sessionDoublesText.text = getString(R.string.doubles, statsManager.getSessionDoubles())
|
binding.sessionDoublesText.text = getString(R.string.doubles, statsManager.getSessionDoubles())
|
||||||
binding.sessionTriplesText.text = getString(R.string.triples, statsManager.getSessionTriples())
|
binding.sessionTriplesText.text = getString(R.string.triples, statsManager.getSessionTriples())
|
||||||
binding.sessionQuadsText.text = getString(R.string.quads, statsManager.getSessionQuads())
|
binding.sessionQuadsText.text = getString(R.string.quads, statsManager.getSessionQuads())
|
||||||
|
|
||||||
// Flag to track if high score screen will be shown
|
// Make the container visible
|
||||||
var showingHighScore = false
|
binding.gameOverContainer.visibility = View.VISIBLE
|
||||||
|
|
||||||
// Play game over sound and trigger animation
|
// Play game over sound if not already played by progression
|
||||||
if (isSoundEnabled) {
|
if (isSoundEnabled && progressionScreen.visibility != View.VISIBLE) {
|
||||||
gameMusic.playGameOver()
|
gameMusic.playGameOver()
|
||||||
}
|
}
|
||||||
|
|
||||||
// First trigger the animation in the game view
|
// Vibrate if not already vibrated by progression
|
||||||
Log.d("MainActivity", "Triggering game over animation")
|
if (progressionScreen.visibility != View.VISIBLE) {
|
||||||
gameView.startGameOverAnimation()
|
vibrate(VibrationEffect.EFFECT_DOUBLE_CLICK)
|
||||||
|
}
|
||||||
// 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
|
|
||||||
|
|
||||||
// Keep all game UI elements hidden
|
|
||||||
binding.gameControlsContainer.visibility = View.GONE
|
|
||||||
binding.holdPieceView.visibility = View.GONE
|
|
||||||
binding.nextPieceView.visibility = View.GONE
|
|
||||||
binding.pauseButton.visibility = View.GONE
|
|
||||||
binding.leftControlsPanel?.visibility = View.GONE
|
|
||||||
binding.rightControlsPanel?.visibility = View.GONE
|
|
||||||
|
|
||||||
// Get all themes with "Theme" in their name
|
|
||||||
val themeRewards = progressionManager.getUnlockedThemes().filter {
|
|
||||||
it.contains("Theme", ignoreCase = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update theme selector if new themes were unlocked
|
|
||||||
if (themeRewards.isNotEmpty()) {
|
|
||||||
updateThemeSelector()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 2000) // Increased from 1000ms (1 second) to 2000ms (2 seconds)
|
|
||||||
|
|
||||||
// Vibrate to indicate game over
|
|
||||||
vibrate(VibrationEffect.EFFECT_DOUBLE_CLICK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -643,7 +585,7 @@ class MainActivity : AppCompatActivity(),
|
||||||
private fun showHighScoreEntry(score: Int) {
|
private fun showHighScoreEntry(score: Int) {
|
||||||
val intent = Intent(this, HighScoreEntryActivity::class.java).apply {
|
val intent = Intent(this, HighScoreEntryActivity::class.java).apply {
|
||||||
putExtra("score", score)
|
putExtra("score", score)
|
||||||
putExtra("level", currentLevel)
|
putExtra("level", viewModel.currentLevel.value ?: 1) // Read from ViewModel
|
||||||
}
|
}
|
||||||
// Use the launcher instead of startActivity
|
// Use the launcher instead of startActivity
|
||||||
highScoreEntryLauncher.launch(intent)
|
highScoreEntryLauncher.launch(intent)
|
||||||
|
@ -930,30 +872,23 @@ class MainActivity : AppCompatActivity(),
|
||||||
* Start a new game
|
* Start a new game
|
||||||
*/
|
*/
|
||||||
private fun startGame() {
|
private fun startGame() {
|
||||||
// Reset pieces placed counter
|
Log.d(TAG, "Starting game at level $selectedLevel")
|
||||||
|
// Reset game state
|
||||||
|
viewModel.resetGame() // Resets score and level in ViewModel
|
||||||
|
viewModel.setLevel(selectedLevel) // Set initial level from selection
|
||||||
piecesPlaced = 0
|
piecesPlaced = 0
|
||||||
|
|
||||||
// Set initial game state
|
|
||||||
currentScore = 0
|
|
||||||
currentLevel = selectedLevel
|
|
||||||
lastLines = 0 // Reset lastLines to 0
|
|
||||||
lastLinesGroup = 0 // Reset lastLinesGroup to 0
|
|
||||||
lastRandomLevel = 0 // Reset lastRandomLevel to 0
|
|
||||||
gameStartTime = System.currentTimeMillis()
|
gameStartTime = System.currentTimeMillis()
|
||||||
|
lastLines = 0
|
||||||
// Update UI to show initial values
|
lastLinesGroup = 0
|
||||||
binding.scoreText.text = "$currentScore"
|
lastRandomLevel = 0
|
||||||
binding.currentLevelText.text = "$currentLevel"
|
// Observers will update scoreText and currentLevelText
|
||||||
binding.linesText.text = "0"
|
|
||||||
binding.comboText.text = "0"
|
|
||||||
|
|
||||||
// Reset game view and game board
|
// Reset game view and game board
|
||||||
gameBoard.reset()
|
gameBoard.reset()
|
||||||
gameView.reset()
|
gameView.reset()
|
||||||
|
|
||||||
// Ensure block skin is properly set (helps with random mode)
|
// Ensure block skin is properly set
|
||||||
val selectedSkin = progressionManager.getSelectedBlockSkin()
|
val selectedSkin = progressionManager.getSelectedBlockSkin()
|
||||||
Log.d("RandomMode", "Game start: Setting block skin to $selectedSkin")
|
|
||||||
gameView.setBlockSkin(selectedSkin)
|
gameView.setBlockSkin(selectedSkin)
|
||||||
|
|
||||||
// Update selectors to refresh UI state
|
// Update selectors to refresh UI state
|
||||||
|
@ -962,9 +897,9 @@ class MainActivity : AppCompatActivity(),
|
||||||
selectedSkin,
|
selectedSkin,
|
||||||
progressionManager.getPlayerLevel()
|
progressionManager.getPlayerLevel()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Show game elements
|
// Ensure game UI elements are visible and others hidden
|
||||||
gameView.visibility = View.VISIBLE
|
binding.gameView.visibility = View.VISIBLE
|
||||||
binding.gameControlsContainer.visibility = View.VISIBLE
|
binding.gameControlsContainer.visibility = View.VISIBLE
|
||||||
binding.holdPieceView.visibility = View.VISIBLE
|
binding.holdPieceView.visibility = View.VISIBLE
|
||||||
binding.nextPieceView.visibility = View.VISIBLE
|
binding.nextPieceView.visibility = View.VISIBLE
|
||||||
|
@ -974,7 +909,7 @@ class MainActivity : AppCompatActivity(),
|
||||||
titleScreen.visibility = View.GONE
|
titleScreen.visibility = View.GONE
|
||||||
progressionScreen.visibility = View.GONE
|
progressionScreen.visibility = View.GONE
|
||||||
|
|
||||||
// Show game UI elements in landscape mode
|
// Show landscape specific controls if needed
|
||||||
if (resources.configuration.orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE) {
|
if (resources.configuration.orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
binding.leftControlsPanel?.visibility = View.VISIBLE
|
binding.leftControlsPanel?.visibility = View.VISIBLE
|
||||||
binding.rightControlsPanel?.visibility = View.VISIBLE
|
binding.rightControlsPanel?.visibility = View.VISIBLE
|
||||||
|
@ -982,32 +917,22 @@ class MainActivity : AppCompatActivity(),
|
||||||
|
|
||||||
// Configure callbacks
|
// Configure callbacks
|
||||||
gameView.onGameStateChanged = { score, level, lines ->
|
gameView.onGameStateChanged = { score, level, lines ->
|
||||||
updateGameStateUI(score, level, lines)
|
// We'll adapt updateGameStateUI later to use ViewModel
|
||||||
|
updateGameStateUI(score, level, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
gameView.onGameOver = { finalScore ->
|
gameView.onGameOver = { finalScore ->
|
||||||
// Pause music on game over
|
// Start animation & pause music
|
||||||
|
gameView.startGameOverAnimation()
|
||||||
gameMusic.pause()
|
gameMusic.pause()
|
||||||
|
|
||||||
// Update high scores
|
// Calculate final stats, XP, and high score
|
||||||
val timePlayedMs = System.currentTimeMillis() - gameStartTime
|
val timePlayedMs = System.currentTimeMillis() - gameStartTime
|
||||||
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
statsManager.updateSessionStats(finalScore, gameBoard.lines, piecesPlaced, timePlayedMs, viewModel.currentLevel.value ?: 1)
|
||||||
val currentDate = dateFormat.format(Date())
|
|
||||||
|
|
||||||
// Track if this is a high score
|
|
||||||
val isHighScore = highScoreManager.isHighScore(finalScore)
|
|
||||||
|
|
||||||
// Show game over screen
|
|
||||||
showGameOver(finalScore)
|
|
||||||
|
|
||||||
// Save player stats to track game history
|
|
||||||
statsManager.updateSessionStats(finalScore, gameBoard.lines, piecesPlaced, timePlayedMs, currentLevel)
|
|
||||||
|
|
||||||
// Handle progression - XP earned, potential level up
|
|
||||||
val xpGained = progressionManager.calculateGameXP(
|
val xpGained = progressionManager.calculateGameXP(
|
||||||
score = finalScore,
|
score = finalScore,
|
||||||
linesCleared = gameBoard.lines,
|
linesCleared = gameBoard.lines,
|
||||||
level = currentLevel,
|
level = viewModel.currentLevel.value ?: 1,
|
||||||
gameTime = timePlayedMs,
|
gameTime = timePlayedMs,
|
||||||
tSpins = statsManager.getSessionTSpins(),
|
tSpins = statsManager.getSessionTSpins(),
|
||||||
combos = statsManager.getSessionMaxCombo(),
|
combos = statsManager.getSessionMaxCombo(),
|
||||||
|
@ -1015,13 +940,22 @@ class MainActivity : AppCompatActivity(),
|
||||||
perfectClearCount = statsManager.getSessionPerfectClears()
|
perfectClearCount = statsManager.getSessionPerfectClears()
|
||||||
)
|
)
|
||||||
val newRewards = progressionManager.addXP(xpGained)
|
val newRewards = progressionManager.addXP(xpGained)
|
||||||
|
val newHighScore = highScoreManager.isHighScore(finalScore)
|
||||||
|
statsManager.endSession() // End session after calculations
|
||||||
|
|
||||||
// Show progression screen if player earned XP
|
Log.d(TAG, "Game Over. Score: $finalScore, Level: ${viewModel.currentLevel.value}, Lines: ${gameBoard.lines}, Start Level: $selectedLevel, New High Score: $newHighScore, XP Gained: $xpGained")
|
||||||
if (xpGained > 0) {
|
|
||||||
// Delay showing progression screen for a moment
|
// Show appropriate screen: Progression or Game Over directly
|
||||||
|
if (xpGained > 0 || newHighScore) {
|
||||||
|
// Delay showing progression slightly to let animation play
|
||||||
Handler(Looper.getMainLooper()).postDelayed({
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
showProgressionScreen(xpGained, newRewards)
|
showProgressionScreen(xpGained, newRewards, newHighScore, finalScore)
|
||||||
}, 2000)
|
}, 1500) // Delay can be adjusted
|
||||||
|
} else {
|
||||||
|
// No XP, no high score -> show game over screen directly after animation
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
showGameOverScreenDirectly(finalScore)
|
||||||
|
}, 1500) // Delay to match progression path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1423,11 +1357,11 @@ class MainActivity : AppCompatActivity(),
|
||||||
return super.onGenericMotionEvent(event)
|
return super.onGenericMotionEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showProgressionScreen(xpGained: Long, newRewards: List<String>) {
|
private fun showProgressionScreen(xpGained: Long, newRewards: List<String>, isNewHighScore: Boolean, finalScore: Int) {
|
||||||
// Apply theme before showing the screen
|
// Apply theme before showing the screen
|
||||||
progressionScreen.applyTheme(currentTheme)
|
progressionScreen.applyTheme(currentTheme)
|
||||||
|
|
||||||
// Hide all game UI elements
|
// Hide game/other UI elements
|
||||||
binding.gameControlsContainer.visibility = View.GONE
|
binding.gameControlsContainer.visibility = View.GONE
|
||||||
binding.holdPieceView.visibility = View.GONE
|
binding.holdPieceView.visibility = View.GONE
|
||||||
binding.nextPieceView.visibility = View.GONE
|
binding.nextPieceView.visibility = View.GONE
|
||||||
|
@ -1443,6 +1377,16 @@ class MainActivity : AppCompatActivity(),
|
||||||
|
|
||||||
// Display progression data
|
// Display progression data
|
||||||
progressionScreen.showProgress(progressionManager, xpGained, newRewards, currentTheme)
|
progressionScreen.showProgress(progressionManager, xpGained, newRewards, currentTheme)
|
||||||
|
|
||||||
|
// Set up the continue action
|
||||||
|
progressionScreen.onContinue = {
|
||||||
|
if (isNewHighScore) {
|
||||||
|
showHighScoreEntry(finalScore)
|
||||||
|
} else {
|
||||||
|
// No high score, just show the final game over screen
|
||||||
|
showGameOverScreenDirectly(finalScore)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2045,11 +1989,10 @@ class MainActivity : AppCompatActivity(),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateGameStateUI(score: Int, level: Int, lines: Int) {
|
private fun updateGameStateUI(score: Int, level: Int, lines: Int) {
|
||||||
currentScore = score.toLong()
|
viewModel.setScore(score.toLong()) // Use ViewModel setter
|
||||||
currentLevel = level
|
viewModel.setLevel(level) // Use ViewModel setter
|
||||||
|
|
||||||
binding.scoreText.text = "$score"
|
// Update other UI elements not handled by score/level observers
|
||||||
binding.currentLevelText.text = "$level"
|
|
||||||
binding.linesText.text = "$lines"
|
binding.linesText.text = "$lines"
|
||||||
binding.comboText.text = gameBoard.getCombo().toString()
|
binding.comboText.text = gameBoard.getCombo().toString()
|
||||||
|
|
||||||
|
|
40
app/src/main/java/com/pixelmintdrop/MainActivityViewModel.kt
Normal file
40
app/src/main/java/com/pixelmintdrop/MainActivityViewModel.kt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package com.pixelmintdrop
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class MainActivityViewModel : ViewModel() {
|
||||||
|
|
||||||
|
// Private MutableLiveData for internal updates
|
||||||
|
private val _currentScore = MutableLiveData<Long>(0L)
|
||||||
|
private val _currentLevel = MutableLiveData<Int>(1)
|
||||||
|
|
||||||
|
// Public LiveData for observation by the Activity
|
||||||
|
val currentScore: LiveData<Long> = _currentScore
|
||||||
|
val currentLevel: LiveData<Int> = _currentLevel
|
||||||
|
|
||||||
|
// Example function to update the score (logic would be moved here)
|
||||||
|
fun incrementScore(points: Long) {
|
||||||
|
_currentScore.value = (_currentScore.value ?: 0L) + points
|
||||||
|
// Potentially add logic here to check for level up based on score
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to set the score directly
|
||||||
|
fun setScore(score: Long) {
|
||||||
|
_currentScore.value = score
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example function to update the level
|
||||||
|
fun setLevel(level: Int) {
|
||||||
|
_currentLevel.value = level
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetGame() {
|
||||||
|
_currentScore.value = 0L
|
||||||
|
_currentLevel.value = 1
|
||||||
|
// Reset other game state within the ViewModel as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add other state variables and logic related to game state here
|
||||||
|
}
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue