mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-18 02: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
|
// Flag to track if high score screen will be shown
|
||||||
var showingHighScore = false
|
var showingHighScore = false
|
||||||
|
|
||||||
|
// Play game over sound and trigger animation
|
||||||
|
if (isSoundEnabled) {
|
||||||
|
gameMusic.playGameOver()
|
||||||
|
}
|
||||||
|
gameView.startGameOverAnimation()
|
||||||
|
|
||||||
// Show progression screen first with XP animation
|
// Show progression screen first with XP animation
|
||||||
showProgressionScreen(xpGained, newRewards)
|
showProgressionScreen(xpGained, newRewards)
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,14 @@ import com.mintris.R
|
||||||
|
|
||||||
class GameMusic(private val context: Context) {
|
class GameMusic(private val context: Context) {
|
||||||
private var mediaPlayer: MediaPlayer? = null
|
private var mediaPlayer: MediaPlayer? = null
|
||||||
|
private var gameOverPlayer: MediaPlayer? = null
|
||||||
private var isEnabled = true
|
private var isEnabled = true
|
||||||
private var isPrepared = false
|
private var isPrepared = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
setupMediaPlayer()
|
setupMediaPlayer()
|
||||||
|
setupGameOverPlayer()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("GameMusic", "Error initializing: ${e.message}")
|
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() {
|
fun start() {
|
||||||
if (isEnabled && mediaPlayer != null && isPrepared) {
|
if (isEnabled && mediaPlayer != null && isPrepared) {
|
||||||
try {
|
try {
|
||||||
|
@ -107,7 +152,9 @@ class GameMusic(private val context: Context) {
|
||||||
try {
|
try {
|
||||||
Log.d("GameMusic", "Releasing MediaPlayer")
|
Log.d("GameMusic", "Releasing MediaPlayer")
|
||||||
mediaPlayer?.release()
|
mediaPlayer?.release()
|
||||||
|
gameOverPlayer?.release()
|
||||||
mediaPlayer = null
|
mediaPlayer = null
|
||||||
|
gameOverPlayer = null
|
||||||
isPrepared = false
|
isPrepared = false
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("GameMusic", "Error releasing music: ${e.message}")
|
Log.e("GameMusic", "Error releasing music: ${e.message}")
|
||||||
|
|
|
@ -91,4 +91,26 @@ class GameHaptics(private val context: Context) {
|
||||||
vibrator.vibrate(vibrationEffect)
|
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 pulseAlpha = 0f
|
||||||
private var isPulsing = false
|
private var isPulsing = false
|
||||||
private var linesToPulse = mutableListOf<Int>() // Track which lines are being cleared
|
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 {
|
private val ghostPaint = Paint().apply {
|
||||||
style = Paint.Style.STROKE
|
style = Paint.Style.STROKE
|
||||||
|
@ -439,6 +442,18 @@ class GameView @JvmOverloads constructor(
|
||||||
// Draw active piece
|
// Draw active piece
|
||||||
drawActivePiece(canvas)
|
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)
|
super.setBackgroundColor(color)
|
||||||
invalidate()
|
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
|
currentPiece = nextPiece
|
||||||
spawnNextPiece()
|
spawnNextPiece()
|
||||||
|
|
||||||
// Center the piece horizontally
|
// Center the piece horizontally and spawn one unit higher
|
||||||
currentPiece?.apply {
|
currentPiece?.apply {
|
||||||
x = (width - getWidth()) / 2
|
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}")
|
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]) {
|
if (boardY >= 0 && grid[boardY][boardX]) {
|
||||||
return false
|
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