mirror of
https://github.com/cmclark00/mintris.git
synced 2025-05-18 05:15:20 +01:00
Fix: Adjust layout padding to respect display cutouts
This commit is contained in:
parent
501e5b37fc
commit
6044b0d93b
8 changed files with 176 additions and 84 deletions
131
README.md
131
README.md
|
@ -1,106 +1,95 @@
|
||||||
# pixelmintdrop
|
# pixelmintdrop
|
||||||
|
|
||||||
A modern Tetris implementation for Android, featuring smooth animations, responsive controls, and a beautiful minimalist design.
|
A modern falling block puzzle game for Android, featuring smooth animations, responsive controls, and a beautiful minimalist design.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Core Gameplay
|
### Core Gameplay
|
||||||
- Classic Tetris mechanics
|
- Familiar block-stacking gameplay
|
||||||
- 7-bag randomizer for piece distribution
|
- 7-bag randomizer for piece distribution
|
||||||
- Ghost piece preview
|
- Ghost piece preview for precise placement
|
||||||
- Hard drop and soft drop
|
- Hard drop and soft drop controls
|
||||||
- T-Spin detection and scoring
|
- Advanced move detection (e.g., T-Spins) and scoring
|
||||||
- High score system with top 5 scores
|
- Persistent high score system (Top 5)
|
||||||
|
|
||||||
### Modern Android Features
|
### Modern Android Features
|
||||||
- Optimized for Android 11+ (API 30+)
|
- Optimized for Android 11+ (API 30+)
|
||||||
- Hardware-accelerated rendering
|
- Smooth hardware-accelerated rendering
|
||||||
- High refresh rate support
|
- High refresh rate support for fluid visuals
|
||||||
- Haptic feedback for piece movement and line clears
|
- Haptic feedback for tactile interaction (piece movement, line clears)
|
||||||
- Dark theme support
|
- Automatic Dark theme support
|
||||||
- Responsive touch controls
|
- Intuitive and responsive touch controls
|
||||||
- Edge-to-edge display support
|
- Full edge-to-edge display utilization
|
||||||
|
|
||||||
### Scoring System
|
### Scoring System
|
||||||
|
|
||||||
The game features a comprehensive scoring system:
|
Pixelmint Drop features a comprehensive scoring system designed to reward skillful play:
|
||||||
|
|
||||||
#### Base Scores
|
#### Base Scores
|
||||||
- Single line: 100 points
|
- Single line clear: 100 points
|
||||||
- Double: 300 points
|
- Double line clear: 300 points
|
||||||
- Triple: 500 points
|
- Triple line clear: 500 points
|
||||||
- Quad (4 lines): 1200 points
|
- Quad line clear (4 lines): 1200 points
|
||||||
|
|
||||||
#### Multipliers
|
#### Multipliers & Bonuses
|
||||||
|
|
||||||
1. **Level Multiplier**
|
1. **Level Multiplier**
|
||||||
- Score is multiplied by current level
|
- Score multiplied by the current level.
|
||||||
- Level increases every 10 lines cleared
|
- Level increases every 10 lines cleared (Max Level: 20).
|
||||||
- Maximum level is 20
|
|
||||||
|
|
||||||
2. **Combo System**
|
2. **Combo System**
|
||||||
- Combo counter increases with each line clear
|
- Consecutive line clears increase a combo multiplier.
|
||||||
- Resets if no lines are cleared
|
- Resets if a piece is placed without clearing lines.
|
||||||
- Multipliers:
|
- Multipliers: 1x (1), 1.5x (2), 2.0x (3), 2.5x (4), 3.0x (5+ combos).
|
||||||
- 1 combo: 1.0x
|
|
||||||
- 2 combos: 1.5x
|
|
||||||
- 3 combos: 2.0x
|
|
||||||
- 4 combos: 2.5x
|
|
||||||
- 5+ combos: 3.0x
|
|
||||||
|
|
||||||
3. **Back-to-Back Quad**
|
3. **Back-to-Back Quad Bonus**
|
||||||
- 50% bonus (1.5x) for consecutive Quad clears
|
- 50% bonus (1.5x) for clearing 4 lines consecutively.
|
||||||
- Resets if a non-Quad clear is performed
|
- Resets on non-Quad clears.
|
||||||
|
|
||||||
4. **Perfect Clear**
|
4. **Perfect Clear Bonus**
|
||||||
- 2x for single line
|
- Bonus multiplier for clearing lines leaving an empty board.
|
||||||
- 3x for double
|
- Multipliers: 2x (Single), 3x (Double), 4x (Triple), 5x (Quad).
|
||||||
- 4x for triple
|
|
||||||
- 5x for Quad
|
|
||||||
- Awarded when clearing lines without leaving blocks
|
|
||||||
|
|
||||||
5. **All Clear**
|
5. **All Clear Bonus**
|
||||||
- 2x multiplier when clearing all blocks
|
- 2x multiplier for clearing the entire grid of blocks.
|
||||||
- Requires no blocks in grid and no pieces in play
|
|
||||||
|
|
||||||
6. **T-Spin Bonuses**
|
6. **T-Spin Bonuses**
|
||||||
- Single: 2x
|
- Additional multipliers for executing T-Spin maneuvers.
|
||||||
- Double: 4x
|
- Single: 2x, Double: 4x, Triple: 6x.
|
||||||
- Triple: 6x
|
|
||||||
|
|
||||||
### Controls
|
### Controls
|
||||||
- Swipe left/right to move piece
|
- **Swipe left/right:** Move piece horizontally.
|
||||||
- Swipe down quickly for hard drop
|
- **Swipe down quickly:** Hard drop (instant placement).
|
||||||
- Swipe down slowly for soft drop
|
- **Swipe down slowly:** Soft drop (faster downward movement).
|
||||||
- Single tap to rotate
|
- **Single tap:** Rotate piece.
|
||||||
|
|
||||||
### Visual Effects
|
### Visual Effects
|
||||||
- Smooth piece movement animations
|
- Silky-smooth piece movement animations.
|
||||||
- Pulsing border glow during line clears
|
- Dynamic pulsing border glow during line clears.
|
||||||
- Ghost piece preview
|
- Clear ghost piece preview for accurate drops.
|
||||||
- Block glow effects
|
- Subtle block glow effects.
|
||||||
- Subtle grid lines
|
- Clean grid lines for better visibility.
|
||||||
- Animated title screen with falling pieces
|
- Engaging animated title screen featuring falling pieces.
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
- Android 11 (API 30) or higher
|
- Android 11 (API 30) or higher.
|
||||||
- Hardware acceleration support
|
- Hardware acceleration support.
|
||||||
- 2GB RAM minimum
|
- Minimum 2GB RAM recommended.
|
||||||
|
|
||||||
### Performance Optimizations
|
### Performance Optimizations
|
||||||
- Hardware-accelerated rendering
|
- Leverages hardware-accelerated rendering via Android Canvas.
|
||||||
- Efficient collision detection
|
- Efficient collision detection algorithms.
|
||||||
- Optimized grid operations
|
- Optimized grid data structures and operations.
|
||||||
- Smooth animations at 60fps
|
- Targets smooth 60fps animations.
|
||||||
- Background thread for score calculations
|
- Score calculations performed on a background thread to maintain UI responsiveness.
|
||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
- Written in Kotlin
|
- Developed entirely in Kotlin.
|
||||||
- Uses Android Canvas for rendering
|
- Utilizes Android Canvas API for custom drawing.
|
||||||
- Follows Material Design guidelines
|
- Adheres to Material Design principles for UI/UX.
|
||||||
- Implements high score persistence using SharedPreferences
|
- Persists high scores using SharedPreferences.
|
||||||
|
|
||||||
## Building from Source
|
## Building from Source
|
||||||
|
|
||||||
|
@ -108,15 +97,13 @@ The game features a comprehensive scoring system:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/cmclark00/pixelmintdrop.git
|
git clone https://github.com/cmclark00/pixelmintdrop.git
|
||||||
```
|
```
|
||||||
|
2. Open the project in Android Studio.
|
||||||
2. Open the project in Android Studio
|
3. Build and run on a compatible Android device or emulator (API 30+).
|
||||||
|
|
||||||
3. Build and run on your device or emulator
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
Contributions are welcome! Please feel free to submit a Pull Request with improvements or bug fixes.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
This project is licensed under the MIT License - see the `LICENSE` file for details.
|
|
@ -11,6 +11,11 @@ import android.graphics.Color
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.InputDevice
|
import android.view.InputDevice
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
|
|
||||||
class HighScoresActivity : AppCompatActivity() {
|
class HighScoresActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: HighScoresBinding
|
private lateinit var binding: HighScoresBinding
|
||||||
|
@ -26,6 +31,20 @@ class HighScoresActivity : AppCompatActivity() {
|
||||||
binding = HighScoresBinding.inflate(layoutInflater)
|
binding = HighScoresBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
// Apply insets to the root view
|
||||||
|
val initialPadding = Rect(binding.root.paddingLeft, binding.root.paddingTop,
|
||||||
|
binding.root.paddingRight, binding.root.paddingBottom)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
||||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
view.updatePadding(
|
||||||
|
left = initialPadding.left + insets.left,
|
||||||
|
top = initialPadding.top + insets.top,
|
||||||
|
right = initialPadding.right + insets.right,
|
||||||
|
bottom = initialPadding.bottom + insets.bottom
|
||||||
|
)
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
|
||||||
highScoreManager = HighScoreManager(this)
|
highScoreManager = HighScoreManager(this)
|
||||||
progressionManager = PlayerProgressionManager(this)
|
progressionManager = PlayerProgressionManager(this)
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,10 @@ import android.widget.ImageButton
|
||||||
import android.graphics.drawable.GradientDrawable
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Switch
|
import android.widget.Switch
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(),
|
class MainActivity : AppCompatActivity(),
|
||||||
GamepadController.GamepadConnectionListener,
|
GamepadController.GamepadConnectionListener,
|
||||||
|
@ -135,6 +139,65 @@ class MainActivity : AppCompatActivity(),
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
// Store initial padding values before applying insets
|
||||||
|
val initialPausePadding = Rect(binding.pauseContainer.paddingLeft, binding.pauseContainer.paddingTop,
|
||||||
|
binding.pauseContainer.paddingRight, binding.pauseContainer.paddingBottom)
|
||||||
|
val initialGameOverPadding = Rect(binding.gameOverContainer.paddingLeft, binding.gameOverContainer.paddingTop,
|
||||||
|
binding.gameOverContainer.paddingRight, binding.gameOverContainer.paddingBottom)
|
||||||
|
val initialCustomizationPadding = Rect(binding.customizationContainer.paddingLeft, binding.customizationContainer.paddingTop,
|
||||||
|
binding.customizationContainer.paddingRight, binding.customizationContainer.paddingBottom)
|
||||||
|
val initialProgressionPadding = Rect(binding.progressionScreen.paddingLeft, binding.progressionScreen.paddingTop,
|
||||||
|
binding.progressionScreen.paddingRight, binding.progressionScreen.paddingBottom)
|
||||||
|
|
||||||
|
// Apply insets to the pause container
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.pauseContainer) { view, windowInsets ->
|
||||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
// Apply insets by adding to initial padding
|
||||||
|
view.updatePadding(
|
||||||
|
left = initialPausePadding.left + insets.left,
|
||||||
|
top = initialPausePadding.top + insets.top,
|
||||||
|
right = initialPausePadding.right + insets.right,
|
||||||
|
bottom = initialPausePadding.bottom + insets.bottom
|
||||||
|
)
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply insets to the game over container
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.gameOverContainer) { view, windowInsets ->
|
||||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
view.updatePadding(
|
||||||
|
left = initialGameOverPadding.left + insets.left,
|
||||||
|
top = initialGameOverPadding.top + insets.top,
|
||||||
|
right = initialGameOverPadding.right + insets.right,
|
||||||
|
bottom = initialGameOverPadding.bottom + insets.bottom
|
||||||
|
)
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply insets to the customization container
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.customizationContainer) { view, windowInsets ->
|
||||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
view.updatePadding(
|
||||||
|
left = initialCustomizationPadding.left + insets.left,
|
||||||
|
top = initialCustomizationPadding.top + insets.top,
|
||||||
|
right = initialCustomizationPadding.right + insets.right,
|
||||||
|
bottom = initialCustomizationPadding.bottom + insets.bottom
|
||||||
|
)
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply insets to the progression screen
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.progressionScreen) { view, windowInsets ->
|
||||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
view.updatePadding(
|
||||||
|
left = initialProgressionPadding.left + insets.left,
|
||||||
|
top = initialProgressionPadding.top + insets.top,
|
||||||
|
right = initialProgressionPadding.right + insets.right,
|
||||||
|
bottom = initialProgressionPadding.bottom + insets.bottom
|
||||||
|
)
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
|
||||||
// Disable Android back gesture to prevent accidental app exits
|
// Disable Android back gesture to prevent accidental app exits
|
||||||
disableAndroidBackGesture()
|
disableAndroidBackGesture()
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
package com.pixelmintdrop
|
package com.pixelmintdrop
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
import com.pixelmintdrop.databinding.ActivityStatsBinding
|
import com.pixelmintdrop.databinding.ActivityStatsBinding
|
||||||
import com.pixelmintdrop.model.StatsManager
|
import com.pixelmintdrop.model.StatsManager
|
||||||
import com.pixelmintdrop.model.PlayerProgressionManager
|
import com.pixelmintdrop.model.PlayerProgressionManager
|
||||||
import android.graphics.Color
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -21,6 +26,20 @@ class StatsActivity : AppCompatActivity() {
|
||||||
binding = ActivityStatsBinding.inflate(layoutInflater)
|
binding = ActivityStatsBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
// Apply insets to the root view
|
||||||
|
val initialPadding = Rect(binding.root.paddingLeft, binding.root.paddingTop,
|
||||||
|
binding.root.paddingRight, binding.root.paddingBottom)
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
||||||
|
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
|
view.updatePadding(
|
||||||
|
left = initialPadding.left + insets.left,
|
||||||
|
top = initialPadding.top + insets.top,
|
||||||
|
right = initialPadding.right + insets.right,
|
||||||
|
bottom = initialPadding.bottom + insets.bottom
|
||||||
|
)
|
||||||
|
WindowInsetsCompat.CONSUMED
|
||||||
|
}
|
||||||
|
|
||||||
statsManager = StatsManager(this)
|
statsManager = StatsManager(this)
|
||||||
progressionManager = PlayerProgressionManager(this)
|
progressionManager = PlayerProgressionManager(this)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="16dp"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black">
|
android:background="@color/black"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black"
|
android:background="@color/black"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="16dp">
|
android:padding="16dp"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue