mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-18 02:55:19 +01:00
Implemented continuous D-pad movement and Start button pause menu functionality
This commit is contained in:
parent
0ac25eb3a9
commit
36559eac4c
2 changed files with 107 additions and 8 deletions
|
@ -39,7 +39,9 @@ import android.content.BroadcastReceiver
|
|||
import android.content.IntentFilter
|
||||
import android.app.AlertDialog
|
||||
|
||||
class MainActivity : AppCompatActivity(), GamepadController.GamepadConnectionListener {
|
||||
class MainActivity : AppCompatActivity(),
|
||||
GamepadController.GamepadConnectionListener,
|
||||
GamepadController.GamepadMenuListener {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MainActivity"
|
||||
|
@ -121,6 +123,7 @@ class MainActivity : AppCompatActivity(), GamepadController.GamepadConnectionLis
|
|||
// Initialize gamepad controller
|
||||
gamepadController = GamepadController(gameView)
|
||||
gamepadController.setGamepadConnectionListener(this)
|
||||
gamepadController.setGamepadMenuListener(this)
|
||||
|
||||
// Set up touch event forwarding
|
||||
binding.touchInterceptor?.setOnTouchListener { _, event ->
|
||||
|
@ -1067,4 +1070,23 @@ class MainActivity : AppCompatActivity(), GamepadController.GamepadConnectionLis
|
|||
// Display progression data
|
||||
progressionScreen.showProgress(progressionManager, xpGained, newRewards, currentTheme)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements GamepadMenuListener to handle start button press
|
||||
*/
|
||||
override fun onPauseRequested() {
|
||||
runOnUiThread {
|
||||
if (gameView.visibility == View.VISIBLE && !gameView.isPaused && !gameView.isGameOver()) {
|
||||
gameView.pause()
|
||||
gameMusic.pause()
|
||||
showPauseMenu()
|
||||
binding.pauseStartButton.visibility = View.GONE
|
||||
binding.resumeButton.visibility = View.VISIBLE
|
||||
} else if (binding.pauseContainer.visibility == View.VISIBLE) {
|
||||
// If pause menu is showing, handle as a resume
|
||||
hidePauseMenu()
|
||||
resumeGame()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ import android.os.Build
|
|||
import android.os.VibrationEffect
|
||||
import android.view.InputDevice.MotionRange
|
||||
import android.os.Vibrator
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
|
||||
/**
|
||||
* GamepadController handles gamepad input for the Mintris game.
|
||||
|
@ -34,6 +36,9 @@ class GamepadController(
|
|||
private const val HARD_DROP_COOLDOWN_MS = 200L
|
||||
private const val HOLD_COOLDOWN_MS = 250L
|
||||
|
||||
// Continuous movement repeat delay
|
||||
private const val CONTINUOUS_MOVEMENT_DELAY_MS = 80L
|
||||
|
||||
// Rumble patterns
|
||||
private const val RUMBLE_MOVE_DURATION_MS = 20L
|
||||
private const val RUMBLE_ROTATE_DURATION_MS = 30L
|
||||
|
@ -102,14 +107,51 @@ class GamepadController(
|
|||
private var isMovingRight = false
|
||||
private var isMovingDown = false
|
||||
|
||||
// Handler for continuous movement
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val moveLeftRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (isMovingLeft && gameView.isActive()) {
|
||||
gameView.moveLeft()
|
||||
vibrateForPieceMove()
|
||||
handler.postDelayed(this, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val moveRightRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (isMovingRight && gameView.isActive()) {
|
||||
gameView.moveRight()
|
||||
vibrateForPieceMove()
|
||||
handler.postDelayed(this, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val moveDownRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (isMovingDown && gameView.isActive()) {
|
||||
gameView.softDrop()
|
||||
vibrateForPieceMove()
|
||||
handler.postDelayed(this, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callback interfaces
|
||||
interface GamepadConnectionListener {
|
||||
fun onGamepadConnected(gamepadName: String)
|
||||
fun onGamepadDisconnected(gamepadName: String)
|
||||
}
|
||||
|
||||
// Listener for gamepad connection
|
||||
interface GamepadMenuListener {
|
||||
fun onPauseRequested()
|
||||
}
|
||||
|
||||
// Listeners
|
||||
private var connectionListener: GamepadConnectionListener? = null
|
||||
private var menuListener: GamepadMenuListener? = null
|
||||
|
||||
// Currently active gamepad for rumble
|
||||
private var activeGamepad: InputDevice? = null
|
||||
|
@ -121,6 +163,13 @@ class GamepadController(
|
|||
connectionListener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a listener for gamepad menu events (pause/start button)
|
||||
*/
|
||||
fun setGamepadMenuListener(listener: GamepadMenuListener) {
|
||||
menuListener = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check for newly connected gamepads.
|
||||
* Call this periodically from the activity to detect connection changes.
|
||||
|
@ -219,29 +268,35 @@ class GamepadController(
|
|||
when (keyCode) {
|
||||
// D-pad and analog movement
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
if (!isMovingLeft && currentTime - lastMoveTime > MOVE_COOLDOWN_MS) {
|
||||
if (!isMovingLeft) {
|
||||
gameView.moveLeft()
|
||||
vibrateForPieceMove()
|
||||
lastMoveTime = currentTime
|
||||
isMovingLeft = true
|
||||
// Start continuous movement after initial input
|
||||
handler.postDelayed(moveLeftRunnable, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
return true
|
||||
}
|
||||
}
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
if (!isMovingRight && currentTime - lastMoveTime > MOVE_COOLDOWN_MS) {
|
||||
if (!isMovingRight) {
|
||||
gameView.moveRight()
|
||||
vibrateForPieceMove()
|
||||
lastMoveTime = currentTime
|
||||
isMovingRight = true
|
||||
// Start continuous movement after initial input
|
||||
handler.postDelayed(moveRightRunnable, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
return true
|
||||
}
|
||||
}
|
||||
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
||||
if (!isMovingDown && currentTime - lastMoveTime > MOVE_COOLDOWN_MS) {
|
||||
if (!isMovingDown) {
|
||||
gameView.softDrop()
|
||||
vibrateForPieceMove()
|
||||
lastMoveTime = currentTime
|
||||
isMovingDown = true
|
||||
// Start continuous movement after initial input
|
||||
handler.postDelayed(moveDownRunnable, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -253,6 +308,11 @@ class GamepadController(
|
|||
return true
|
||||
}
|
||||
}
|
||||
// Start button (pause)
|
||||
KeyEvent.KEYCODE_BUTTON_START -> {
|
||||
menuListener?.onPauseRequested()
|
||||
return true
|
||||
}
|
||||
// Rotation buttons - supporting multiple buttons for different controllers
|
||||
KeyEvent.KEYCODE_BUTTON_A,
|
||||
KeyEvent.KEYCODE_BUTTON_X,
|
||||
|
@ -281,14 +341,17 @@ class GamepadController(
|
|||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
||||
isMovingLeft = false
|
||||
handler.removeCallbacks(moveLeftRunnable)
|
||||
return true
|
||||
}
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
||||
isMovingRight = false
|
||||
handler.removeCallbacks(moveRightRunnable)
|
||||
return true
|
||||
}
|
||||
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
||||
isMovingDown = false
|
||||
handler.removeCallbacks(moveDownRunnable)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -320,38 +383,52 @@ class GamepadController(
|
|||
|
||||
// Apply deadzone
|
||||
if (Math.abs(axisX) > STICK_DEADZONE) {
|
||||
if (axisX > 0 && !isMovingRight && currentTime - lastMoveTime > MOVE_COOLDOWN_MS) {
|
||||
if (axisX > 0 && !isMovingRight) {
|
||||
gameView.moveRight()
|
||||
vibrateForPieceMove()
|
||||
lastMoveTime = currentTime
|
||||
isMovingRight = true
|
||||
isMovingLeft = false
|
||||
|
||||
// Start continuous movement after initial input
|
||||
handler.removeCallbacks(moveLeftRunnable)
|
||||
handler.postDelayed(moveRightRunnable, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
return true
|
||||
} else if (axisX < 0 && !isMovingLeft && currentTime - lastMoveTime > MOVE_COOLDOWN_MS) {
|
||||
} else if (axisX < 0 && !isMovingLeft) {
|
||||
gameView.moveLeft()
|
||||
vibrateForPieceMove()
|
||||
lastMoveTime = currentTime
|
||||
isMovingLeft = true
|
||||
isMovingRight = false
|
||||
|
||||
// Start continuous movement after initial input
|
||||
handler.removeCallbacks(moveRightRunnable)
|
||||
handler.postDelayed(moveLeftRunnable, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// Reset horizontal movement flags when stick returns to center
|
||||
isMovingLeft = false
|
||||
isMovingRight = false
|
||||
handler.removeCallbacks(moveLeftRunnable)
|
||||
handler.removeCallbacks(moveRightRunnable)
|
||||
}
|
||||
|
||||
if (Math.abs(axisY) > STICK_DEADZONE) {
|
||||
if (axisY > 0 && !isMovingDown && currentTime - lastMoveTime > MOVE_COOLDOWN_MS) {
|
||||
if (axisY > 0 && !isMovingDown) {
|
||||
gameView.softDrop()
|
||||
vibrateForPieceMove()
|
||||
lastMoveTime = currentTime
|
||||
isMovingDown = true
|
||||
|
||||
// Start continuous movement after initial input
|
||||
handler.postDelayed(moveDownRunnable, CONTINUOUS_MOVEMENT_DELAY_MS)
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// Reset vertical movement flag when stick returns to center
|
||||
isMovingDown = false
|
||||
handler.removeCallbacks(moveDownRunnable)
|
||||
}
|
||||
|
||||
// Check right analog stick for rotation
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue