工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

必要な部品と材料

部品数量備考
Arduino UNO1
AZ-Delivery 2.4インチ TFT LCD タッチディスプレイ シールド (ILI9341, 8ビット並列)1240x320ピクセル、SDカードスロット内蔵

使用するアプリとオンラインサービス

プロジェクト概要

Arduino UNOとTFT LCDシールド (240x320ピクセル、ILI9341ドライバー、8ビット並列通信) で動作する、クラシックなブレークアウトゲームの小型版です。

ゲーム内容

複数のステージがあり、各ステージでレンガの行数・列数・パターンを設定可能 (最大8行、2行ごとに色違い)。タッチパネルでパドルを左右に動かし、ボールを壁やパドルで反射させてレンガを壊していきます。パドルでボールを取り損ねるとミス。行ごとに得点が異なります。

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

各レベルでパドルサイズとボールサイズを設定可能。ボール速度はヒットごとに加速。パドルのどの位置でヒットしたかによって水平速度も変化します。

新しいステージを自由に定義・追加できます。

Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

遊び方

デバイスを両手で持ち、親指で画面をタッチしてパドルを左右に動かします。

Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

新ステージの定義方法

以下の構造体でステージを定義します。


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},
    // ... 以下同様に追加可能
};

壁パターン

壁(レンガ配置)パターンは8x8ビット配列で定義します。


{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
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

ハードウェア

AZ-Delivery 2.4インチ TFT LCDシールド (抵抗膜式4線タッチスクリーン、SDカードリーダー内蔵) を使用。詳細は拙記事「Road testing an AZ-Delivery 2.4 TFT LCD Touch Display」を参照。

Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

シールドの取り付け

Arduinoにシールドを挿すだけです。

Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

使用ライブラリ:


#include      // コアグラフィックライブラリ
#include 
#include 

タッチスクリーンのキャリブレーション

タッチ位置を正確に取得するためキャリブレーションが必要です。MCUFriend_kbv ライブラリの例題 TouchScreen_Calibr_native を使用します。シリアルモニタを開き、画面の指示に従って白くハイライトされた位置マーカーを押し続けます。全ポイント完了でキャリブレーション値が画面とシリアル出力に表示されます。このプロジェクトでは「ポートレート(縦向き)キャリブレーション」の値を使用します。


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)

アニメーション処理

画像を時間経過で移動させるには、静的な速度を用い、各タイムステップで位置に加算します。

pos += vel * dt;

浮動小数点演算を避ける工夫

ILI9341の解像度は240x320で、ピクセル参照には9ビット×2必要。16ビット整数を使えば6ビットを小数部に割り当てられます。

nnnn nnnn nndd dddd  (上位10ビット整数部、下位6ビット小数部)

この6ビットを「バイナリ指数 (exponent)」と呼び、0.000〜0.63の小数部を表現可能。整数演算のみで浮動小数点演算を回避できます。整数部取得は右シフトで行います。

number >> exponent

実際のコードでは以下のように使用。ボール位置更新時に指数分右シフトして整数座標を得ています。


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

デモモード

以下の定義を有効化すると、パドルが自動でボールを追従するデモモードになります (動画参照)。

#define DEMO_MODE

楽しんでください!

新しいパターンやレベルを作って共有しましょう!

ソースコード

Arduino Breakout (Arduino)


/* 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  // Core graphics library
#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
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4
Adafruit_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 1000
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;
game_state_type state;

void setup() {
    initTft(tft);
    gameSize = {0, 0, tft.width(), tft.height()};
    newGame(&games[0], &state, tft);
}

void loop(void) {
    int selection = readUiSelection(game, &state, -1);
    drawPlayer(game, &state);
    state.playerxold = state.playerx;
    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;
    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 < GAMES_NUMBER) {
        level++;
        newGame(&games[level], &state, tft);
    } else if (state.remainingLives <= 0) {
        gameOverTouchToStart();
        state.score = 0;
        level = 0;
        newGame(game, &state, tft);
    }
}

// 以下、newGame, setupState, updateLives, setupWall, drawBrick, noBricks,
// drawPlayer, drawBall, touchToStart, gameOverTouchToStart, updateScore,
// checkBrickCollision, checkCornerCollision, hitBrick, checkBorderCollision,
// checkBallCollisions, checkBallExit, setBrick, unsetBrick, isBrickIn,
// initTft, clearDialog, drawBoxedString, readUiSelection, waitForTouch
// 等の関数定義が続く (全文はオリジナル参照)

回路図

Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現

製造プロセス

  1. Arduino NanoとMPU-6050で作るリアルタイムジャイロスコープゲーム
  2. Arduino UNOとOLEDディスプレイでクラシックPongゲームを自作:ステップバイステップチュートリアル
  3. Arduinoで携帯型静電容量タッチピアノを自作:MPR121シールド活用・ステップバイステップ
  4. DIY Arduino USBゲームコントローラー - 高性能ゲームパッドを自作
  5. Arduino NanoとMAX7219で作る24×16 LEDポングゲーム機
  6. 巨大レゴミニフィグ・アニマトロニクス「オペレーション」ゲームをArduinoで自作
  7. USB-MIDI機器をBluetooth LEでiOSに無線接続 ─ Arduinoベースの3つのアダプター設計
  8. Pixel Chaser: Arduino Nanoで作るワンタップLEDゲーム
  9. Arduino Dueでマスターする音声認識と音声合成
  10. Arduinoで自動化するChrome恐竜ゲーム – LDRとPythonで障害物を検知してジャンプ
  11. Arduino UNOで作る静電容量式タッチLEDスイッチ - 簡単DIY