HOME > ActionScript > テトリスアルゴリズム > テトリミノの回転

テトリミノの回転

回転の理屈

テトリミノを左右と下に動かす事が出来るようになったので、次はテトリミノを回転させます。
回転動作に使用するキーはアローキーの上です。実のところ、テトリミノを動かす理屈を理解していいれば全然難しい事はありません。

ソースファイル pt4.zip

移動の場合はキー操作に合わせて「位置情報」を更新してフィールドの再描画を行っていましたが、回転動作の場合は位置情報の更新は行わずに、落下中のテトリミノのパターンデータ配列の要素そのものを90度回転した状態に入れ替えてフィールドデータに反映→フィールドの再描画を行うというプロセスになります。

プロセスとしては途中の経由が違うだけで移動の処理とほぼ同じですが、移動の場合と同様にアタリ判定を行ないます。回転の場合のアタリ判定の処理は、移動の場合とは少しだけ手法が違うのでそれについて触れていきます。
また、回転動作が加わる事である問題が起こるようになりますので、その問題についての対処もしていきます。

回転時のアタリ判定

アタリ判定のプロセス

移動時のアタリ判定の処理の場合は、移動する前に障害物などの探索を行い、移動して良いかどうかを判断してから移動の処理を行いました。回転の場合はアタリ判定の処理を行う為に一度実際にテトリミノのパターンデータを回転させてしまいます。と言っても、落下中のパターンデータ配列をいきなり回転させてしまうのではなく、一度パターンデータ配列のコピーを作成してからその複製を回転させてシミュレートを行うと言う手順になります。

この「一度実際に回転させてシミュレートする」という考え方は、「Windowsプログラミング研究所 別ウィンドウが開きます」さんの公開している方法を参考にしています。なるほどなぁという感じで、他にも色々方法は考えられますが、個人的には一番わかりやすい方法で、回りくどいようでいて実は割と処理も速い方ではないかなと思っています。
ただ、これは一番シンプルに再現した場合の考え方なので、テトリスを色々とプレイされている方でしたら解ると思いますが、現在のテトリスの回転動作は非常にトリッキーなアルゴリズムを実装されています。なのでこれを刺激にして色々と拡張や他の方法を考えて欲しいというのが「Windowsプログラミング研究所 別ウィンドウが開きます」さんの意図じゃないかなと勝手に私は受け止めています。

シミュレート

回転のシミュレートを行う関数はgetRotateHit()関数です(main.asファイル 396行目)。キーイベントのリスナー関数に呼び出されて、回転のシミュレートを実行します。回転後のシミュレート結果で何か障害物にぶつかると言う事が判った時点で「真」を返します。真が返ってきた場合はその後の処理は行わず、偽が返ってきた場合にはコピーではないホントのパターンデータ配列を回転させてフィールドデータに反映しフィールドの再描画を行うという流れです。

コピーしたパターンデータ配列を走査していき、テトリミノコードが入った要素を検出したら、その部分がフィールド上のどのセルに相当するかの座標を算出し、フィールドデータの要素を参照します。その参照したフィールド上のセルに何か障害物があれば真を返し、何もなければ偽を返して終了します。
移動の場合は「隣のセルに何かあるかどうか」でしたが、回転の場合はダイレクトに「重なるかどうか」を調べます。その辺りの手法こそ違いますが処理の流れ的には同じだとわかると思います。

フィールドデータの更新

何も障害物がないとわかった場合にはホントのテトリミノパターンデータ配列を回転させてデータの状態を確定し、あとは移動処理と同様にフィールドデータの更新へ移行しますが、回転の場合も現在フィールド上に反映されているテトリミノのパターンデータを削除するのを忘れてはいけません。
削除するタイミングは回転できる事が判って、ホントのパターンデータを回転させる前に実行しておきます(main.asファイル 269行目)。

問題点

さて冒頭でも触れましたが、回転の動作が加わる事である問題点が出てきます。その問題点とは割と限定的ではあるのですが、プログラムが停止してしまう程の問題点です。とは言え「限定的」と言うだけに、原因となる要素と場所が判りやすい為対応も簡単です。

位置情報がマイナスになってしまう

テトリミノのパターンデータの性質を理解されていると気が付くと思いますが、実は棒形テトリミノが縦になった時の状態には二つのデータパターン状態が存在します(横の状態も2パターン)。下の図の様な感じの2種類です。

問題が起きるのは棒型のパターンデータ配列が、上の図の右の状態(正方形の中心より右寄り)になった場合で、その状態の棒型テトリミノが左の壁に近付いた時に限り不具合が発生します。
具体的な原因はその状態の棒型テトリミノを壁に密接しようとした場合に、移動情報のx値がマイナスになってしまう事が引き金になっています。

マイナスになってしまうと、それ以降でフィールドデータ配列の更新を行う際に「-1はインデックス ムニャムニャの範囲では~」と油断していると割と良く見るエラーが返ります。これは単に配列のインデックスに負数を指定してアクセスしようとしたからで、処理的にはエラーが返って来て「ああ、って事はちゃんと動いてるんだ」という事がわかります。

位置情報がマイナスになってしまう

正しく動いているとしてもプログラムが止まっては仕方ないので対処します。対処方法は色々考えられますが、その時点でのテトリミノのパターンデータ配列の幅を狭める方法をとりました。具体的には二次元目の配列長を要素一つ分短くします。
問題になる症状は「位置情報がマイナスになる」事で、その原因も「棒形テトリミノの特定状態で左の壁に密接する時」と限定できますので、割り切ってピンポイントな評価で対応用のメソッドを用意します。

対応用のメソッドはsizeReduction()とrestoreSize()(main.asファイル 305~335行目)です。
sizeReduction()は位置情報のx値がマイナスになった場合にパターンデータ配列を縮小します。
対してrestoreSize()は、位置情報のx値が1の時にパターンデータ配列の一次元目と二次元目の配列長が違う場合、パターンデータ配列を復元する関数です。実際にはrestoreSize()は、sizeReduction()が実行された次の動作で右移動の処理が実行されない限り実行されません。違う言い方をしますとsizeReduction()が実行された次の動作で右移動が実行された直後に一度きり実行されるような構成になっています。

動作確認

下の画面でテトリミノが動かない時はFlash画面を一度クリックしてみてください。

これで左右と下移動、回転動作の実装が完了しました。あとはテトリミノを固定して、消して…といきたいところですが、回転動作にまだちょっと違和感があります。次はこの違和感を無くすために回転動作に補正処理を実装します。

それとテトリスのアルゴリズムとは直接関係が無いので詳しく触れませんでしたが、二次元配列を90度回転させる処理についてです。要素を操作するこの処理には一定の法則があります。複雑そうに見えて理屈が判ってしまえば反時計回りに90度回転なども簡単にわかると思います(実際には90度回転と言うのはあくまでイメージなのですが)。
使用する機会は割と限定されますが、こういった配列操作の法則は覚えておくと便利ですので興味がわいた方は法則を見つけてみてください。

Flashファイルをご覧いただくためには、
アドビシステム株式会社のフラッシュプレーヤー(Flash Player)が必要です。
インストールされていない方は下のボタンから、最新版が無償で入手できます。

Adobe Flash Playerのダウンロード

ソースファイルについて

ソースファイルはasファイルのみです。
今回も前回の処理部分は幾つか変更しました。気になる場合は前回のソースと比較してみて下さい。

使用する環境としてはFlashIDE(動作確認はSC4のみ)を想定していますので。適当に用意したflaファイルに、ダウンロードしたソースファイルをドキュメントクラスとして適切に設定すれば問題無く動作します。
また、コーディングはFlashDevelopを使用して行っておりますので、プロジェクト内にファイルを適切に配置、もしくはクラスパスを設定するなどすればFlashDevelopだけでも問題なく動作します。Stageサイズは幅、高さともに500pxです。
申し訳ありませんが、ご質問等にはお答えできませんので、ご使用は環境に合わせて各自行ってください。

TOP