LoginSignup
2
0

70歳の挑戦... ESP32とTFT-LCD上で動くテトリス風ゲームを作ってみた

Last updated at Posted at 2024-04-24

 先に投稿したPC版テトリス風ゲームのArduino版(ESP32)を作成しました。
tenoros0.jpg
 よりゲームらしくしようと、タイトル画面(TENOROS)も加え、タッチパネル操作ができるようにしました。Arduino版の作成によりPC版のコードの悪い部分をかなり修正でき、さらにPC版ではできなかったちょっとした効果も付け加えられ、結果良かったです。
 今回用いたのは次の2つ。

1.ESP32-WROVER-KEY-R2(マイクロファンラボ製)
2.3.5インチ TFTディスプレイモジュール SPI接続 480x320

 細かい事を挙げていくと長くなりますので、詳しく知りたい方は私の以前の投稿

などを見てください。早速、以下にコードを示します。

Tenoros20240424.ino
#include <TFT_eSPI.h>  // Hardware-specific library

#define Y_H 24   // フィールドの高さ(上3段と最下段の壁を含む)
#define X_W 12   // フィールドの幅(両側の壁を含む)
#define Vars 32  // ブロックの種類(回転で得られるもの全部を別種とする)
#define PI 18    // 縦横pixel数 フィールド縦18x24=432 dots, フィールド横18x12=216 dots
#define Y0 0     // フィールド表示位置
#define X0 52
#define Y TFT_YELLOW
#define W TFT_WHITE
#define R TFT_RED
#define D TFT_DARKGREY
#define K TFT_BLACK
#define B TFT_BLUE
#define G TFT_GREEN
#define M TFT_MAGENTA

TFT_eSPI tft = TFT_eSPI();  // Invoke custom library

int field[Y_H][X_W];                                     // ブロックなどのデータを設定
int aline[Y_H];                                          // 横一列の固定ブロック数
int bXL = 0, bYU = 0, bW = 0, bH = 0, bXR = 0, bYD = 0;  // 現ブロックのデータの代入先
int nextB5[5];
int bNum = 0;
int timer = 0;
enum { TITLE,
      PLAY,
      OVER,
      RESET };  // 各シーンを定める定数
int scene;       // どのシーンの処理を行うか

int bSizeX[Vars] = { 4, 1, 4, 1,  // 各ブロックの横サイズ
                    3, 2, 3, 2,
                    3, 2, 3, 2,
                    3, 2, 3, 2,
                    3, 2, 3, 2,
                    2, 2, 2, 2,
                    3, 2, 3, 2,
                    3, 2, 3, 2 };
int bSizeY[Vars] = { 1, 4, 1, 4,  // 各ブロックの縦サイズ
                    2, 3, 2, 3,
                    2, 3, 2, 3,
                    2, 3, 2, 3,
                    2, 3, 2, 3,
                    2, 2, 2, 2,
                    2, 3, 2, 3,
                    2, 3, 2, 3 };

int blocks[Vars][4][4] =  // variety, y, x
 { { { 1, 1, 1, 1 },     // I
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 0, 0, 0 },
     { 1, 0, 0, 0 },
     { 1, 0, 0, 0 } },
   { { 1, 1, 1, 1 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 0, 0, 0 },
     { 1, 0, 0, 0 },
     { 1, 0, 0, 0 } },
   { { 1, 1, 1, 0 },  // 逆L
     { 0, 0, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 1, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },
     { 1, 0, 0, 0 },
     { 1, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 0, 1, 0 },  // L
     { 1, 1, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 0, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 1, 0 },
     { 1, 0, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 1, 0 },  // T
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },
     { 1, 1, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 1, 0, 0 },
     { 1, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },  // 逆T
     { 1, 1, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 1, 0, 0 },
     { 1, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 1, 0 },
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },  // 正方形
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 1, 0 },  // 稲妻
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 1, 0 },
     { 1, 1, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 0, 0, 0 },
     { 1, 1, 0, 0 },
     { 0, 1, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },  // 逆稲妻
     { 0, 1, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 1, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 1, 1, 0, 0 },
     { 0, 1, 1, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 } },
   { { 0, 1, 0, 0 },
     { 1, 1, 0, 0 },
     { 1, 0, 0, 0 },
     { 0, 0, 0, 0 } } };

void initField() {  // フィールド情報配列の初期化
 for (int i = 0; i < Y_H - 1; i++) {
   for (int j = 0; j < X_W; j++) {
     if (j == 0 || j == X_W - 1)
       field[i][j] = 9;
     else field[i][j] = 0;  // 何も無い所は0(黒)
   }
   aline[i] = 0;  // 横一列の情報
 }
 for (int j = 0; j < X_W; j++) field[Y_H - 1][j] = 9;  // 壁は9(濃い灰色)
}

void drawWall(void) {                   // 壁を描画
 for (int i = 3; i <= Y_H - 1; i++) {  // 0,1,2は壁なし
   if (i == Y_H - 1)
     for (int j = 0; j < X_W; j++)
       tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, D);
   else {
     tft.fillRect(X0 + PI * 0, Y0 + PI * i, PI - 2, PI - 2, D);
     tft.fillRect(X0 + PI * (X_W - 1), Y0 + PI * i, PI - 2, PI - 2, D);
   }
 }
}

void drawField(void) {  // フィールド情報を描画
 for (int i = 0; i < Y_H - 1; i++) {
   for (int j = 1; j < X_W - 1; j++) {
     if (field[i][j] == 1) {  // 移動中のブロックは黄
       tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, Y);
     } else if (field[i][j] == 2) {  // 固定ブロックは白
       tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, W);
     } else {  // == 9
       tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, K);
     }
   }
 }
}

void bRight(int n) {  // 右移動
 if (bXR < X_W - 2) {
   for (int y = bH - 1; y >= 0; y--) {
     for (int x = bW - 1; x >= 0; x--)
       if (field[bYU + y][bXL + x + 1] > 1) return;  // 固定物に衝突
   }
   for (int y = bH - 1; y >= 0; y--) {
     for (int x = bW - 1; x >= 0; x--) {
       if (field[bYU + y][bXL + x] < 2 && field[bYU + y][bXL + x + 1] < 2)  // 自分自身のみ移動
         field[bYU + y][bXL + x + 1] = field[bYU + y][bXL + x];             // フィールドデータ移動
       if (field[bYU + y][bXL + x] >= 2 && field[bYU + y][bXL + x + 1] < 2)
         field[bYU + y][bXL + x + 1] = 0;
     }
     if (field[bYU + y][bXL] < 2) field[bYU + y][bXL] = 0;
   }
   bXL++;
   bXR++;
 }
}

void bLeft(int n) {  // 左移動
 if (bXL > 1) {
   for (int y = bH - 1; y >= 0; y--) {
     for (int x = 0; x < bW; x++)
       if (field[bYU + y][bXL + x - 1] > 1 && field[bYU + y][bXL + x] == 1) return;  // 衝突
   }
   for (int y = bH - 1; y >= 0; y--) {
     for (int x = 0; x < bW; x++) {
       if (field[bYU + y][bXL + x - 1] < 2 && field[bYU + y][bXL + x] < 2)  // 自分自身のみ移動
         field[bYU + y][bXL + x - 1] = field[bYU + y][bXL + x];
       if (field[bYU + y][bXL + x - 1] < 2 && field[bYU + y][bXL + x] >= 2)
         field[bYU + y][bXL + x - 1] = 0;
     }
     if (field[bYU + y][bXR] < 2) field[bYU + y][bXR] = 0;
   }
   bXL--;
   bXR--;
 }
}

int rotCheck(int n0, int bXL, int bYU) {
 int l, m, n = n0;
 int bW, bH, bXR, bYD;

 l = (int)(n / 4) * 4;
 m = ((n % 4) + 1) % 4;
 n = l + m;       // 回転後のブロック番号でチェック
 bW = bSizeX[n];  // 各情報更新
 bH = bSizeY[n];
 bXR = bXL + bW - 1;
 bYD = bYU + bH - 1;
 if (bXR >= X_W - 1) {  // 右壁にぶつかったとき
   bXL -= 1;
   bXR -= 1;
 }
 if (bXL < 1) {  // 左壁にぶつかったとき
   bXL += 1;
   bXR += 1;
 }

 bool flg = true;  // Collision Check
 for (int y = 0; y < bH; y++) {
   for (int x = 0; x < bW; x++) {
     if (blocks[n][y][x] == 1 && field[bYU + y][bXL + x] > 1) {
       flg = false;  // ブロック描画位置に何かある
     }
   }
 }
 if (flg == true) return 1;
 else return 0;
}

void bRot(int* num) {  // 回転(右のみ)
 int l, m, n = *num;
 if (rotCheck(n, bXL, bYU) == 0) return;  // 回転できない

 for (int y = 0; y < bH; y++) {  // 前ブロックを消す
   for (int x = 0; x < bW; x++) {
     field[bYU + y][bXL + x] -= blocks[n][y][x];
     tft.fillRect(X0 + PI * (bXL + x), Y0 + PI * (bYU + y), PI - 2, PI - 2, D);
   }
 }

 l = (int)(n / 4) * 4;
 m = ((n % 4) + 1) % 4;
 n = l + m;       // 回転後の新ブロック番号
 bW = bSizeX[n];  // 各情報更新
 bH = bSizeY[n];
 bXR = bXL + bW - 1;
 bYD = bYU + bH - 1;
 if (bXR >= X_W - 1) {  // 右壁にぶつかったとき
   bXL -= 1;
   bXR -= 1;
 }
 if (bXL < 1) {  // 左壁にぶつかったとき
   bXL += 1;
   bXR += 1;
 }

 for (int y = 0; y < bH; y++) {  // 回転後のブロック描画
   for (int x = 0; x < bW; x++) {
     if (field[bYU + y][bXL + x] <= 1) {
       if (blocks[n][y][x] == 1) {
         field[bYU + y][bXL + x] = 1;
         tft.fillRect(X0 + PI * (bXL + x), Y0 + PI * (bYU + y), PI - 2, PI - 2, Y);
       } else if (blocks[n][y][x] == 0) {
         field[bYU + y][bXL + x] = 0;
         tft.fillRect(X0 + PI * (bXL + x), Y0 + PI * (bYU + y), PI - 2, PI - 2, K);
       }
     }
   }
 }
 *num = n;
}

int rakka(int n) {
 bool descentflg = true;
 bW = bSizeX[n];
 bH = bSizeY[n];
 for (int x = 0; x < bW; x++) {
   for (int y = bH - 1; y > bH - 4; y--) {
     if (blocks[n][y][x] == 1 && field[bYU + y + 1][bXL + x] > 1) descentflg = false;  // ブロック落下不可
   }
 }
 int sum;
 if (descentflg == false) {
   for (int y = 0; y < bH; y++) {
     for (int x = 0; x < bW; x++) {
       if (blocks[n][y][x] == 1) field[bYU + y][bXL + x] = 2;  // ブロック固定
     }
   }

   int TG[Y_H];
   for (int i = 0; i < Y_H; i++) { TG[i] = -1; }
   sum = 0;
   for (int i = Y_H - 2; i >= 0; i--) {  // 横一列揃ったか調べる
     aline[i] = 0;
     for (int j = 1; j < X_W - 1; j++) {
       if (field[i][j] == 2) aline[i] = aline[i] + 1;
     }
     if (aline[i] == X_W - 2) {  // == 10 揃った
       for (int j = 1; j < X_W - 1; j++)
         tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, M);  // MAGENTAで強調
       TG[sum] = i;
       sum++;
       delay(50);
     }
   }

   if (aline[3] > 0) return aline[3];  //--- GAME OVER ----------------

   if (sum > 0) {  // 揃った行を消す
     for (int t = 0; t < sum; t++) {
       for (int i = TG[t] + t; i > 0; i--) {
         for (int j = 1; j < X_W - 1; j++)
           tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, R);  // 赤で強調
         delay(50);
         for (int j = 1; j < X_W - 1; j++) {
           field[i][j] = field[i - 1][j];  // 消去行に上段のデータを移動、上書き
           if (field[i][j] == 0) {
             tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, K);
           } else {  // field[i][j] == 2 固定ブロックは描画
             tft.fillRect(X0 + PI * j, Y0 + PI * i, PI - 2, PI - 2, W);
           }
         }
         aline[i] = aline[i - 1];  // 固定ブロック数の行データも移動
       }
       for (int j = 1; j < X_W - 1; j++) field[0][j] = 0;  // 最上段は0で埋める
     }
   }
   sum = 0;
   descentflg = true;

   return -1;  // 次の新ブロックの生成落下

 } else {  // 落下可能
   bYU++;
   bYD++;
   for (int i = Y_H - 2; i >= 0; i--) {  // 最上段の0,1,2行もブロックを描画、落下させる
     if (i == 0) {
       for (int j = 1; j < X_W - 1; j++) field[i][j] = 0;  // 最上段は0で埋める
     } else {
       for (int j = 1; j < X_W - 1; j++) {
         if (field[i][j] >= 2) { ; }  // 壁、固定物があるので移動できない
         else if (field[i - 1][j] == 2) {
           ;
         }  // 固定物は移動しない
         else {
           field[i][j] = field[i - 1][j];  // 一行下に移動
           field[i - 1][j] = 0;            // 移動後は空欄
         }
       }
     }
   }

   int tY = bYU;
   bool flg = true;
   while (flg) {
     tY += 1;
     for (int y = 0; y < bH; y++) {
       for (int x = 0; x < bW; x++) {  // 現状、どこまで落下できるか調べる
         if (field[tY + y][bXL + x] > 1 && blocks[n][y][x] == 1) {
           flg = false;
         }
       }
     }
   }
   tY -= 1;
   for (int y = 0; y < bH; y++) {  // 落下予想図
     for (int x = 0; x < bW; x++) {
       if (blocks[n][y][x] == 1) {
         tft.fillRect(X0 + PI * (bXL + x), Y0 + PI * (tY + y), PI - 2, PI - 2, R);
       }
     }
   }
   return 0;
 }
}

void nbDisp(int* b) {   // 次のブロック5個を表示
 int X1 = 0, Y1 = PI;  // 文字(番号)、ブロック位置
 int pi = PI - 5;      // 13
 int dw = pi * 4, dh = pi * 5;
 tft.fillRect(X1, Y1, dw, dh * 5, K);
 for (int n = 0; n < 5; n++) {
   int i = b[n];  // numbers of next 5 blocks
   for (int y = 0; y < bSizeY[i]; y++) {
     for (int x = 0; x < bSizeX[i]; x++) {
       if (blocks[i][y][x] == 1)
         tft.fillRect(X1 + pi * x, Y1 + pi + dh * n + pi * y, pi - 2, pi - 2, Y);
     }
   }
   tft.setTextColor(W);
   tft.drawString("Next " + String(n), X1, Y1 + dh * n, 2);
 }
}

void nbSet(int* num, int* b) {  // 新ブロックをセット
 bW = bSizeX[*num];
 bH = bSizeY[*num];
 bYU = 4 - bH;
 int j = random(0, X_W - 1 - bSizeX[*num]) + 1;
 bXL = j;
 bXR = bXL + bW - 1;
 bYD = bYU + bH - 1;
 for (int y = 0; y < bH; y++) {
   for (int x = 0; x < bW; x++) {
     if (blocks[*num][y][x] == 1) field[bYU + y][bXL + x] = 1;
     else field[bYU + y][bXL + x] = 0;
   }
 }
 for (int n = 0; n < 4; n++) b[n] = b[n + 1];  // キューの更新
 b[4] = random(0, 32);
}

void gStart() {
 initField();
 randomSeed(analogRead(A0));
 for (int i = 0; i < 5; i++) nextB5[i] = random(0, 24);  // 5個のブロック生成。初手は稲妻型以外。
 scene = PLAY;
 timer = -1;  // timer = -1 で新ブロック生成、落下が始まる
}

int dtimer = 5;
int machi = 200;
int countRot = 0;
int dButtonW = (320 - 50) / 3;  // =90
int bx0 = 0, bx1 = dButtonW + 25, bx2 = bx1 * 2;
int dBH = 479 - (Y0 + PI * 24);
int bx3 = X0 + PI * 12;
int rButtonW = X0, rBH = PI * 4;

void setup() {
 Serial.begin(115200);
 tft.init();          // DisplayとTouchは同じSPIを使用
                      // T_DOのみMISOと接続し、SDO(MISO)はMISOと接続しない。
                      // T_DIN、SDI(MOSI)はMOSIと接続する。
 tft.setRotation(2);  // J2Pinsが上部の縦長使い。
 // 描画座標は、右向きにx(0-319)、下向きにy(0-479)。
 // タッチ座標は、上向きにt_x(0-319)、左向きにt_y(0-479)なので換算が必要。

 tft.fillScreen(TFT_BLACK);  // Clear the screen
 tft.setTextColor(K);
 tft.fillRect(bx0, Y0 + PI * 24, dButtonW, dBH, B);
 tft.drawString("Left", bx0 + PI, Y0 + PI * 24 + 10, 2);
 tft.fillRect(bx1, Y0 + PI * 24, dButtonW, dBH, R);
 tft.drawString("Rotation", bx1 + PI, Y0 + PI * 24 + 10, 2);
 tft.fillRect(bx2, Y0 + PI * 24, dButtonW, dBH, G);
 tft.drawString("RIGHT", bx2 + PI, Y0 + PI * 24 + 10, 2);
 tft.fillRect(bx3, Y0 + PI * 19, rButtonW, rBH, W);
 tft.drawString("Down", bx3 + 10, Y0 + PI * 20, 2);
 tft.fillRect(bx3, Y0 + PI * 14, rButtonW, rBH, M);
 tft.drawString("Reset", bx3 + 10, Y0 + PI * 15, 2);
 drawWall();
 scene = TITLE;
 timer = 0;
}

uint16_t t_x;  // To store the touch coordinates
uint16_t t_y;
bool pressed;
bool jamp = false;

void loop(void) {
 tft.fillRect(0, 0, 30, 14, TFT_BLACK);
 tft.drawString(String(timer, DEC), 0, 0, 2);
 switch (scene) {
   case TITLE:
     tft.fillRect(90, 185, 140, 32, W);
     tft.setTextColor(K);
     tft.drawString("TENOROS", 102, 192, 4);
     tft.setTextColor(R);
     tft.drawString("TENOROS", 100, 190, 4);
     if (timer > 10) {
       tft.fillRect(90, 185, 140, 32, K);
       gStart();
     }
     break;

   case PLAY:
     drawField();
     // Pressed will be set true as there is a valid touch on the screen
     pressed = false;
     t_x = -1;
     t_y = -1;
     if (tft.getTouch(&t_x, &t_y)) {
       pressed = true;
       Serial.print(t_x);
       Serial.print(" : ");
       Serial.print(t_y);
       Serial.println("");
       delay(1);
       if (t_x < dBH * 0.65) {                                   // 0.66=320/480
         if (t_y < dButtonW * 1.5) bRight(bNum);                 // 1.5= 480/320
         if (t_y > bx1 * 1.5 && t_y < (bx1 + dButtonW) * 1.4) {  // 感度に合わせ調整
           countRot++;
           if (countRot > 1) {
             bRot(&bNum);
             countRot = 0;
           }
         }
         if (t_y > 2 * bx1 * 1.4) bLeft(bNum);
       } else {
         if (t_x > (PI + dBH) * 0.6 && t_x < (PI + dBH + rBH) * 0.65) jamp = true;  // 感度に合わせ調整
         if (t_x > (PI + dBH + rBH + PI) * 0.65 && t_x < (PI + dBH + rBH + PI + rBH) * 0.66) scene = RESET;
       }
     }

     if (timer == 0) {
       bNum = nextB5[0];
       nbSet(&bNum, nextB5);
       nbDisp(nextB5);
     } else if (timer % dtimer == 0) {
       int t = rakka(bNum);      // ブロック落下処理
       if (t == -1) timer = -1;  // 次のtimer++でtimer==0がtrueになり、新ブロックの生成落下
       if (t > 0) {
         scene = OVER;  //if (aline[3] > 0)
         timer = 0;
       }
     }
     break;

   case OVER:
     tft.setTextColor(G);
     tft.drawString("GAME OVER", 88, 192, 4);
     tft.setTextColor(R);
     tft.drawString("GAME OVER", 86, 190, 4);
     if (timer > 30) {
       tft.fillRect(80, 190, 160, 32, K);
       gStart();  //scene = PLAY;
     }
     break;

   case RESET:
     tft.setTextColor(G);
     tft.drawString("GAME RESET", 81, 192, 4);
     tft.setTextColor(R);
     tft.drawString("GAME RESET", 79, 190, 4);
     if (timer > 20) {
       tft.fillRect(78, 190, 162, 32, K);
       gStart();  //scene = PLAY;
     }
     break;

   default:
     break;
 }

 timer++;
 if (jamp == true) {
   jamp = false;  // 待ち時間なし
   dtimer = 1;
 } else {
   dtimer = 5;
   delay(machi);  // jamp==false 一定時間待つ
 }
}

 最後までご覧いただきありがとうございました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0