C++でつくったテトリスの完成品

これまでC++で作成してきたテトリスに機能を追加します。テトリスにハードドロップといってキーを押すと一瞬でテトリミノを着地させることができます。またハードドロップさせた場合、どこにブロックが配置されるのかを示すゴーストを表示させるタイプのものもあります。

そこで今回はゴーストとハードドロップの機能を実装することを目指します。

ハードドロップの実装

まずどのキーをおせばハードドロップさせることができるかを決めなければなりません。テトリスのガイドラインではスペースキーが当てられています。ここでもそれに従うことにします。

Tetrisクラスのメンバ変数にHardDrop関数を追加し、スペースキーが押されたときにこれが呼び出されるようにします。

MainWindow.cpp

Tetrisクラスにもメンバ関数を追加しなければなりません。以下の関数を追加します。

Tetris.h

ではどのような処理をすればよいでしょうか? いまそのままテトリミノを落下できるところまで移動させるとどこまで移動できるのかを考えます。この位置はゴーストを表示すべき位置でもあります。

そこで先にテトリミノをどこまで落下させることができるかを調べる関数をつくります。それがGetHardDropCount関数です。

Tetris.cpp

スペースキーが押されたらGetHardDropCountで現在のテトリミノは何段落下することができるのかを調べ、その分だけ下に平行移動させます。そしてハードドロップを実行したらそのままテトリミノは固定されてしまうので、FixBlocks関数を実行します。

ゴーストを描画する

次にゴーストを描画するための処理ですが、これはTetris関数のメンバであるDraw関数の最初にゴーストを描画するための処理を追加します。落下中のテトロミノとゴーストが重なってしまう場合もあるので、先にゴーストを描画してそのあと落下中のテトロミノを描画すればトラブルはおきません。

DrawGhostBlocks関数ではゴーストを描画すべき位置を取得してその場所にゴーストを描画します。ゴーストを描画すべき位置はGetGhostBlocks関数で取得します。

GetGhostBlocks関数では現在のテトリミノの位置を取得したあと、GetHardDropCount関数でどこまで落下することができるのかを調べて、そのあとm_rowをそれだけ増やしたBlockの配列を返します。このときテトリミノの色も取得しておきます。ゴーストを表示するとき表示色も必要だからです。

ゴースト用の色をつくる

ゴーストを表示する場所ともとの色がわかったらあとは表示させるだけです。この処理はDrawGhostBlock関数でおこないます。ゴーストはテトロミノよりも目立たない色で描画したいので新しくGetGhostColor関数を作ります。

GetGhostColor関数ですが、こんな感じになっています。テトリミノの元の色よりも黒に近い色にしています。

それからゴーストを描画するということは再描画すべき部分が増えることを意味しています。再描画の処理によってチカチカすると目立つのは外枠のブロックです。そこでフィールド内部のブロックが多少チカチカするのは仕方ないということにして以下のように譲歩します。外枠ではなくその内部だけを再描画の対象としています。これだけでもチカチカをかなり抑えることができます。

スコアの表示

それからスコアも表示させたいと思います。

得点ですが、これを参考にしました。

テトリス ~げーむのせつめいしょ

これによると1列だけ消した場合は40点、2列同時に消した場合は100点、3列になると300点、そして4列同時に消した場合は1200点です。1列ずつチマチマ消してもたいした点数になりませんが、Iミノをぶっ込んで4列同時に消すと大量得点をゲットすることができるというわけです。

それからラインを消せない場合でもドロップ得点というものがあります。高いところから落とすとそれだけ大きな点数を得ることができるのです。↓キーを押してドロップする場合とハードドロップでは得点に差をつけているゲームもあります。そこで↓キーを押したままにして急速落下させた場合は1段あたり1点、ハードドロップの場合は高さの2倍の得点にすることにします。

まずスコア表示のためのメンバ変数とメンバ関数を追加します。

それからTetris::Draw関数にShowScore関数を追加します。

得点したらm_Scoreを増やす

あとは必要なときにm_Scoreを増やしていけばOKです。

まずハードドロップのときはウィンドウ全体を再描画しているのでスコアが変化すると自動的に表示もかわります。

ところがソフトドロップの場合は、チカチカを防止するため、ウィンドウ全体を再描画するのではなく灰色のブロックで囲まれた枠内だけを描画しています。これではスコア部分が再描画されないので、別途スコアが表示される領域を更新する処理を追加しています。

ブロックライン得点はブロックが消えて上の段のブロックが落ちてきたときに点数加算の処理をしています。

スコアを表示させるだけでずいぶんそれっぽいものになります。