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