Jeu Breakout tactile Arduino : recréez l'arcade classique sur écran TFT 2,4″
Composants et fournitures
| Arduino UNO | × | 1 |
| Écran tactile TFT LCD 2,4" AZ-Delivery Shield Arduino | × | 1 |
Applications et services en ligne
- Arduino IDE
À propos de ce projet
C'est une petite version du jeu vidéo classique Breakout pour Arduino UNO et écran TFT LCD (240×320 pixels), pilote ILI9341 avec communication parallèle 8 bits.
Le jeu
Ce Breakout a plusieurs écrans avec différentes lignes et colonnes de briques configurables, jusqu'à huit lignes, avec chaque deux lignes d'une couleur différente, qui peuvent être programmées activées ou désactivées avec différents motifs. En utilisant une seule balle, le joueur doit abattre le plus de briques possible en utilisant les murs et/ou la raquette en bas pour faire ricocher la balle contre les briques et les éliminer. Si la raquette du joueur rate le rebond de la balle, il perd un tour.
Chaque ligne de briques rapporte des points différents :
uint8_t pointsForRow[] = {7, 7, 5, 5, 3, 3, 1, 1};
Chaque niveau peut configurer la taille de la raquette et de la balle. La vitesse de la balle augmente à chaque coup, vous pouvez configurer la vitesse initiale pour chaque écran. Selon le point de la raquette qui frappe la balle, la vitesse horizontale change aussi.
Vous pouvez définir de nouveaux écrans avec différents motifs de murs :
Comment jouer
Tenez l'appareil avec vos mains et utilisez vos pouces sur l'écran pour déplacer la raquette vers la gauche ou la droite.
Définir un nouvel écran
Cette structure est utilisée pour définir un nouvel écran :
typedef struct game_type {
int ballsize;
int playerwidth;
int playerheight;
int exponent;
int top;
int rows;
int columns;
int brickGap;
int lives;
int wall[GAMES_NUMBER];
int initVelx;
int initVely;
} game_type;
Et ajoutez le nouvel écran au jeu :
game_type games[GAMES_NUMBER] =
// ballsize, playerwidth, playerheight, exponent, top, rows, columns, brickGap, lives, wall[8], initVelx, initVely
{
{ 10, 60, 8, 6, 40 , 8, 8, 3, 3, {0x18, 0x66, 0xFF, 0xDB, 0xFF, 0x7E, 0x24, 0x3C} , 28, -28},
{ 10, 50, 8, 6, 40 , 8, 8, 3, 3, {0xFF, 0x99, 0xFF, 0xE7, 0xBD, 0xDB, 0xE7, 0xFF} , 28, -28},
{ 10, 50, 8, 6, 40 , 8, 8, 3, 3, {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55} , 28, -28},
{ 8, 50, 8, 6, 40 , 8, 8, 3, 3, {0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF} , 34, -34},
{ 10, 40, 8, 6, 40 , 8, 8, 3, 3, {0xFF, 0xAA, 0xAA, 0xFF, 0xFF, 0xAA, 0xAA, 0xFF} , 28, -28},
{ 10, 40, 8, 6, 40 , 8, 8, 3, 3, {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA} , 28, -28},
{ 12, 64, 8, 6, 60 , 4, 2, 3, 4, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 20, -20},
{ 12, 60, 8, 6, 60 , 5, 3, 3, 4, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 22, -22},
{ 10, 56, 8, 6, 30 , 6, 4, 3, 4, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 24, -24},
{ 10, 52, 8, 6, 30 , 7, 5, 3, 4, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 26, -26},
{ 8, 48, 8, 6, 30 , 8, 6, 3, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 28, -28},
{ 8, 44, 8, 6, 30 , 8, 7, 3, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 30, -30},
{ 8, 40, 8, 6, 30 , 8, 8, 3, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 32, -32},
{ 8, 36, 8, 6, 40 , 8, 8, 3, 3, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} , 34, -34},
{ 8, 36, 8, 6, 40 , 8, 8, 3, 3, {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA} , 34, -34}
};
Motif de mur
Le motif de mur est défini comme un tableau de bits 8×8.
Exemple :
{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}
Ce qui correspond à ce tableau de bits :
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
1,0,1,0,1,0,1,0
Produira ce mur (noter qu'il est miroir) :
Matériel
Ce projet utilise un écran TFT LCD 2,4 pouces AZ-Delivery avec écran tactile résistif 4 fils et lecteur de carte SD intégré.
Plus sur ce shield dans mon article « Test routier d'un écran tactile AZ-Delivery 2,4 TFT LCD ».
Assemblage du shield
Il suffit de brancher le shield sur l'Arduino.
Bibliothèques
#include // Bibliothèque graphique de base
#include
#include
Calibrage de l'écran tactile
Vous devez calibrer l'affichage pour que les informations de position soient correctes quand vous touchez l'écran. La bibliothèque MCUFriend_kbv fournit un exemple nommé « TouchScreen_Calibr_native ». L'exemple envoie les résultats sur le port série. Démarrez le moniteur série de l'IDE Arduino pour copier le code généré par l'exemple.
Suivez les instructions sur l'écran tactile, appuyez et maintenez les marqueurs de position affichés, qui sont surlignés en blanc. Une fois tous les marqueurs de position faits, le calibrage de l'affichage est affiché sur l'écran tactile et par le port série.
Pour ce projet, vous avez besoin des données pour le « calibrage portrait ».
TouchScreen.h GFX Calibration
Making all control and bus pins INPUT_PULLUP
Typical 30k Analog pullup with corresponding pin
would read low when digital is written LOW
e.g. reads ~25 for 300R X direction
e.g. reads ~30 for 500R Y direction
Testing : (A2, D8) = 26
Testing : (A3, D9) = 28
ID = 0x9341
cx=153 cy=103 cz=534 X, Y, Pressure
cx=150 cy=475 cz=406 X, Y, Pressure
cx=155 cy=868 cz=231 X, Y, Pressure
cx=517 cy=103 cz=561 X, Y, Pressure
cx=535 cy=855 cz=364 X, Y, Pressure
cx=884 cy=88 cz=650 X, Y, Pressure
cx=908 cy=478 cz=557 X, Y, Pressure
cx=902 cy=864 cz=488 X, Y, Pressure
*** COPY-PASTE from Serial Terminal:
const int XP=8,XM=A2,YP=A3,YM=9; //240x320 ID=0x9341
const int TS_LEFT=118,TS_RT=931,TS_TOP=72,TS_BOT=887;
PORTRAIT CALIBRATION 240 x 320
x = map(p.x, LEFT=118, RT=931, 0, 240)
y = map(p.y, TOP=72, BOT=887, 0, 320)
LANDSCAPE CALIBRATION 320 x 240
x = map(p.y, LEFT=72, RT=887, 0, 320)
y = map(p.x, TOP=931, BOT=118, 0, 240)
Animation
Pour déplacer l'image à travers l'écran au fil du temps, on utilise une vitesse statique et on l'applique à la position d'une image à chaque pas de temps.
pos += vel * dt;
Éviter l'arithmétique à virgule flottante
La résolution ILI9341 est 240 × 320, donc nous avons besoin de deux entiers de 9 bits pour référencer un pixel à l'écran. En utilisant des entiers de 16 bits, cela laisse 6 bits libres pour représenter une partie décimale.
nnnn nnnn nndd dddd
Nous appelons ce nombre, 6, l'exposant binaire. Et nous pouvons utiliser ces 6 bits pour avoir une partie décimale allant de 0,000 à 0,63. Ainsi, nous pouvons utiliser l'arithmétique entière en évitant l'arithmétique à virgule flottante.
Pour obtenir la partie entière du nombre, nous faisons un décalage arithmétique vers la droite.
number >> exponent
state.ballx += state.velx;
state.bally += state.vely;
// vérification collisions balle et sortie
checkBallCollisions(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent);
checkBallExit(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent);
Mode démo
Décommentez la directive Define et la raquette suivra la balle comme vu dans les vidéos de démo :
#define DEMO_MODE
Amusez-vous !
Créez de nouveaux motifs et niveaux et partagez-les !
Code
- Arduino Breakout
Arduino Breakout
/* Arduino Touch TFT Breakout
Jeu breakout classique
Pièces nécessaires:
Arduino UNO
AZ-Delivery 2.4 TFT LCD Touch Display Arduino Shield ou compatible
Ce code est dans le domaine public.
Modifié le 07/11/2020
Par Enrique Albertos */
// #define DEMO_MODE
#include // Bibliothèque graphique de base
#include
#include
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define PRIMARY_COLOR 0x4A11
#define PRIMARY_LIGHT_COLOR 0x7A17
#define PRIMARY_DARK_COLOR 0x4016
#define PRIMARY_TEXT_COLOR 0x7FFF
#define LCD_CS A3 // Chip Select sur Analog 3
#define LCD_CD A2 // Command/Data sur Analog 2
#define LCD_WR A1 // LCD Write sur Analog 1
#define LCD_RD A0 // LCD Read sur Analog 0
#define LCD_RESET A4 // Ou connecter au reset de l'Arduino
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
#define LOWFLASH (defined(__AVR_ATmega328P__) && defined(MCUFRIEND_KBV_H_))
// Seuil de pression écran tactile
#define MINPRESSURE 40
#define MAXPRESSURE 1000
// Calibrage écran tactile
const int16_t XP = 8, XM = A2, YP = A3, YM = 9; // 240x320 ID=0x9341
const int16_t TS_LEFT = 122, TS_RT = 929, TS_TOP = 77, TS_BOT = 884;
const TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define SCORE_SIZE 30
char scoreFormat[] = "%04d";
typedef struct gameSize_type {
int16_t x, y, width, height;
} gameSize_type;
gameSize_type gameSize;
uint16_t backgroundColor = BLACK;
int level;
const uint8_t BIT_MASK[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
uint8_t pointsForRow[] = {7, 7, 5, 5, 3, 3, 1, 1};
#define GAMES_NUMBER 16
typedef struct game_type {
int ballsize;
int playerwidth;
int playerheight;
int exponent;
int top;
int rows;
int columns;
int brickGap;
int lives;
int wall[GAMES_NUMBER];
int initVelx;
int initVely;
} game_type;
game_type games[GAMES_NUMBER] = // voir définition complète ci-dessus
{ ... };
game_type* game;
typedef struct game_state_type {
uint16_t ballx;
uint16_t bally;
uint16_t ballxold;
uint16_t ballyold;
int velx;
int vely;
int playerx;
int playerxold;
int wallState[8];
int score;
int remainingLives;
int top;
int bottom;
int walltop;
int wallbottom;
int brickheight;
int brickwidth;
} game_state_type;
game_state_type state;
// SETUP ARDUINO
void setup() {
initTft(tft);
gameSize = {0, 0, tft.width(), tft.height()};
newGame(&games[0], &state, tft);
}
// BOUCLE ARDUINO
int selection = -1;
void loop(void) {
selection = readUiSelection(game, &state, selection);
drawPlayer(game, &state);
state.playerxold = state.playerx;
// Vitesse max
if (abs(state.vely) > ((1 << game->exponent) - 1)) {
state.vely = ((1 << game->exponent) - 1) * ((state.vely > 0) - (state.vely < 0));
}
if (abs(state.velx) > ((1 << game->exponent) - 1)) {
state.velx = ((1 << game->exponent) - 1) * ((state.velx > 0) - (state.velx < 0));
}
state.ballx += state.velx;
state.bally += state.vely;
checkBallCollisions(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent);
checkBallExit(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent);
drawBall(state.ballx >> game->exponent, state.bally >> game->exponent,
state.ballxold >> game->exponent, state.ballyold >> game->exponent,
game->ballsize);
state.ballxold = state.ballx;
state.ballyold = state.bally;
// Incrément vitesse
state.velx = (20 + (state.score >> 3)) * ((state.velx > 0) - (state.velx < 0));
state.vely = (20 + (state.score >> 3)) * ((state.vely > 0) - (state.vely < 0));
// Niveau suivant si plus de briques
if (noBricks(game, &state) && level < GAMES_NUMBER) {
level++;
newGame(&games[level], &state, tft);
} else if (state.remainingLives <= 0) {
gameOverTouchToStart();
state.score = 0;
level = 0;
newGame(game, &state, tft);
}
}
// Fonctions utilitaires (newGame, setupState, drawPlayer, drawBall, touchToStart, gameOverTouchToStart,
// updateScore, checkBrickCollision, checkCornerCollision, hitBrick, checkBorderCollision,
// checkBallCollisions, checkBallExit, setBrick, unsetBrick, isBrickIn, initTft, clearDialog,
// drawBoxedString, readUiSelection, waitForTouch) - voir code complet dans le sketch original
Schémas
Processus de fabrication
- Construire un jeu gyroscopique temps réel avec Arduino Nano et capteur MPU-6050
- Créer un jeu Pong classique sur Arduino UNO avec écran OLED – Tutoriel étape par étape
- Construire un piano tactile capacitif portable avec Arduino – Guide étape par étape
- Manette de jeu USB Arduino DIY – Construisez votre propre gamepad haute performance
- Construire une console Pong 24×16 LED avec Arduino Nano et MAX7219
- Construire un jeu « Opération » géant animé type Lego Minifigure avec Arduino
- Adaptateurs MIDI USB-BLE sans fil – Connectivité transparente pour musiciens
- Pixel Chaser : Jeu LED interactif à une touche avec Arduino Nano
- Maîtriser la reconnaissance et la synthèse vocale sur Arduino Due