mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-18 00:45:20 +01:00
Enhanced game over experience: Added louder game over sound, improved game over animation, and added haptic feedback
This commit is contained in:
parent
ce19427cca
commit
292ea656f8
6 changed files with 134 additions and 2 deletions
|
@ -366,6 +366,12 @@ class MainActivity : AppCompatActivity() {
|
|||
// Flag to track if high score screen will be shown
|
||||
var showingHighScore = false
|
||||
|
||||
// Play game over sound and trigger animation
|
||||
if (isSoundEnabled) {
|
||||
gameMusic.playGameOver()
|
||||
}
|
||||
gameView.startGameOverAnimation()
|
||||
|
||||
// Show progression screen first with XP animation
|
||||
showProgressionScreen(xpGained, newRewards)
|
||||
|
||||
|
|
|
@ -9,12 +9,14 @@ import com.mintris.R
|
|||
|
||||
class GameMusic(private val context: Context) {
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
private var gameOverPlayer: MediaPlayer? = null
|
||||
private var isEnabled = true
|
||||
private var isPrepared = false
|
||||
|
||||
init {
|
||||
try {
|
||||
setupMediaPlayer()
|
||||
setupGameOverPlayer()
|
||||
} catch (e: Exception) {
|
||||
Log.e("GameMusic", "Error initializing: ${e.message}")
|
||||
}
|
||||
|
@ -46,6 +48,49 @@ class GameMusic(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupGameOverPlayer() {
|
||||
try {
|
||||
Log.d("GameMusic", "Setting up GameOver MediaPlayer")
|
||||
gameOverPlayer = MediaPlayer.create(context, R.raw.game_over).apply {
|
||||
setVolume(1.0f, 1.0f) // Increased from 0.7f to 1.0f for maximum volume
|
||||
|
||||
// Set audio attributes for better performance
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_GAME)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
Log.d("GameMusic", "GameOver MediaPlayer setup complete")
|
||||
} catch (e: Exception) {
|
||||
Log.e("GameMusic", "Error setting up GameOver MediaPlayer", e)
|
||||
gameOverPlayer = null
|
||||
}
|
||||
}
|
||||
|
||||
fun playGameOver() {
|
||||
if (isEnabled && gameOverPlayer != null) {
|
||||
try {
|
||||
Log.d("GameMusic", "Playing game over sound")
|
||||
// Temporarily lower background music volume
|
||||
mediaPlayer?.setVolume(0.2f, 0.2f)
|
||||
|
||||
// Play game over sound
|
||||
gameOverPlayer?.start()
|
||||
|
||||
// Restore background music volume after a delay
|
||||
gameOverPlayer?.setOnCompletionListener {
|
||||
mediaPlayer?.setVolume(0.5f, 0.5f)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("GameMusic", "Error playing game over sound: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun start() {
|
||||
if (isEnabled && mediaPlayer != null && isPrepared) {
|
||||
try {
|
||||
|
@ -107,7 +152,9 @@ class GameMusic(private val context: Context) {
|
|||
try {
|
||||
Log.d("GameMusic", "Releasing MediaPlayer")
|
||||
mediaPlayer?.release()
|
||||
gameOverPlayer?.release()
|
||||
mediaPlayer = null
|
||||
gameOverPlayer = null
|
||||
isPrepared = false
|
||||
} catch (e: Exception) {
|
||||
Log.e("GameMusic", "Error releasing music: ${e.message}")
|
||||
|
|
|
@ -91,4 +91,26 @@ class GameHaptics(private val context: Context) {
|
|||
vibrator.vibrate(vibrationEffect)
|
||||
}
|
||||
}
|
||||
|
||||
fun vibrateForGameOver() {
|
||||
Log.d(TAG, "Attempting to vibrate for game over")
|
||||
|
||||
// Only proceed if the device has a vibrator and it's available
|
||||
if (!vibrator.hasVibrator()) return
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// Create a strong, long vibration effect
|
||||
val vibrationEffect = VibrationEffect.createOneShot(300L, VibrationEffect.DEFAULT_AMPLITUDE)
|
||||
vibrator.vibrate(vibrationEffect)
|
||||
Log.d(TAG, "Game over vibration triggered successfully")
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(300L)
|
||||
Log.w(TAG, "Device does not support vibration effects (Android < 8.0)")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error triggering game over vibration", e)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -178,6 +178,9 @@ class GameView @JvmOverloads constructor(
|
|||
private var pulseAlpha = 0f
|
||||
private var isPulsing = false
|
||||
private var linesToPulse = mutableListOf<Int>() // Track which lines are being cleared
|
||||
private var gameOverAnimator: ValueAnimator? = null
|
||||
private var gameOverAlpha = 0f
|
||||
private var isGameOverAnimating = false
|
||||
|
||||
private val ghostPaint = Paint().apply {
|
||||
style = Paint.Style.STROKE
|
||||
|
@ -439,6 +442,18 @@ class GameView @JvmOverloads constructor(
|
|||
// Draw active piece
|
||||
drawActivePiece(canvas)
|
||||
}
|
||||
|
||||
// Draw game over effect if animating
|
||||
if (isGameOverAnimating) {
|
||||
val gameOverPaint = Paint().apply {
|
||||
color = Color.WHITE
|
||||
alpha = (128 * gameOverAlpha).toInt()
|
||||
isAntiAlias = true
|
||||
style = Paint.Style.FILL
|
||||
maskFilter = BlurMaskFilter(48f * gameOverAlpha, BlurMaskFilter.Blur.OUTER)
|
||||
}
|
||||
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gameOverPaint)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1133,4 +1148,41 @@ class GameView @JvmOverloads constructor(
|
|||
super.setBackgroundColor(color)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the game over animation
|
||||
*/
|
||||
fun startGameOverAnimation() {
|
||||
Log.d(TAG, "Starting game over animation")
|
||||
|
||||
// Cancel any existing animations
|
||||
pulseAnimator?.cancel()
|
||||
gameOverAnimator?.cancel()
|
||||
|
||||
// Trigger haptic feedback
|
||||
gameHaptics?.vibrateForGameOver()
|
||||
|
||||
// Create new game over animation
|
||||
gameOverAnimator = ValueAnimator.ofFloat(0f, 1f, 0.7f).apply {
|
||||
duration = 1500L // 1.5 seconds total
|
||||
interpolator = LinearInterpolator()
|
||||
|
||||
addUpdateListener { animation ->
|
||||
gameOverAlpha = animation.animatedValue as Float
|
||||
isGameOverAnimating = true
|
||||
invalidate()
|
||||
Log.d(TAG, "Game over animation update: alpha = $gameOverAlpha")
|
||||
}
|
||||
|
||||
addListener(object : android.animation.AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: android.animation.Animator) {
|
||||
isGameOverAnimating = false
|
||||
gameOverAlpha = 0.7f // Keep at 70% opacity
|
||||
invalidate()
|
||||
Log.d(TAG, "Game over animation ended")
|
||||
}
|
||||
})
|
||||
}
|
||||
gameOverAnimator?.start()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,10 +136,10 @@ class GameBoard(
|
|||
currentPiece = nextPiece
|
||||
spawnNextPiece()
|
||||
|
||||
// Center the piece horizontally
|
||||
// Center the piece horizontally and spawn one unit higher
|
||||
currentPiece?.apply {
|
||||
x = (width - getWidth()) / 2
|
||||
y = 0
|
||||
y = -1 // Spawn one unit above the top of the screen
|
||||
|
||||
Log.d(TAG, "spawnPiece() - new piece spawned at position (${x},${y}), type=${type}")
|
||||
|
||||
|
@ -326,6 +326,11 @@ class GameBoard(
|
|||
if (boardY >= 0 && grid[boardY][boardX]) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the position is more than one unit above the top of the screen
|
||||
if (boardY < -1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
BIN
app/src/main/res/raw/game_over.mp3
Normal file
BIN
app/src/main/res/raw/game_over.mp3
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue