Add full gamepad support to all screens including pause menu, progression screen, high scores, and game over

This commit is contained in:
cmclark00 2025-03-31 08:01:47 -04:00
parent f4f40c4c34
commit 08c9f8a1ce
5 changed files with 107 additions and 11 deletions

View file

@ -12,6 +12,8 @@ import com.mintris.model.HighScore
import com.mintris.model.HighScoreManager
import com.mintris.model.PlayerProgressionManager
import android.graphics.Color
import android.view.KeyEvent
import android.view.InputDevice
class HighScoreEntryActivity : AppCompatActivity() {
private lateinit var binding: HighScoreEntryBinding
@ -39,6 +41,11 @@ class HighScoreEntryActivity : AppCompatActivity() {
binding.scoreText.text = "Score: $score"
binding.saveButton.setOnClickListener {
saveScore()
}
}
private fun saveScore() {
// Only allow saving once
if (!hasSaved) {
val name = binding.nameInput.text.toString().trim()
@ -53,6 +60,36 @@ class HighScoreEntryActivity : AppCompatActivity() {
}
}
}
// Override onKeyDown to handle gamepad buttons
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
// Check if it's a gamepad input
if (event != null && isGamepadDevice(event.device)) {
when (keyCode) {
KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_DPAD_CENTER -> {
// A button saves the score
saveScore()
return true
}
KeyEvent.KEYCODE_BUTTON_B -> {
// B button cancels
setResult(Activity.RESULT_CANCELED)
finish()
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
// Helper function to check if the device is a gamepad
private fun isGamepadDevice(device: InputDevice?): Boolean {
if (device == null) return false
val sources = device.sources
return (sources and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD ||
(sources and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
}
// Prevent accidental back button press from causing issues

View file

@ -12,6 +12,8 @@ import com.mintris.model.HighScoreManager
import com.mintris.model.PlayerProgressionManager
import android.graphics.Color
import android.util.Log
import android.view.KeyEvent
import android.view.InputDevice
class HighScoresActivity : AppCompatActivity() {
private lateinit var binding: HighScoresBinding
@ -113,4 +115,29 @@ class HighScoresActivity : AppCompatActivity() {
Log.e("HighScoresActivity", "Error in onResume", e)
}
}
// Handle gamepad buttons
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
// Check if it's a gamepad input
if (event != null && isGamepadDevice(event.device)) {
when (keyCode) {
KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BACK -> {
// B button or Back button returns to previous screen
finish()
return true
}
}
}
return super.onKeyDown(keyCode, event)
}
// Helper function to check if the device is a gamepad
private fun isGamepadDevice(device: InputDevice?): Boolean {
if (device == null) return false
val sources = device.sources
return (sources and InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD ||
(sources and InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
}
}

View file

@ -1143,6 +1143,12 @@ class MainActivity : AppCompatActivity(),
activateSelectedMenuItem()
} else if (titleScreen.visibility == View.VISIBLE) {
titleScreen.performClick()
} else if (progressionScreen.visibility == View.VISIBLE) {
// Handle continue in progression screen
progressionScreen.performContinue()
} else if (binding.gameOverContainer.visibility == View.VISIBLE) {
// Handle play again in game over screen
binding.playAgainButton.performClick()
}
}
}
@ -1159,6 +1165,20 @@ class MainActivity : AppCompatActivity(),
pauseMenuItems.add(binding.statsButton)
pauseMenuItems.add(binding.pauseLevelUpButton)
pauseMenuItems.add(binding.pauseLevelDownButton)
pauseMenuItems.add(binding.settingsButton)
pauseMenuItems.add(binding.musicToggle)
// Add theme selector if present
val themeSelector = binding.themeSelector
if (themeSelector.visibility == View.VISIBLE) {
pauseMenuItems.add(themeSelector)
}
// Add block skin selector if present
val blockSkinSelector = binding.blockSkinSelector
if (blockSkinSelector.visibility == View.VISIBLE) {
pauseMenuItems.add(blockSkinSelector)
}
}
/**

View file

@ -266,7 +266,7 @@ class GamepadController(
* @return true if the event was handled, false otherwise
*/
fun handleKeyEvent(keyCode: Int, event: KeyEvent): Boolean {
// Skip if game is not active
// Skip if game is not active but handle menu navigation
if (!gameView.isActive()) {
// Handle menu navigation even when game is not active
if (event.action == KeyEvent.ACTION_DOWN) {
@ -284,6 +284,11 @@ class GamepadController(
navigationListener?.onMenuSelect()
return true
}
KeyEvent.KEYCODE_BUTTON_B -> {
// B button can be used to go back/cancel
menuListener?.onPauseRequested()
return true
}
}
}

View file

@ -304,4 +304,11 @@ class ProgressionScreen @JvmOverloads constructor(
card?.setCardBackgroundColor(backgroundColor)
}
}
/**
* Public method to handle continue action via gamepad
*/
fun performContinue() {
continueButton.performClick()
}
}