これまでは上から落ちてきたテトリミノが床やブロックに接すると機械的に固定させていました。今回はこの部分を変更させます。

テトリス(tetris)のガイドラインを理解する – Qiitaのロックダウン(設置判定)によると

上から落ちてきたテトリミノは底面が床やブロックと触れても直ちに設置されるわけではありません。0.5秒間なにも無ければ設置されます。言い方を変えると0.5秒のあいだに回転や移動をさせることが可能なのです。しかも0.5秒のあいだに回転や移動をするとそのときからさらに0.5秒の猶予が生まれます。

これだけだと回転させ続けることで無限に設置しないこともできるので回転や移動には制限があります。回転と移動が計15回行われると猶予なしでそのまま設置されます。底面が触れてない場合であれば回転・移動の回数に制限はありません。

15回という制限はミノが1ブロック落下するとリセットされます。ただし回転で上昇しても位置の最低値が更新されないとリセットされません。

このようになっています。

そこでこれに対応させます。

ミノが下に移動したら着地しているかどうか調べます。着地しているのであればタイマーをセットして0.5秒後に固定させます。タイマーがセットされている最中に移動や回転がおこなわれたらタイマーをセットしなおします。

これまではミノを下に移動させるときはこのようにしていました。移動させようとしたときにすでに着地しているのであれば固定させる処理をしていました。

これを移動させたあと着地しているかどうかしらべて別のタイマーをセットして500ms経過後にTetoroDownedメソッドを実行することにします。

変更されたMoveDownTetoroメソッドを示します。

着地しているか調べて着地しているのであれば自作メソッド SetSubTimerIfTetoroDownedでタイマーをセットします。また移動や回転させることで着地していないものが着地することになるので、基本は下に移動させてからタイマーをセットするのですが、移動前と移動後に2回調べています。

IsTetoroDownedメソッドは着地しているかどうか調べるためのメソッドです。下に移動させてみて他のブロックに当たったりフィールドの外に出る場合は移動不可ということになります。CanRotateメソッドをつかって判定していますが、CanRotate・・・名前の付け方がよくない・・・

SetSubTimerIfTetoroDownedはタイマーをセットするためのメソッドです。「着地してから500ms、ただしそのあいだに移動や回転がおこなわれた場合はリセットされる」というルールなので、すでにTimerオブジェクトがあるときは停止させてからセットし直しています。

500ms間なにもなければイベントハンドラSubTimer_Tickが実行されます。

移動や回転のときは500msの猶予がリセットされるのでSetSubTimerIfTetoroDownedメソッドを呼び出しています。メソッドのなかでミノが着地しているかどうか調べてタイマーをリセットします。