F24: Brick Breaker
Contents
Grading Criteria
- How well is Software & Hardware Design described?
- How well can this report be used to reproduce this project?
- Code Quality
- Overall Report Quality:
- Software Block Diagrams
- Hardware Block Diagrams
- Schematic Quality
- Quality of technical challenges and solutions adopted.
Brick Breaker
Abstract
Brick Breaker is a classic arcade-style game focused on quick reflexes and survival, reminiscent of retro gaming experiences. This project aims to recreate the intense and fast-paced gameplay using the SJ-2 board and an LED matrix display. In this game, players control a character (or an object) that must dodge incoming obstacles from multiple directions, with the speed and frequency of obstacles increasing over time. The objective is to survive as long as possible, setting high scores based on survival time. Players will use buttons or a joystick to maneuver, with core implementation focusing on responsive controls, real-time collision detection, and adaptive difficulty for sustained challenge.
Objectives & Introduction
The project is split into a few sub-topics that could be worked by individuals:
- Main "clock" task for updating the LED matrix.
- Main gameplay loop task that would update the position of the ball, paddle, and blocks.
- Design of various game screens via a state machine.
- Game logic to determine the ball's bounce relative to its current trajectory.
- MP3 background track during gameplay.
Team Members & Responsibilities
- Manoj
- Game logic
- Block generator
- Kevin
- Hardware connections
- Game page switching logic
- Game page switching logic
- Led testing , button testing
- Harbans
- Accerometer and paddle
- Block generator
Schedule
Week# | Start Date | End Date | Task | Status |
---|---|---|---|---|
1 |
|
|
|
|
2 |
|
|
|
|
3 |
|
|
|
|
4 |
|
|
|
|
5 |
|
|
|
|
6 |
|
|
|
|
7 |
|
|
|
|
8 |
|
|
|
|
9 |
|
|
|
|
10 |
|
|
|
|
Parts List & Cost
Part | Link | Price | Quantity |
---|---|---|---|
LED Matrix | Sparkfun | $80 | 1 |
Power Supply | Adafruit | $30 | 1 |
Button | Adafruit | $2.50 | 1 |
Quick connect wires | Adafruit | $4.95 | 1 |
MP3 Module | Adafruit | $34.95 | 1 |
Speakers | Adafruit | $7.50 | 1 |
SJ2 Development Board | Amazon | $50 | 1 |
Design & Implementation
For the design and implementation of the Brick Breaker game, the SJ2 board serves as the central controller to interface with a 64x64 LED matrix, control buttons, and an accelerometer. Each of these components plays a crucial role in the functionality of the game, enabling dynamic gameplay and interactivity.
Hardware Design
In the hardware setup for this project, we outlined a few high-level connections that were necessary to implement the Brick Breaker game. These connections can be visualized in the top-level schematic shown below. The schematic was designed using draw.io.
Hardware Interconnects:
- SJ2 Connection to the LED Matrix
- SJ2 Connection to Buttons
- SJ2 Connection to Accelerometer
SJ2 Board Connection to LED Matrix: The SJ2 board controlled the 64x64 LED matrix, which served as the primary visual interface for the game. The matrix required a range of GPIO pins for row, column, and color control. It did not use standard communication protocols like I2C or UART but relied on GPIO switching to drive the display. The key pin connections are as follows:
Address Pins | Color Pins | Control Pins |
---|---|---|
A, B, C, D, E | R2, G2, B2 | OE, CLK, LAT |
- Address Pins: Allowed selection of specific rows for updating pixel data (rows 0 - 31).
- Color Pins: Enabled 8 distinct colors through combinations of red, green, and blue.
- Control Pins:
- OE (Output Enable): Controlled when the display was active.
- CLK (Clock): Synchronized data transfer for row and pixel updates.
- LAT (Latch): Locked data into the display.
SJ2 Board Connection to Buttons The buttons served as an input interface for the player to control the paddle in the game. The buttons were connected to GPIO pins on the SJ2 board and configured to trigger on falling-edge interrupts. Each button press caused an interrupt, which was handled by a software ISR to update the paddle’s position on the LED matrix.
Key features of the button setup:
- Interrupt-Driven Design:
- Each button press generated an interrupt to ensure immediate responsiveness.
- Debouncing:
- Software debouncing eliminated the effects of mechanical noise in button presses.
SJ2 Board Connection to Accelerometer The accelerometer provided an alternative input method by allowing the player to control the paddle through tilting. It was connected to the SJ2 board via the I2C interface, which facilitated real-time reading of the accelerometer's X-axis data. This data was processed to move the paddle proportionally to the tilt.
Key features of the accelerometer setup:
- I2C Communication:
- Enabled efficient data transfer between the accelerometer and the SJ2 board.
- Real-Time Input:
- X-axis readings were mapped to paddle movement for smooth control.
- Calibration:
- Initial calibration ensured accurate and stable readings, compensating for noise or offsets.
Hardware Interface
The 64x64 LED matrix acts as the primary display for the game, rendering all visual elements such as the paddle, ball, and bricks. The SJ2 board interfaces with the matrix using GPIO pins, which are configured to drive the rows, columns, and colors.
- GPIO Configuration:
- The matrix requires GPIO pins for address selection (A, B, C, D, E), color data (R2, G2, B2), and control signals (OE, CLK, LAT).
- The pins are switched at high frequencies to refresh the display and maintain smooth animations.
- Driving the Display:
- Row Selection: Address pins are used to select a specific row on the matrix for updating pixel data.
- Pixel Data Transfer: Color pins determine the intensity of red, green, and blue for each pixel, enabling up to 8 colors.
- Control Signals:
- OE (Output Enable): Controls when the LEDs are active.
- CLK (Clock): Synchronizes data transfer to the display.
- LAT (Latch): Locks the updated data into the matrix for display.
Software Design
The Brick Breaker game was implemented using a state machine design, which allowed for modular and organized control over the game's logic. The main function driving the game, game_state_machine__run_game(), transitions through different states based on user interactions and game events. These states, such as INIT, GAME, PAUSE, and GAME_OVER, provide a clear structure to the game flow. A state machine design was chosen for its ability to simplify complex logic by dividing it into smaller, well-defined states, making the code easier to understand and maintain. Transitions between states occur based on specific triggers, such as a button press to pause the game or the ball falling out of bounds. By using a state machine, redundant operations were minimized, particularly in the GAME state, where initialization functions were executed only once during transitions to ensure optimal performance.
The LED matrix was updated dynamically within the GAME state to display the paddle, ball, and bricks. Instead of rewriting the entire display buffer, only the portions of the matrix affected by the game elements were updated. This approach ensured smoother animations and reduced computational overhead. For instance, paddle movement involved modifying only the row where the paddle resided, while ball updates modified the ball's current and next positions. This optimization kept the gameplay visually responsive without overloading the system's resources. The main gameplay loop also called specialized functions to handle game elements like the paddle, ball, and brick states, ensuring modularity and scalability for future enhancements.
The ball movement and collision logic, handled within game_state_machine__update_ball_position, formed the core of the game’s mechanics. The ball's trajectory was calculated based on its current velocity and direction. Collisions with walls, the paddle, and bricks were detected and resolved in real time. Wall collisions caused the ball to bounce, while paddle collisions adjusted its angle of reflection based on the contact point, giving players greater control. Brick collisions were handled by checking the corresponding coordinates in the matrix buffer. If a collision occurred, the brick's state was updated, and the ball's direction was adjusted. Special cases, such as corner collisions with multiple bricks, were also addressed by updating all affected bricks and recalculating the ball’s trajectory.
To enhance gameplay, bricks were designed with varying levels of durability represented by their color. Each brick color indicated its "life," with red bricks having one life and higher durability bricks represented by colors like green, blue, and purple. When a brick was hit, its life was decremented, and the LED matrix was updated to reflect the new state. Scoring was integrated into this system, with players earning points for each hit or destroyed brick. To add a competitive aspect, a high-score table was maintained, tracking the top five scores. Although the high scores were stored in a sorted array for this implementation, future plans include saving them to the SJ2 board’s flash memory to ensure persistence across power cycles.
Player input was managed through buttons and an accelerometer, providing intuitive and responsive control. The buttons allowed precise left or right movement of the paddle, while the accelerometer offered an alternative control method, enabling the paddle to move based on the tilt of the SJ2 board. This dual-input system enhanced player engagement and added variety to the gameplay experience. Additionally, dynamic game elements, such as increasing ball speed and additional levels of difficulty, kept the game challenging as players progressed. The game state transitions were smooth and well-optimized, with the state machine ensuring clear separation of responsibilities and efficient execution of tasks.
Testing & Technical Challenges
A significant technical challenge during the implementation of the Brick Breaker game was ensuring accurate collision detection, especially when the ball interacted with multiple bricks or hit a corner. The issue arose when the ball's next position overlapped with a corner shared by two or more blocks. This led to inconsistencies in how collisions were detected and resolved. For instance, if two bricks were stacked vertically or placed side by side, the ball's direction could behave unpredictably, leading to unexpected bounces. Initially, our collision logic treated corners as part of either a row or a column based on the ball's direction of travel. While this approach worked in simple cases, it failed when multiple blocks were involved.
To address this, we standardized the handling of corners by treating all corners as part of a column rather than a row. This change provided a consistent logic flow for detecting and handling collisions, ensuring the ball's trajectory behaved predictably even in complex scenarios. Testing this approach revealed that treating corners as rows led to erratic bounces and breaks in the gameplay flow, while treating them as part of columns yielded a smoother and more intuitive experience. This adjustment significantly improved the game's performance and user experience, resolving an issue that had initially seemed insurmountable.
Conclusion
The Brick Breaker game project served as an excellent opportunity to apply and expand our knowledge of embedded systems, specifically in hardware-software integration and real-time application development. Throughout the project, we faced several challenges, including collision detection issues with block corners and the difficulties associated with debugging real-time game logic. By addressing these problems with a combination of structured design and innovative solutions, such as standardizing collision handling and leveraging modular code, we were able to deliver a functional and engaging game.
Testing was both a critical and challenging aspect of the project. While print statement debugging helped identify and resolve issues, it became evident that this method is not scalable for larger or more complex projects. This realization underscored the importance of implementing robust unit testing frameworks in future endeavors to streamline the debugging process and improve code reliability.
Through this project, we not only deepened our understanding of the SJ2 board and its peripherals but also gained valuable insights into designing interactive systems with real-time constraints. We learned the significance of modular programming, effective problem-solving, and the practical challenges of integrating multiple hardware components. Moreover, this project reinforced the importance of designing for scalability and maintainability, skills that are critical for larger and more complex systems.
Ultimately, this project has enhanced our ability to think critically about embedded system design and implementation, providing a strong foundation for tackling similar challenges in future endeavors. The lessons learned and skills developed here will undoubtedly inform and improve our approach to future projects, whether they involve gaming systems, embedded controls, or other interactive applications.
Project Video
Upload a video of your project and post the link here.
Project Source Code
References
Acknowledgement
We'd like to thank Preet for giving us the opportunity to develop and learn through an interactive team project. We would also like to acknowledge the TA Shilja Jain for their feedback throughout the semester.
References Used
List any references used in project.
Appendix
You can list the references you used.