Game Breakout Sentuh Arduino: Bangun Arcade Klasik pada Layar TFT LCD 2.4″
Komponen dan Perlengkapan
Arduino UNO – 1 unit
AZ-Delivery 2.4 TFT LCD Touch Display Arduino Shield – 1 unit
Aplikasi dan Layanan Online
Tentang Proyek
Ini adalah versi kecil dari permainan video breakout klasik untuk Arduino UNO dan layar TFT LCD (240x320 piksel), driver ILI9341 dengan komunikasi paralel 8-bit.
Permainan
Breakout ini memiliki beberapa layar dengan baris dan kolom batu bata yang dapat dikonfigurasi, hingga delapan baris, dengan setiap dua baris warna berbeda, yang dapat diprogram menyala atau mati dengan pola berbeda. Menggunakan satu bola, menggunakan panel sentuh pemain harus menuntaskan sebanyak mungkin batu bata dengan menggunakan dinding dan/atau palet di bawah untuk memantulkan bola terhadap batu bata dan menghapusnya. Jika palet pemain melewatkan pantulan bola, mereka akan kehilangan giliran.
Setiap baris batu bata menghasilkan poin yang berbeda.
uint8_t pointsForRow[] = {7, 7, 5, 5, 3, 3 , 1, 1};
Setiap level dapat mengonfigurasi ukuran palet dan ukuran bola. Kecepatan bola meningkat pada setiap pukulan, Anda dapat mengonfigurasi kecepatan awal untuk setiap layar. Bergantung pada titik palet yang mengenai bola, kecepatan horizontal juga berubah
Anda dapat menentukan layar baru dengan pola dinding yang berbeda:
Cara Bermain
Pegang perangkat dengan tangan Anda dan gunakan jempol Anda di atas layar untuk memindahkan palet ke kiri atau ke kanan.
Definisi Layar Baru
Struktur ini digunakan untuk mendefinisikan layar baru:
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;
dan tambahkan layar baru ke dalam set:
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},
Pola Dinding
Pola dinding didefinisikan sebagai array bit 8x8
ej.
{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}
yang sesuai dengan array bit ini
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
Akan menghasilkan dinding ini, perhatikan bahwa itu dicerminkan:
Perangkat Keras
Proyek ini menggunakan layar TFT LCD AZ-Delivery 2,4 inci dengan layar sentuh resistif 4-kawat dan pembaca kartu SD terintegrasi. Layar TFT LCD AZ-Delivery 2,4 inci.
Selengkapnya tentang shield ini dalam artikel saya "Road testing an AZ-Delivery 2, 4 TFT LCD Touch Display"
Pengassemblyan Shield
Anda hanya perlu memasang shield di atas Arduino.
Libraries
#include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_TFTLCD.h> #include <TouchScreen.h>
Kalibrasi Layar Sentuh
Anda harus mengkalibrasi layar sehingga informasi posisi benar saat Anda menyentuh layar. Library MCUFriend_kbv menyediakan contoh dengan nama "TouchScreen_Calibr_native". Contoh mengirim hasilnya ke port serial. Mulai serial monitor Arduino IDE sehingga Anda dapat menyalin kode yang dihasilkan oleh contoh.
Ikuti instruksi pada layar sentuh, tekan dan tahan penanda posisi yang ditampilkan, yang disorot putih. Setelah Anda selesai dengan semua penanda posisi, kalibrasi layar akan ditampilkan kepada Anda pada layar sentuh dan melalui port serial.
Untuk proyek ini Anda butuh data untuk "kalibrasi 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)
Animasi
Untuk memindahkan gambar di seluruh layar seiring waktu adalah dengan menggunakan kecepatan statis dan menerapkannya ke posisi gambar setiap langkah waktu.
pos += vel * dt;
Menghindari Aritmetika Titik Mengambang
Resolusi ILI9341 adalah 240 x 320 jadi kita butuh dua integer 9 bit untuk mereferensikan piksel di layar. Menggunakan integer 16 bit ini membiarkan 6 bit bebas untuk merepresentasikan bagian desimal.
nnnn nnnn nndd dddd
Kami menyebut angka ini, 6, eksponen biner. Dan kita dapat menggunakan enam bit ini untuk memiliki bagian desimal yang berkisar dari 0,000 hingga 0,63. Jadi kita dapat menggunakan matematika integer menghindari aritmetika titik mengambang.
Untuk mendapatkan bagian integer dari angka kita lakukan pergeseran aritmetika ke kanan.
number >> exponent
state.ballx += state.velx; state.bally += state.vely; // check ball collisions and exit checkBallCollisions(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent); checkBallExit(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent);
Mode Demo
Hapus komentar Define Directive dan palet akan mengikuti bola seperti yang terlihat dalam video demo:
#define DEMO_MODE
Nikmatinya!
Buat pola dan level baru dan bagikan!
Kode
Arduino BreakoutArduino
/* Arduino Touch TFT Breakout Classic breakout game Parts needed: Ardunio UNO AZ-Delivery 2.4 TFT LCD Touch Display Arduino Shield or compatible This example code is in the public domain. Modified 07 11 2020 By Enrique Albertos */ // #define DEMO_MODE #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_TFTLCD.h> #include <TouchScreen.h> #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 goes to Analog 3 #define LCD_CD A2 // Command/Data goes to Analog 2 #define LCD_WR A1 // LCD Write goes to Analog 1 #define LCD_RD A0 // LCD Read goes to Analog 0 #define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET); #define LOWFLASH (defined(__AVR_ATmega328P__) && defined(MCUFRIEND_KBV_H_)) // Touch screen presure threshold #define MINPRESSURE 40 #define MAXPRESSURE 1000 // Touch screen calibration 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] = // 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} }; 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 state; ////////////////////////////////////////////////////////////// // ARDUINO SETUP ////////////////////////////////////////////////////////////// void setup() { initTft(tft); gameSize = {0, 0, tft.width(), tft.height()}; newGame(&games[0], &state, tft); } ////////////////////////////////////////////////////////////// // ARDUINO LOOP ////////////////////////////////////////////////////////////// int selection = -1; void loop(void) { selection = readUiSelection(game, &state, selection); drawPlayer(game, &state); // store old position to remove old pixels state.playerxold = state.playerx; // calculate new ball position x1 = x0 + vx * dt // check max speed 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; // check ball collisions and exit checkBallCollisions(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent); checkBallExit(game, &state, state.ballx >> game->exponent, state.bally >> game->exponent); // draw ball in new position drawBall(state.ballx >> game->exponent, state.bally >> game->exponent, state.ballxold >> game->exponent, state.ballyold >> game->exponent, game->ballsize ); // store old position to remove old pixels state.ballxold = state.ballx; state.ballyold = state.bally; // increment velocity state.velx = (20 + (state.score >> 3 )) * ( (state.velx > 0) - (state.velx < 0)); state.vely = (20 + (state.score >> 3 )) * ( (state.vely > 0) - (state.vely < 0)); // if no bricks go to next level 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); } } void newGame(game_type* newGame, game_state_type * state, Adafruit_TFTLCD &tft) { game = newGame; setupState(game, state, tft); clearDialog(gameSize); updateLives(game->lives, state->remainingLives); updateScore(state->score); setupWall(game, state); touchToStart(); clearDialog(gameSize); updateLives(game->lives, state->remainingLives); updateScore(state->score); setupWall(game, state); } void setupStateSizes(game_type* game, game_state_type * state, Adafruit_TFTLCD &tft) { state->bottom = tft.height() - 30; state->brickwidth = tft.width() / game->columns; state->brickheight = tft.height() / 24; } void setupState(game_type* game, game_state_type * state, Adafruit_TFTLCD &tft) { setupStateSizes(game, state, tft); for (int i = 0; i < game->rows ; i ++) { state->wallState[i] = 0; } state->playerx = tft.width() / 2 - game->playerwidth / 2; state->remainingLives = game->lives; state->bally = state->bottom << game->exponent; state->ballyold = state->bottom << game->exponent; state->velx = game->initVelx; state->vely = game->initVely; } void updateLives(int lives, int remainingLives) { for (int i = 0; i < lives; i++) { tft.fillCircle((1 + i) * 15, 15, 5, BLACK); } for (int i = 0; i < remainingLives; i++) { tft.fillCircle((1 + i) * 15, 15, 5, YELLOW); } } void setupWall(game_type * game, game_state_type * state) { int colors[] = {RED, RED, BLUE, BLUE, YELLOW, YELLOW, GREEN, GREEN}; state->walltop = game->top + 40; state->wallbottom = state->walltop + game->rows * state->brickheight; for (int i = 0; i < game->rows; i++) { for (int j = 0; j < game->columns; j++) { if (isBrickIn(game->wall, j, i)) { setBrick(state->wallState, j, i); drawBrick(state, j, i, colors[i]); } } } } void drawBrick(game_state_type * state, int xBrick, int yBrickRow, uint16_t backgroundColor) { tft.fillRect((state->brickwidth * xBrick) + game->brickGap, state->walltop + (state->brickheight * yBrickRow) + game->brickGap , state->brickwidth - game->brickGap * 2, state->brickheight - game->brickGap * 2, backgroundColor); } boolean noBricks(game_type * game, game_state_type * state) { for (int i = 0; i < game->rows ; i++) { if (state->wallState[i]) return false; } return true; } void drawPlayer(game_type * game, game_state_type * state) { // paint tft.fillRect(state->playerx, state->bottom, game->playerwidth, game->playerheight, YELLOW); if (state->playerx != state->playerxold) { // remove old pixels if (state->playerx < state->playerxold) { tft.fillRect(state->playerx + game->playerwidth, state->bottom, abs(state->playerx - state->playerxold), game->playerheight, backgroundColor); } else { tft.fillRect(state->playerxold, state->bottom, abs(state->playerx - state->playerxold), game->playerheight, backgroundColor); } } } void drawBall(int x, int y, int xold, int yold, int ballsize) { // remove old pixels //if (xold != x && yold != y) { if (xold <= x && yold <= y) { tft.fillRect(xold , yold, ballsize, y - yold, BLACK); tft.fillRect(xold , yold, x - xold, ballsize, BLACK); } else if (xold >= x && yold >= y) { tft.fillRect(x + ballsize , yold, xold - x, ballsize, BLACK); tft.fillRect(xold , y + ballsize, ballsize, yold - y, BLACK); } else if (xold <= x && yold >= y) { tft.fillRect(xold , yold, x - xold, ballsize, BLACK); tft.fillRect(xold , y + ballsize, ballsize, yold - y, BLACK); } else if (xold >= x && yold <= y) { tft.fillRect(xold , yold, ballsize, y - yold, BLACK); tft.fillRect(x + ballsize, yold, xold - x, ballsize, BLACK); } // paint new ball tft.fillRect(x , y, ballsize, ballsize, YELLOW); // } } void touchToStart() { drawBoxedString(0, 200, " BREAKOUT", 3, YELLOW, BLACK); drawBoxedString(0, 240, " TOUCH TO START", 2, RED, BLACK); while (waitForTouch() < 0) {} } void gameOverTouchToStart() { drawBoxedString(0, 180, " GAME OVER", 3, YELLOW, BLACK); drawBoxedString(0, 220, " TOUCH TO START", 2, RED, BLACK); while (waitForTouch() < 0) {} } void updateScore (int score) { char buffer[5]; snprintf(buffer, sizeof(buffer), scoreFormat, score); drawBoxedString(tft.width() - 50, 6, buffer, 2, YELLOW, PRIMARY_DARK_COLOR); } void checkBrickCollision(game_type* game, game_state_type * state, uint16_t x, uint16_t y) { int x1 = x + game->ballsize; int y1 = y + game->ballsize; int collissions = 0; collissions += checkCornerCollision(game, state, x, y); collissions += checkCornerCollision(game, state, x1, y1); collissions += checkCornerCollision(game, state, x, y1); collissions += checkCornerCollision(game, state, x1, y); if (collissions > 0 ) { state->vely = (-1 * state->vely); if ((((x % state->brickwidth) == 0) && ( state->velx < 0 )) || ((((x + game->ballsize) % state->brickwidth) == 0) && ( state->velx > 0 )) ) { state->velx = (-1 * state->velx); } } } int checkCornerCollision(game_type * game, game_state_type * state, uint16_t x, uint16_t y) { if ((y > state->walltop) && (y < state->wallbottom)) { int yBrickRow = ( y - state->walltop) / state->brickheight; int xBrickColumn = (x / state->brickwidth); if (isBrickIn(state->wallState, xBrickColumn, yBrickRow) ) { hitBrick(state, xBrickColumn, yBrickRow); return 1; } } return 0; } void hitBrick(game_state_type * state, int xBrick, int yBrickRow) { state->score += pointsForRow[yBrickRow]; drawBrick(state, xBrick, yBrickRow, WHITE); delay(16); drawBrick(state, xBrick, yBrickRow, BLUE); delay(8); drawBrick(state, xBrick, yBrickRow, backgroundColor); unsetBrick(state->wallState, xBrick, yBrickRow); updateScore(state->score); } void checkBorderCollision(game_type * game, game_state_type * state, uint16_t x, uint16_t y) { // check wall collision if (x + game->ballsize >= tft.width()) { state->velx = -abs(state->velx); } if (x <= 0 ) { state->velx = abs(state->velx); } if (y <= SCORE_SIZE ) { state->vely = abs(state->vely); } if (((y + game->ballsize) >= state->bottom) && ((y + game->ballsize) <= (state->bottom + game->playerheight)) && (x >= state->playerx) && (x <= (state->playerx + game->playerwidth))) { // change vel x near player borders if (x > (state->playerx + game->playerwidth - 6)) { state->velx = state->velx - 1; } else if (x < state->playerx + 6) { state->velx = state->velx + 1; } state->vely = -abs(state->vely) ; } } void checkBallCollisions(game_type * game, game_state_type * state, uint16_t x, uint16_t y) { checkBrickCollision(game, state, x, y); checkBorderCollision(game, state, x, y); } void checkBallExit(game_type * game, game_state_type * state, uint16_t x, uint16_t y) { if (((y + game->ballsize) >= tft.height())) { state->remainingLives--; updateLives(game->lives, state->remainingLives); delay(500); state->vely = -abs(state->vely) ; } } void setBrick(int wall[], uint8_t x, uint8_t y) { wall[y] = wall[y] | BIT_MASK[x]; } void unsetBrick(int wall[], uint8_t x, uint8_t y) { wall[y] = wall[y] & ~BIT_MASK[x]; } boolean isBrickIn(int wall[], uint8_t x, uint8_t y) { return wall[y] & BIT_MASK[x]; } ////////////////////////////////////////////////////////////// // TFT SETUP ////////////////////////////////////////////////////////////// void initTft(Adafruit_TFTLCD & tft) { tft.reset(); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(0); } ////////////////////////////////////////////////////////////// // Screen Painting methods ////////////////////////////////////////////////////////////// /** Print a text in forecolor over a filled box with background color. Rectangle size is calculated to include the whole text without margins @param x horizontal coordinate in points left upper corner @param y vertical coordinate in points left upper corner @param fontsize font size of the text to print @param foreColor forecolor of the text to print @param backgroundColor color of the filled rect @return void */ void drawBoxedString(const uint16_t x, const uint16_t y, const char* string, const uint16_t fontsize, const uint16_t foreColor, const uint16_t backgroundColor) { tft.setTextSize(fontsize); int16_t x1, y1; uint16_t w, h; tft.getTextBounds(string, x, y, &x1, &y1, &w, &h); tft.fillRect(x, y, w, h, backgroundColor); tft.setCursor(x, y); tft.setTextColor(foreColor); tft.print(string); } /** Clear the screen to the default backgrounds @param void @return void */ void clearDialog(gameSize_type gameSize) { tft.fillRect(gameSize.x, gameSize.y, gameSize.width, gameSize.height, backgroundColor); tft.fillRect(gameSize.x, gameSize.y, gameSize.width, SCORE_SIZE, PRIMARY_DARK_COLOR); } ////////////////////////////////////////////////////////////// // READ UI SELECTION ////////////////////////////////////////////////////////////// /* Checks if the user is selecting any of the visible enabled ui elements The onTap callback of the selected element is called and it set as pressed @param lastSelected the last selection @return the new selection */ int readUiSelection(game_type * game, game_state_type * state, const int16_t lastSelected ) { int16_t xpos, ypos; //screen coordinates TSPoint tp = ts.getPoint(); //tp.x, tp.y are ADC values // if sharing pins, you'll need to fix the directions of the touchscreen pins pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); // we have some minimum pressure we consider 'valid' // pressure of 0 means no pressing! if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) { xpos = map(tp.x, TS_RT, TS_LEFT, 0, tft.width()); ypos = map(tp.y, TS_BOT, TS_TOP, 0, tft.height()); // are we in buttons area ? if (xpos > tft.width() / 2) { state->playerx += 2; } else { state->playerx -= 2; } if (state->playerx >= tft.width() - game->playerwidth) state->playerx = tft.width() - game->playerwidth; if (state->playerx < 0) state->playerx = 0; return 1; } #ifdef DEMO_MODE state->playerx = (state->ballx >> game->exponent) - game->playerwidth / 2; if (state->playerx >= tft.width() - game->playerwidth) state->playerx = tft.width() - game->playerwidth; if (state->playerx < 0) state->playerx = 0; #endif return -1; } int waitForTouch() { int16_t xpos, ypos; //screen coordinates TSPoint tp = ts.getPoint(); //tp.x, tp.y are ADC values // if sharing pins, you'll need to fix the directions of the touchscreen pins pinMode(XM, OUTPUT); pinMode(YP, OUTPUT); // we have some minimum pressure we consider 'valid' // pressure of 0 means no pressing! if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) { return 1; } return -1; }
Skematik