【M5Stack FACES】テトリス操作で下ボタンでの落下速度アップを実現

スポンサーリンク

今回は、M5Stack FACESの記事です。
前回まででテトリスのGAMEBOYカバーでの操作ができる様になりました。
今回は、↓ボタンでの落下速度アップを実現しようと思います。

スポンサーリンク

今回の修正ポイント

落下速度アップを実現するための修正箇所イメージは以下の3点です。
・ ↓ボタンの押下フラグを追加する
・ ↓ボタンの押下判定処理を追加する(長押し中でも判定させる)
・ ↓ボタンが押下フラグが立っている時は落下スピードを加速する
前回のコード解析で、ボタンの押下処理の場所は何となく、分かっていますので、
今回のポイントは、落下処理を何処で行っているか?という所になります。

実装

それでは順番に実装していこうと思います。

押下フラグの追加

まずは↓ボタンの押下処理の追加です。
前回までのコード解析で、押下処理判定で but_*** と言うフラグを使っている事が何となく分かっています。
なので、今回は新たに↓ボタン用のフラグ but_DOWN を追加します。
前回まで作成したコードの21行目に変数の宣言場所がありますので、そこに追加すればOK。

   boolean but_A = false, but_LEFT = false, but_RIGHT = false, but_DOWN = false;

赤字部分が今回の追加コード。
他の変数と同様に、falseで初期化しています。

ボタン押下判定の追加

続いて、↓ボタンの押下判定処理を追加です。
これは、前回までの対応で、keyPodLoop関数で処理している事が分かっています。
今回も同じ様にボタン押下の処理を行いますが、前回と異なるのはボタンが押されている間はずっと判定させる(フラグを立てる)部分です。
前回の修正で、ボタンが押された瞬間にしか反応しない処理を入れていたので、↓ボタン押下だけは押している間はずっと反応する様にします。
修正箇所は107行目のClearKeys関数と109行目のKeyPodLoop関数です。

void ClearKeys() { but_A=false; but_LEFT=false; but_RIGHT=false; but_DOWN=false;}
//========================================================================
bool KeyPadLoop(){
  if(M5.BtnA.wasPressed()){ClearKeys();but_LEFT =true;return true;}
  if(M5.BtnB.wasPressed()){ClearKeys();but_RIGHT=true;return true;}
  if(M5.BtnC.wasPressed()){ClearKeys();but_A    =true;return true;}
  // GameBoyカバーボタンの対応
  Wire.requestFrom(0X08, 1);        // 0x08アドレスから1バイト読み出す要求
  if(0 != Wire.available()) {       // 読み出すデータがあれば処理をする
    uint8_t key_val = Wire.read();  // 1バイトデータを取得
    if (old_key_val != key_val ) {  // 1つ前で取得したキー情報と同じでなければ処理をする
      old_key_val = key_val;  // 取得したキー情報を保持
      // ↑:FE ↓:FD ←:FB →:F7 A:EF B:DF SELECT:BF START:7F
      if(0xFB == key_val){ClearKeys();but_LEFT =true;return true;}  // ← 押下処理
      if(0xF7 == key_val){ClearKeys();but_RIGHT=true;return true;}  // → 押下処理
      if(0xEF == key_val){ClearKeys();but_A    =true;return true;}  // A 押下処理
    }
    if (0xFD == key_val) {   // ↓ 押下処理
      old_key_val = key_val;  // 取得したキー情報を保持
      ClearKeys();but_DOWN =true;return true;
    }
  }
  return false;
}

今回の修正箇所が赤字部分です。
ボタンが押下し続けている間は反応させたかったので、if (old_key_val != key_val){} の処理の中では処理せず、
その外側で1つ前のボタン押下状態に関係なく、毎回、ボタンの判定をする様にしています。

ClearKeys関数の修正は、フラグの初期化をしている部分です。
ここも同時に追加修正しました。

落下処理の修正

最後に今回の最大のポイントとなる、落下速度を上げる部分となります。
この処理をしている場所を探すのは、少しコードを読み進める必要があるのですが…
結果から言うと、修正箇所は128行目のGetNextPosRot関数となります。

void GetNextPosRot(Point* pnext_pos, int* pnext_rot) {
  bool received = KeyPadLoop();
  if (but_A) started = true;
  if (!started) return;
  pnext_pos->X = pos.X;
  pnext_pos->Y = pos.Y;
  fall_cnt ++;
  if (received && but_DOWN) { but_DOWN = false; fall_cnt ++;} // ↓ボタン押下時は落下速度アップ
  if (fall_cnt >= 10) {fall_cnt = fall_cnt % 10; pnext_pos->Y += 1;}
  // if ((fall_cnt = (fall_cnt + 1) % 10) == 0) pnext_pos->Y += 1; // 元のコード(自動落下)
  else if (received) {
    if (but_LEFT) { but_LEFT = false; pnext_pos->X -= 1;}
    else if (but_RIGHT) { but_RIGHT = false; pnext_pos->X += 1;}
    else if (but_A) { but_A = false;
      *pnext_rot = (*pnext_rot + block.numRotate - 1)%block.numRotate; 
    }
  }
}

例の如く、赤字部分が修正箇所です。

このコードの特定は、but_RIGHT などでコード内を検索し、ボタン押下による処理の場所を探しました。
but_LEFTbut_RIGHT が押された場合の処理を見るとわかりますが、pnext_pos->X の値を変化させる事で左右移動を実現させています。
そして、落下もpnext_pos->Y の値を変化させる事で実現しているのですが…
ここで、ポイントとなるのが、“10カウントしたら、1つブロックを下ろす(落下する)”ように作られている所です。
元のコードの下記の部分がそれにあたります。

   if ((fall_cnt = (fall_cnt + 1) % 10) == 0) pnext_pos->Y += 1;

これは、ループの度に処理をしていたら、落下が早すぎてしまうから、スピード調整をしているんですね。
基本は、1ループで1カウントアップする(自動落下)ようになっているので、
↓ボタンが押されていたら2カウントアップする様に修正しています。
ココは元々が1行のif文で記述されているので、少し分かりにくいかもしれませんね。
もし、分かりにくい様なら、処理を1つずつ分解して考えてみましょう。

参考:今回の修正コード

今回の修正もGitHubに上げていますので、参考にしてみてください。
COMMIT : 下ボタンでの落下速度アップを実装

懸念点が…

これで一応落下速度をアップさせる処理ができたのですが…
少し遊んでいると、時々スピードが変わらない様な動きをする時があるんですよね。。。
ハッキリとした原因は未解析ですが、ボタン押下も同時押しは反応しない様になっていますし、
GAMEBOYカバーのボタン反応もイマイチ良くなかったりしますから…
その辺りが何か関係しているのかもしれません。
あまり深くまで探るつもりは無いのですが、少し気になる所ではあります。

おわりに

何はともあれ、一応の落下速度アップの実装はできたのではないでしょうか?
今回は、倍速での落下としましたが、カウントアップ幅を上げる事でさらにスピードアップさせる事ができます。
ぜひ、数値を変更して試してみてくださいね。

次回は…回転・移動ボタンの長押し処理の対応でしょうか?
予定は未定ですが、次回もお楽しみに☆

スポンサーリンク