0
0

70歳の挑戦... タッチ機能は諦めて、キー入力でブロック操作することに

Posted at

 前回の続きです。

せっかくSTM32F103C8T6(with 128k,Bluepill)から自作テトリス風ゲームが動かせるようなので、タッチ機能で操作できないかと悪戦苦闘しました。しかし、出来そうにありません。諦めてシリアル通信に変更、一応完成させました。ついでにArduinoIDEのToolsで2点ほど試しました(右下の写真参照)。

1.CDC(Communication Device Class)を用いたシリアル通信
2.Optimize: "Fastest(-O3) with LTO"

F103_Tenoros.jpg

1により別途USBシリアルモジュールが不要になります。2は微妙ですが、2~3%程速くなってると思われます。スケッチにおけるシリアル通信操作は以下のようにしました。

      if (Serial.available())
      {
        char c=Serial.read();
        if(c== 'a'){ bLeft(bNum);
        }else if(c == 'd') {bRight(bNum);
        }else if(c == 's') {bRot(&bNum); // bNum と&bNum の違いに意味はありません
        }else if(c == 'z') {jamp=true;
        }else if(c == 'x') {scene=RESET;}
      }

こちらの方がブロック操作は楽でした。特に「Tera Term」であればリターンキーを押さなくても逐一、キー送信してくれるので楽です。
 ピンの接続です。

TFT SPI BluePill
LED 3.3
TFT_SCK PA5
TFT_MOSI PA7
TFT_DC(RS) PA2
TFT_RESET PA3
TFT_CS PA4
GND G
VCC 5V

 TFT_eSPIライブラリでの「User_Setup.h」とAeduinoIDEのスケッチを以下に載せます。

User_Setup.h
#define USER_SETUP_INFO "User_Setup"

// Define STM32 to invoke optimised processor support (only for STM32)
#define STM32

#define ILI9488_DRIVER     // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)

// ######       EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP        ######

#define STM_PORTA_DATA_BUS
// The TFT can be connected to SPI port 1 or 2
#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
#define TFT_MOSI PA7
#define TFT_MISO PA6
#define TFT_SCLK PA5

#define TFT_DC   PA2 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
#define TFT_RST  PA3 // Reset pin to TFT RST (or RESET)
#define TFT_CS   PA4 // Chip select control pin to TFT CS

#define TOUCH_CS  PA1     // Chip select pin (T_CS) of touch screen

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
//#define SMOOTH_FONT

// ##################################################################################
//
// Section 4. Other options
//
// ##################################################################################

#define SPI_FREQUENCY  18000000
#define SPI_READ_FREQUENCY  10000000

#define SPI_TOUCH_FREQUENCY  1000000

タッチ機能の部分は実際には役に立っていません。次にスケッチを示します。

F103_Tenoros.ino
F103_Tenoros.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,
       RST };  // 各シーンを定める定数
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);
  }
  Serial.println("New Block");
}

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 で新ブロック生成、落下が始まる
  Serial.println("New Game Start");
}

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 (Serial.available())
      {
        char c=Serial.read();
        if(c== 'a'){ bLeft(bNum);
        }else if(c == 'd') {bRight(bNum);
        }else if(c == 's') {bRot(&bNum);
        }else if(c == 'z') {jamp=true;
        }else if(c == 'x') {scene=RESET;}
      }

      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);                 //jamp = true; // 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);
      Serial.println("GAME OVER");
      if (timer > 30) {
        tft.fillRect(80, 190, 160, 32, K);
        gStart();  //scene = PLAY;
      }
      break;

    case RST:
      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 一定時間待つ
  }
}

数百円のマイコンボードなのに結構遊べます。最後までご覧いただき有難うございました。

0
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
0
0