亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

Arduino Touch Breakout 游戏

组件和用品

Arduino UNO
× 1
AZ-Delivery 2.4 TFT LCD 触摸屏 Arduino 扩展板
× 1

应用和在线服务

Arduino IDE

关于这个项目

这是Arduino UNO和TFT LCD屏幕(240x320像素)的经典突破视频游戏的小版本,具有8位并行通信的驱动程序ILI9341。

游戏

这个 Breakout 有多个屏幕,带有不同的可配置行和列的积木,最多八行,每两行一种不同的颜色,可以用不同的模式编程打开或关闭。使用单个球,使用触摸面板,玩家必须使用墙壁和/或下方的桨击倒尽可能多的砖块,以将球弹到砖块上并消除它们。如果球员的球拍错过了球的反弹,他们将失去一个回合。

每排积木获得不同的积分。

uint8_t pointsForRow[] ={7, 7, 5, 5, 3, 3 , 1, 1}; 

每个级别都可以配置桨的大小和球的大小。每次击球时球速都会增加,您可以为每个屏幕配置初始速度。根据击球点的不同,水平速度也会发生变化

您可以定义为具有不同墙壁图案的新屏幕:

怎么玩

用双手握住设备,用拇指手指在屏幕上向左或向右移动拨片。

定义一个新屏幕

这个结构体用于定义一个新的屏幕:

typedef struct game_type {
int ballsize;
int playerwidth;
int playerheight;
int exponent;
int top;
int行;
int 列;
int brickGap;
int living;
int wall[GAMES_NUMBER];
int initVelx;
int initVely;
} game_type;

并将新屏幕添加到集合中:

game_type games[GAMES_NUMBER] =
// 球大小、玩家宽度、玩家高度、指数、顶部、行、列、brickGap、生命、墙[8]、initVelx、initVely
{
{ 10, 60, 8, 6, 40 , 8, 8, 3, 3, {0x18, 0x66, 0xFF, 0xDB, 0xFF, 0x7E, 0x24, 0x3C}, 28, -28},

墙面图案

墙壁图案定义为8x8位数组

ej.

{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA} 

对应这个位数组

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

会产生这面墙,注意是镜像的:

硬件

该项目使用 AZ-Delivery 2.4 英寸 TFT LCD 显示屏,带有电阻式 4 线触摸屏和集成 SD 卡读卡器。 AZ-Delivery 2.4英寸TFT液晶显示屏。

在我的文章“道路测试 AZ-Delivery 2, 4 TFT LCD 触摸显示器”中详细介绍了此防护罩

组装盾牌

您只需将屏蔽罩插在 Aduino 上即可。

图书馆

#include  // 核心图形库
#include
#include

校准触摸屏

您必须校准显示器,以便在您触摸显示器时位置信息是正确的。 MCUFriend_kbv 库提供了一个名为“TouchScreen_Calibr_native”的示例。该示例将结果发送到串行端口。启动Arduino IDE的串口监视器,复制示例生成的代码。

按照触摸屏上的说明,按住以白色突出显示的位置标记。完成所有位置标记后,将在触摸屏和串口上向您输出显示器的校准情况。

对于这个项目,你需要“人像校准”的数据。

TouchScreen.h GFX 校准
使所有控制和总线引脚 INPUT_PULLUP
典型的 30k 模拟上拉与相应引脚
当数字写为低电平时读为低
例如对于 300R X 方向读取 ~25
e.g. 500R Y 方向读取 ~30
测试:(A2, D8) =26
测试:(A3, D9) =28
ID =0x9341
cx=153 cy=103 cz=534 X、Y、压力
cx=150 cy=475 cz=406 X、Y、压力
cx=155 cy=868 cz=231 X、Y、压力
cx=517 cy=103 cz=561 X、Y、压力
cx=535 cy=855 cz=364 X、Y、压力
cx=884 cy=88 cz=650 X、Y、压力
cx=908 cy=478 cz=557 X、Y、压力
cx=902 cy=864 cz=488 X、Y、压力
*** 从串行终端复制粘贴:
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;
肖像校准240 x 320
x =map(px, LEFT=118 , RT=931, 0, 240)
y =map(py, TOP=72, BOT=887, 0, 320)
景观校准 320 x 240
x =map(py, LEFT=72, RT=887, 0, 320)
y =map(px, TOP=931, BOT=118, 0, 240)

动画

随着时间的推移在屏幕上移动图像是使用静态速度并将其应用于每个时间步长的图像位置。

pos +=vel * dt;

避免浮点运算

ILI9341 分辨率为 240 x 320,因此我们需要两个 9 位整数来引用屏幕中的一个像素。使用 16 位整数,这让我们有 6 位自由来表示小数部分。

nnnn nnnn nndd dddd

我们称这个数字 6 为二进制指数。我们可以使用这六位来获得一个范围从 0.000 到 0.63 的小数部分。所以我们可以使用整数数学来避免浮点运算。

为了得到数字的整数部分,我们做一个算术右移。

数字>> 指数

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 ->指数);

演示模式

取消对定义指令的注释,球拍将跟随演示视频中的球:

#define DEMO_MODE 

享受吧!

创建新模式并分享它们!

代码

  • Arduino Breakout
Arduino BreakoutArduino
/* Arduino Touch TFT Breakout Classic breakout game 所需部件:Ardunio UNO AZ-Delivery 2.4 TFT LCD Touch Display Arduino Shield or compatible 此示例代码在公共领域。 07 11 2020 由 Enrique Albertos 修改*/​​// #define DEMO_MODE#include  // 核心图形库#include #include #define BLACK 0x0000#define BLUE 0x001F#define RED 0xF800#定义GREEN 0x07E0#定义青色到0x07FF#定义品红0xF81F#定义YELLOW 0xFFE0#定义WHITE为0xFFFF的#define PRIMARY_COLOR 0x4A11#定义PRIMARY_LIGHT_COLOR 0x7A17#定义PRIMARY_DARK_COLOR 0x4016#定义PRIMARY_TEXT_COLOR 0x7FFF的#定义LCD-CS A3 //片选去模拟3 #define LCD_CD A2 // 命令/数据进入模拟 2#define LCD_WR A1 // LCD 写入进入模拟 1#define LCD_RD A0 // LCD 读取进入模拟 0#define LCD_RESET A4 // 可以交替连接到 Arduino 的复位pinAdafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);#define LOWFLASH (defined(__AVR_ATmega328P__) &&defined(MCUFRIEND_KBV_H_))// 触摸屏压力阈值#define MINPRESSURE 40#define MAXPRESSURE 100st 触摸屏校准=100st XP 8, XM =A2, YP =A3, YM =9; //240x320 ID=0x9341const 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 分数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, 0x208 , 0x80};uint8_t pointsForRow[] ={7, 7, 5, 5, 3, 3, 1, 1};#define GAMES_NUMBER 16typedef struct game_type { int ballsize;国际玩家宽度;国际球员高度;整数指数;国际顶级;整数行;整数列; intbrickGap; int生活; int 墙[GAMES_NUMBER]; int initVelx; int initVely;} game_type;game_type games[GAMES_NUMBER] =// 球大小、玩家宽度、玩家高度、指数、顶部、行、列、brickGap、生命、墙[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、3、8 , 3, {0xFF, 0x99, 0xFF, 0xE7, 0xBD, 0xDB, 0xE7, 0xFF} , 28, -28}, { 10, 50, 8, 6, 40 , 8, 8, 3, 3, {0x5AA, 0 , 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}, 0 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;国际玩家x; int playerxold; int wallState[8];积分;剩余生命;国际顶级;国际底部;内墙;内部墙底; int 砖高度; int brickwidth;};game_state_type state;////////////////////////////////////////// //////////////////// ARDUINO 设置//////////////////////// //////////////////////////////////void setup(){ initTft(tft);游戏大小 ={0, 0, tft.width(), tft.height()}; newGame(&games[0], &state, tft);}///////////////////////////////// ///////////////////////// ARDUINO 循环//////////////////// /////////////////////////////////////// int selection =-1;void loop( void){ selection =readUiSelection(game, &state, selection); drawPlayer(游戏,&状态); // 存储旧位置以移除旧像素 state.playerxold =state.playerx; // 计算新的球位置 x1 =x0 + vx * dt // 检查最大速度 if (abs( state.vely)> ((1 <exponent) - 1)) { state.vely =((1 <<游戏->指数) - 1) * ((state.vely> 0) - (state.vely <0)); } if (abs( state.velx)> ((1 <exponent) - 1)) { state.velx =((1 <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 -> 球尺寸 ); // 存储旧位置以移除旧像素 state.ballxold =state.ballx; state.ballyold =state.bally; // 增加速度 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 (noBricks(game, &state) &&level lives, state->remainingLives); updateScore(state->score);设置墙(游戏,状态);触摸开始(); clearDialog(游戏大小); 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 rows; i ++) { state->wallState[i] =0; } state->playerx =tft.width() / 2 - 游戏->playerwidth / 2;状态->剩余生命=游戏->生命;状态->bally =状态->底部<<游戏->指数;状态->ballyold =状态->底部<<游戏->指数;状态->velx =游戏->initVelx; state->vely =game->initVely;}void updateLives(int lives, int resumeLives) { for (int i =0; i walltop =游戏->top + 40; state->wallbottom =state->walltop + game->rows * state->brickheight; for (int i =0; i rows; i++) { for (int j =0; j 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 rows; i++) { if (state->wallState[i]) return false; } return true;}void drawPlayer(game_type * game, game_state_type * state) { // 绘制 tft.fillRect(state->playerx, state->bottom, game->playerwidth, game->playerheight, YELLOW); if (state->playerx !=state->playerxold) { // 移除旧像素 if (state->playerx 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) { // 移除旧像素 //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); } // 绘制新球 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 碰撞 =0;碰撞 +=checkCornerCollision(game, state, x, y);碰撞 +=checkCornerCollision(game, state, x1, y1);碰撞 +=checkCornerCollision(game, state, x, y1);碰撞 +=checkCornerCollision(game, state, x1, y); if (collisions> 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 wallbottom)) { int yBrickRow =( y - state->walltop) / state->brickheight; int xBrickColumn =(x / state->brickwidth);如果 (isBrickIn(state->wallState, xBrickColumn, yBrickRow) ) { hitBrick(state, xBrickColumn, yBrickRow);返回 1; } } return 0;}void hitBrick(game_state_type * state, int xBrick, int yBrickRow) { state->score +=pointsForRow[yBrickRow]; drawBrick(状态,xBrick,yBrickRow,白色);延迟(16); drawBrick(状态,xBrick,yBrickRow,蓝色);延迟(8); drawBrick(状态,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) { // 检查墙壁碰撞 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))) { // 改变玩家边界附近的 vel x if (x> (state->playerx + game->playerwidth - 6)) { state ->velx =状态->velx - 1; } else if (x playerx + 6) { state->velx =state->velx + 1; } state->vely =-abs(state->vely); }}void checkBallCollision(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);延迟(500);状态->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 设置////////////////// /////////////////////////////////////////void initTft(Adafruit_TFTLCD &tft) { tft.reset(); uint16_t ID =tft.readID(); tft.begin(ID); tft.setRotation(0);}//////////////////////////////////////// /////////////////////屏幕绘画方法//////////////////////// ////////////////////////////////////** 在填充框上打印前景色文本背景颜色。计算矩形大小以包括没有边距的整个文本 @param x 左上角的水平坐标 @param y 左上角的垂直坐标 @param fontsize 要打印的文本字体大小 @param foreColor 要打印的文本的前景色@param backgroundColor 填充矩形的颜色 @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);}/** 清屏到默认背景@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);}////////////////////////// ////////////////////////////////// 读取用户界面选择////////// ////////////////////////////////////////////////// //* 检查用户是否正在选择任何可见的启用 ui 元素调用所选元素的 onTap 回调并将其设置为按下 @param lastSelected 最后一个选择 @return 新选择*/int readUiSelection(game_type * game, game_state_type * state, const int16_t lastSelected ) { int16_t xpos, ypos; //屏幕坐标 TSPoint tp =ts.getPoint(); //tp.x, tp.y 是 ADC 值 // 如果共享引脚,您需要固定触摸屏引脚的方向 pinMode(XM, OUTPUT); pinMode(YP,输出); // 我们有一些我们认为“有效”的最小压力 // 压力为 0 意味着没有压力! if (tp.z> MINPRESSURE &&tp.z  tft.width() / 2) { state->playerx +=2; } else { 状态->playerx -=2; } if (state->playerx>=tft.width() - game->playerwidth) state->playerx =tft.width() - game->playerwidth; if (state->playerx <0) state->playerx =0;返回 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; //屏幕坐标 TSPoint tp =ts.getPoint(); //tp.x, tp.y 是 ADC 值 // 如果共享引脚,您需要固定触摸屏引脚的方向 pinMode(XM, OUTPUT); pinMode(YP,输出); // 我们有一些我们认为“有效”的最小压力 // 压力为 0 意味着没有压力! if (tp.z> MINPRESSURE &&tp.z  

示意图


制造工艺

  1. Arduino Gyroscope Game with MPU-6050
  2. Arduino Pong Game - OLED 显示器
  3. 便携式电容式触摸钢琴
  4. Arduino 游戏控制器
  5. Arduino Pong Game on 24x16 Matrix with MAX7219
  6. Giant Animatronics Lego Minfig 操作游戏
  7. USB-BLE 无线 MIDI 适配器
  8. 像素追逐游戏
  9. 使用 Arduino 进行语音识别和合成
  10. 使用 arduino 的自动化恐龙游戏
  11. 使用 Arduino 的触摸控制灯
  12. LED 轮盘游戏