【#10】~Tスピン判定編~新人プログラマーはテトリスを作れるのか?【C#.NET】

2021.07.26

CATEGORY : C#.NET プログラミング

こんにちは、あんみんどうふです。

今回はTスピンを行ったかどうかの判定を作って、いろいろ応用したいと思います。

現状、回転入れができるだけなのでTスピンをしても特に何もありません
高度なテクニックをきめたのに何も見返りがないのは寂しいので、いい感じに作ります。

先に警告しますが今回の投稿めちゃめちゃ長いです。流し読み推奨です(笑)

 

前回の記事はこちら。

こんにちは、あんみんどうふです。 今回はゲームオーバーの実装…だけだとすぐ終わっちゃうので、ゲームが始まるときのカウントダウンも実装します。 前回の記事はこちら。 https://www.terasol.co.jp/%e3...

全編見たい方はタグからどうぞ。

10-1.準備

まずはTスピンを行ったかどうかのフラグを表す変数を作ります。
判定には「回転した」「Tスピンした」「Tスピンミニした」の3種と、「スーパーローテーションが○パターン目だった」ことを表す数値が必要です。

 

ここで“Tスピンミニ”という単語が出てきました。Tスピンには3+1種類あり、1列で発生する「シングル」、2列の「ダブル」、3列の「トリプル」、そして「ミニ」があります。
Tスピンミニは通常のTスピンとは異なり、壁や床を蹴って行うTスピンを指します。これのシングル(1列消し)は通常のTスピンシングルよりずっと簡単で、画像のように壁や床にくっついて回転するだけでTスピンミニになります。

厳密に言うとミニはTスピンの種類というよりはTスピンの”ボーナス加点”みたいなものです。
壁を蹴りさえすればその時点でミニなので、その状態で1列消せば「Tスピンシングルミニ」、2列消せば「Tスピンダブルミニ」・・・ということになります。

対戦テトリスでは1列消しのミニを総じて「Tスピンミニ」と言っているので、画像右側にある消し方がTスピンミニっていうんだな~ぐらいに覚えておくといいと思います。
ダブルやトリプルはミニしても特に変わらないのでそのままの名前で呼ばれます。

余談ですが、本家テトリスの火力で並べると「ミニ(1列)<シングル<ダブル<トリプル」という順で、最も簡単に作れる分ミニが最弱です。実はミニ自体の火力は”0″なので、攻撃手段ですらありません。
しかしテトリスプレイヤーは時折ミニを使ってラインを消します。この理由は、連続でTスピンやテトリスを行うと発生するボーナス「Back To Back」を継続させるためです。
Back To Backが発生すると火力ボーナスとして1列分のダメージが追加されるので、これを目当てにミニで消すプレイヤーが多いわけです。

 

変数の準備はできたので判定の仕組みについて解説します。

以下の条件をすべて満たすことででTスピンを行ったことになります。

・現在操作しているミノが「Tミノ」である
・設置したタイミングで最後の操作が「ミノの回転」である
・Tミノの周囲4マスの空間のうち、3マス以上が壁やミノで埋まっている

Tミノの周囲4マスの空間はこのことです。

この空間が3つ以上埋まっている必要があります。

これらの条件を満たした上で列を消すと、シングル・ダブル・トリプル・ミニ、といったように消した列数や消し方によってTスピンの種類が決まります。

 

10-2.フラグ管理

回転を行ったフラグを立たせるためにminoTurnメソッドに追記します。
書く場所はどこでもいいと思いますが、dirの値を変えた直後が不具合なく確実だと思うのでそこに書きます。

(わかりづらいですが、17行目の「useSpin = true;」です)

 

移動したら回転フラグをfalseにします。そのままにしていると最後の操作が「移動」ではなく「回転」になってしまうので・・・。
移動を司るメソッドminoMovingに追記します。

minoMoveCheckのif文の中に書かれていればオッケーです。移動に失敗した場合フラグはそのままにします。

 

次にスーパーローテーションのパターン数を数えます。
minoSuperRotationメソッドの最初に追記し、変数を初期化させます。

 

そして同一メソッド内の「Iミノ以外」のif文にあるミノ重複チェック(minoDuplicateCheck)の手前に追記します。
全部で4回チェックしているので、4つすべてに追記です。

(「lastSRS++;」をif文の前に追記するだけなので他3回分のコードは省略します)

 

これで回転したかどうかの判定や、スーパーローテーションの到達パターン数を数えることができるようになりました。
到達パターン数は後のTスピンミニの実装で使います。

 

10-3.Tスピン判定

新規でminoTspinCheckメソッドを作り、以下のコードを書きます。

これを実行するためにminoTurnメソッドの最後に追記します。
操作中のミノがTミノであれば呼び出します。

Tスピンの判定だけはこれで完成です。現状、テストする術がないのでモヤモヤが残りますが・・・。

 

10-4.Tスピンミニ

通常のTスピン判定はできたので、次にTスピンミニの判定です。

Tスピンミニとしてみなす条件は以下の通りです。

Tスピンを成功させる
・埋まっている空間の数が「3つ」であり、その位置がTミノの土台側に2つ凸型の方に1つである
・スーパーローテーションの到達パターン数が「4以外」である

2つ目の条件についてですが、例えば回転後のTミノが上向きだと下2つと上のどちらか1つの空間が埋まっている必要があります。

これが右向きだと左2つと右1つ、左向きだと右2つと左1つ、といった感じです(下向きは多分Tスピンミニ自体できないので無いです)。

 

また、先程スーパーローテーションの所に追記した変数も使います。「4パターン目以外」が条件なので、lastSRSの値が4未満であればオッケーですね。

これらの仕様をminoTspinCheckに書き起こして追記します。

判定は空間が埋まっているかどうかを0と1で決めて、結合した文字列で比較する方法が一番楽だと思いました。
ミニとしてみなされるパターンを向き毎に用意して比較しています。

 

10-5.結果を表示させる

Tスピンしたことをわかりやすく表示させます。
本家でもTスピンしたら「T-Spin ○○」みたいに出てくるので、そんな感じにしてみます。

デザイナーを開き、pictureboxを適当な所に配置します。nameは「statusMessage」にでもしておきましょうか。

 

この領域に2秒間だけ表示させたいのでタイマーを使います。ツールボックスからTimerをフォームに持ってきて、nameを「statusViewTimer」にし、Intervalを「2000」にします。
このIntervalは○秒経ったら××するの部分です。2000ミリ秒=2秒です。

もう一つTimerを作成し、nameを「statusAnimation」にします。Intervalを「20」にします。
これは先程の××の部分で、20ミリ秒=0.02秒ごとに処理が行われます。

 

次に変数を用意します。いつものグローバル変数の部分に追記します。

今回は前に作ったゲームオーバーの演出のように、領域を移動させたいと考えています。
変数で管理せずに移動し続けるとそのままどこかへ行ってしまうので、初期位置用の変数を用意しました。

次にその初期位置を決定するため、Loadイベントに追記します。
(Loadイベント内であれば書く場所はどこでもいいです)

Load時に先程作成したpicturebox「statusMessage」の座標を取得しています。
これで変数の値から初期位置を呼び出せるようになりました。

 

表示の処理に移ります。
新規メソッド「statusView」を作成し、以下のコードを入力します。

メソッドが呼び出されたら透明度・位置を初期化してからタイマーを開始します。

 

各タイマーのTickイベントにコードを書きこみます。
まずは「statusViewTimer」から。2秒立つとタイマーがストップし、表示されていた文字が消えます。

 

次に「statusAnimation」です。0.02秒ごとに実行され、ここで文字を描画する処理を行います。

ざっくり要約すると、中央揃え青い文字で描画し、処理を行うたびに文字を薄くしています。

 

ここまで非常に長いですが、あと少しで終わります。
minoDropメソッドに追記します。

設置した時にTスピンのフラグが立っていれば「T-Spin」と表示させます。ミニの条件を満たしていれば更に「Mini」と表示。

 

デバッグモードで土台を作ってテストします。

フィールドの左隣に文字が出てますね!
Tスピンの判定もうまくできてるので今回の分はこれで完成です。

長かった・・・。

 

次回はスコアを実装します。ゲームといえばこういう要素がモチベーションになりますよね。
Tスピンをしたら高得点、パーフェクトクリアしたらもっと高得点!みたいに作りたいと思います。

#11 スコア実装編へ続く。

こんにちは、あんみんどうふです。 今回はスコアを実装します。やはりゲームにはこれが無いとやりがいがありませんね! 前回の記事はこちら。 https://www.terasol.co.jp/%e3%83%97%e3%83%a...