/*******************************************************************************
DTETが目指すもの
2005.10.31 Mihys
*******************************************************************************/
#include <tetris.h>
/*
DTETの公開を終了し、今後テトリスに対する想いが
薄れてしまう前に、自身の経験や考え、伝えたいこと等を
簡単に書き留めておこうと思う。
以下の文章は経験に基づいて書いたとはいえ、
主観的な見解や飛躍した表現を免れない部分もあるがご了承いただきたい。
*/
class Consumer : public Tetris{ // 家庭用テトリスに見られるセンス
private:
ゲームには必ず長所と短所があるはずである。
それらを正しく見極めていきたい。
DTETに取り入れたいくつかのシステムは、
以下に紹介するテトリスの影響を少なからず受けている。
public:
PC98版BPSテトリス();
マジカルテトリスチャレンジfeaturingミッキー();
テトリス64();
テトリスDX();
初代GBテトリス();
};
Consumer::PC98版BPSテトリス()
{
テンキーで移動と回転を行い、スペースキーで瞬間落下させ、
「落下で即固定され、固定直後すぐに次のブロックが操作可能」となる。
このシンプルで短いサイクルが、慣れると意外にクセとなる。
このゲームをプレイして高速操作にハマったといっても過言ではない。
}
Consumer::マジカルテトリスチャレンジfeaturingミッキー()
{
今までに市販やアーケードの様々なテトリスをプレイしてきた。
その中で、DTETを作るきっかけの1つとなったのは、
「マジカルテトリスチャレンジfeaturingミッキー」だ。
対戦モードもエンドレスもまんべんなくプレイしたが、
あるとき、エンドレスモードの方で妙な違和感を覚えた。
演出が控えめだからか。それとも、相手からの攻撃がないからか。
否、それよりも決定的な要素は、
「複数のNEXTの有無」という点であった。
正確にはブロック横取りを目的としたシステムではあるが、
前半のステージでは対戦相手のスピードが遅いので、
実質的にはNEXTが2つあるということになる。
これまで、エンドレスよりも対戦の方が
ブロックをサクサクと置けていたが、どうりで
相手にNEXTを横取りされたときに考えが一瞬止まるわけだ。
無意識のうちに、NEXTを2つ見る習慣が出来ていたようだ。
ここで感じた。
「スピードの向上のためには、プレイヤーの腕だけでなく
複数のNEXT表示というシステムも不可欠なのではないか」と。
}
Consumer::テトリス64()
{
基本的な要素は初代セガテトリスと同じだが、
通常モードの回転入れはなかなか面白い。
また、ぷよぷよのクイックターンのような
「ダブルターン」(180度回転)も設定で可能であり、
オフセットターンと組み合わせるとバラエティに富んだ回転入れが出来る。
しかし、そもそもこのゲーム自体の難易度が高いわけではないので、
通常の操作でも充分プレイ可能なのだが、
落下速度がもっと速ければ有意義であったに違いない。
もうひとつ特徴的なのは、「消去中にも次のブロックが動かせる」という点。
一般的にブロックの消去中というのは、点滅なりフェードアウトなりの演出があり
その間は操作を受け付けない状態になるが、
このソフトでは並列動作のごとく消去の処理と操作の処理が
同時に行われ、実に新鮮であった。
ほとんどのプレイヤーにとってはどうでもよいことかもしれないが、
このような小さな工夫の積み重ねがゲームバランスを左右する要素であり、
重要だと考える。
}
Consumer::テトリスDX()
{
Aボタンで右寄りの回転、Bボタンで左寄りの回転。
たとえ棒やS字、Z字等の、本来2通りしかない回転パターンでも、
押すボタンによって結果が異なり、
状況に応じて使い分ければ操作の手数を減らすことが十分に可能である。
また、ブロックの出現直後は上空で留まっているが、
「移動や回転の操作を行うことで」落下が開始される。
これなら初心者には考える時間が少し与えられ、
上級者はノータイムでブロックを積む事が出来るようになっている。
欲を言えば、秒間フレーム数が30ではなく60であれば嬉しかったのだが、
確実に多くのプレイヤーを満足させられるシステムであることは間違いない。
}
Consumer::初代GBテトリス()
{
「横移動の押しっぱなしがほとんど使えない」という理由で
操作性が悪いという意見もあるかもしれないが、
このソフトにも見習うべき点がある。
それは、「横移動の先行入力システム」だ。
たとえば、レベルハート9では
「ずらし入れ」のタイミングが難しいと思うかもしれないが、
着地する少し前から「壁に擦るように」横キーを押しっぱなしにしていれば
多少アバウトなタイミングでも成功する。
このシステムは製作者が意図したものなのか、
あるいは単なる偶然に出来上がったのかは分からないが、
非常に将来性のあるシステムだと言える。
しかし、後継ソフトであるテトリスDXでは
残念ながらこのシステムが取り入れられていない。
ちなみにテトリスプラスやテトリスTGMシリーズでは、
ブロック出現時に限って先行入力が可能となっている。
}
class DTET : public Tetris{ // DTETが目指すもの
private:
DTETの製作のコンセプトは、テトリスとしての基本を保ちつつ
完成度を高めるにはどうすればよいかという考えが原点である。
今後、テトリスがますます「パズルアクションとして」
質が高く、ブランドに左右されないゲームに進化する事を望んでいる。
public:
マルチNEXT();
レベルとスピード(); // 執筆予定
スコアシステム();
回転法則();
回転入れ();
先行入力();
ブロック出現時();
ミス判定(); // 執筆予定
対戦とネットワーク(); // 執筆予定
横移動(); // 執筆予定
};
DTET::マルチNEXT()
{
複数のNEXT表示は、実装自体は簡単である。
しかし、このシステムが必要であると考え付くまでに
多くの経験を要する。
ピアノやタッチタイピングで習得する運指のように
複数のNEXTを見て判断するにはトレーニングが必要である。
このシステムが実際に高速操作の助けとなるかを判断するためには、
マルチNEXTである程度の練習した後にNEXTを1つのみでプレイしてみるのが良い。
おそらく普段どおりのスピードで積んでいく事ができず、
かなりの違和感が生じるはずだ。
最低でもNEXTは3つ以上が望ましい。
}
DTET::スコアシステム()
{
DTETのスコアの計算の基準は、運要素が少なく、フェアであることを目指し、
「バランスがよく、計算方法が明快」になる事を前提に考えた。
まず、多段消しで高得点になることは当然であり、
1段消し40点、2段消し100点、3段消し300点、4段消し1200点と定義し、
これにレベルの値を乗算する。
問題は「連続消し」の計算方法をどうするかという点にある。
もちろん、単発で消すよりも連続で消した方がボーナスを多くしたいのだが、
マジカルテトリスのごとくコンボ重視の積み方が明らかに4段消しに勝る
というのも考え物だ。
そうなると、連続消しボーナスの比率はコンボ数と
およそ線形となるような関係がちょうど良いかと思われる。
ところが、まだ疑問が残っている。例えば、
「4段消し → 2段消し → 1段消し」のコンボと、
「1段消し → 2段消し → 4段消し」のコンボと
どちらのボーナスが多くなるようにすれば良いか。
これはブロックの順序も関係してくるので、
地形の準備も含め、前者のコンボの方が簡単であろう。
しかし結局のところ、両者のボーナスの比率に差を生じさせると
運によって左右されてくる危険性が高まる。
こうして、吟味の結果
「(コンボ中に取得した素点)×(1+コンボ数)÷2」
という計算方法を採用し、
コンボ中の消去段数の順序に依存することのないシステムとなった。
}
DTET::回転法則()
{
まず回転法則は、
X座標に関してはテトリスDXのように回転方向による軸のずらしを採用し、
Y座標に関してはテトリス64のように「転がし」が容易なパターンを採用。
次に180度回転については、DTETの製作開始前から
「右回転ボタンと左回転ボタンを同時押し」という考えが浮かんでいた。
しかし、一言で同時押しといっても、
常に完全に同じタイミングで両ボタンが押されるとは限らず、
もちろんタイミングがずれる事もあるはずである。
さらに、どちらのボタンが先に押されるかという事も考慮しなければならない。
これを解決するためには、ゆっくり操作する状況をイメージすれば、
「右回転ボタンが押された状態で左回転ボタンが押されたら、
その左回転ボタンは右回転の役割を果たす」および
「左回転ボタンが押された状態で右回転ボタンが押されたら、
その右回転ボタンは左回転の役割を果たす」
という仕様を思いつく。
ここで、「回転をした後にすぐに逆回転をして戻したい」という場合、
ボタンを離してからもう一方のボタンを押さないと
元の回転角に戻せず、180度回転になってしまうので、
通常よりも操作スピードが不利になる事が考えられる。
しかし全体を通してみれば、回転後に元に戻す状況の回数よりも
180度回転させる状況の方が明らかに多い。
}
DTET::回転入れ()
{
回転入れのアルゴリズムは、上級者向けのテトリスであるためには
注意を払って考えなければならない。
通常の回転で、明らかに直感的に考えられない転がり方をしてしまったら
プレイヤーに違和感を与えてしまう。
なおかつ、テクニックを覚えたプレイヤーが
積極的に回転入れを活用していけるようなバランスが必要である。
考えるべき事は、
「回転後のブロックが地形と重なる場合、どの方向に逃がせばよいか」
という点だ。
たとえば、「右にずらすか左にずらすか」という場合を考えるとする。
当然、右にずらしても重なる場合は左にずらすようにするのだが、
どちらにも可能な場合は、どちらを優先するかを考えなければならない。
回転法則のX座標の考えと同様、
できるだけ右と左の差別がない壁蹴りを考えたい。
DTETは、ブロックを転がすというイメージに基づき、
「右回転で地形と重なる場合は、右に転がすイメージとし、1マス右にずらす」
ならびに
「左回転で地形と重なる場合は、左に転がすイメージとし、1マス左にずらす」
という動作を適用した。
しかし、自然な壁蹴りを優先させるとはいえ、これだけでは
「右回転で1マス左にずらす」「左回転で1マス右にずらす」
という動作を捨てなければならない事になる。
出来ればこちらのケースも含み、これらの4パターンに対応させたい。
「回転ボタンをさらに2つ増やす」という方法もあるが、
そのためだけにプレイヤーにボタンを4つ使わせるのは望ましくない。
ではどうすればよいか。
ここで、回転法則が4パターンある事を思い出してみる。
「[A]右回転」「[B]左回転」「[C]左回転+右回転」「[D]右回転+左回転」
この中で、[A]と[B]はすでに適用してしまったが、
[C]と[D]はまだ使用可能な状態であり、適用できる。
以上を含め、ブロックをずらすために地形の判定を行う順序は、
「右回転ボタン」、または「左回転ボタンを押した状態で右回転ボタン」の場合は
「ニュートラル → 右 → 左 → 下 → 右下 → 左下」、
「左回転ボタン」、または「右回転ボタンを押した状態で左回転ボタン」の場合は
「ニュートラル → 左 → 右 → 下 → 左下 → 右下」
というアルゴリズムに決めた。
}
DTET::先行入力()
{
ブロックの移動や回転の操作で地形にぶつかる場合、当然ブロックは動けない。
ソフトによってはブロックが動けない場合に効果音を鳴らすものもあり、
それは「今の操作は無効である」とプレイヤーに伝えるものなのであろう。
しかし、ただ一言で「無効だ」と終わってしまうのは少々味気ない。
その時にプレイヤーが「ブロックをどう動かしたかったのか」を
検討してみても良いのではないか。
考えられる理由として、
「回転入れに失敗した」
「押すタイミングが早すぎた」
等の状況が挙げられる。
前者ついては、本当に入らない隙間に入れようとしている場合は仕方がない。
しかし、後者については少しの工夫で解決することができる。
それが初代GBテトリスにも採用されている先行入力機能だ。
実現するためにはどうすればよいか。
一般的には「操作完了フラグ[A]」を用い、
「キーが入力されている場合、
操作の成功か失敗かに関係なく操作完了フラグ[A]を立て、
キーが入力されている限り[A]が解除されない」
という既成概念があるが、この[A]を立てる条件を
「操作に成功した場合に限り」としてやるだけで完成である。
つまり、ブロックが動けない場合は「見て見ぬふり」をすれば良い。
こうすることで、押すタイミングが早すぎても慌てずに済み、
このシステムを知っているプレイヤーはあらかじめ押しておくことで
操作の高速化を図ることができるし、
横穴等にブロックを確実にはめ込む事も可能となる。
少なくとも移動と回転についてはこのシステムを適用する際に
デメリットはおそらく生じないはずである。
ただし、他の操作にもそのまま適用するには注意が必要だ。
たとえば、「ブロックを固定」する操作について考える。
自然落下の速度が最大でプレイヤーがブロックを固定させようとしている時、
操作が遅れて、自然固定の直後に固定キーを押してしまう状況があるとする。
固定時間と出現時間が共に短い場合には特にあり得るケースである。
ここで先行入力が可能になっている場合、固定キーを離さないと
「次のブロックを操作する前に即固定される」という現象が発生してしまう。
これを解消するために、「固定操作には先行入力を適用しない」という方法はある。
しかし、そうなると今度は高速に操作する上級者プレイヤーにとって
大きな障害となってしまう。
中級者と上級者、両方の満足を得るためには
「操作の遅れか、先行入力か」という判別が必要となる。
ここで、「操作完了フラグ[A]」とは別に
もうひとつ「固定完了フラグ[B]」を設ける。
これらを用いた具体的なアルゴリズムは、
1.「設置から自然固定までの時間」
1-1.「[A]が立っていない時に固定キーが押された場合、
固定の処理に移ると共に、[A]と[B]の両方を立てる」
2.「固定から次のブロック出現までの時間」
2-1.「固定キーが押されている時、
[A]も[B]も立っていない場合に限り[A]と[B]の両方を立てる」
2-2.「固定キーが離されている時は[A]を解除する」
ということになる。
こうする事で、操作の遅れによる固定入力を1度だけキャンセルし、
それ以外のキーを先行入力とみなすことができる。
}
DTET::ブロック出現時()
{
現在のほとんどのテトリスに「固定から次のブロック出現までの時間」が存在する。
この間に移動キーの押しっぱなしによって
リピート発動のためのカウンタを溜めることができるようになっているが、
これを待たずにブロックを操作したいプレイヤーもいるはずである。
よって、この待機時間をプレイヤーの入力によってキャンセルし、
直ちにブロックの操作ができる機能があれば、更なる高速操作が可能になる。
しかし、ブロックを移動させずに落下させる場合であれば良いが、
ブロックを端まで移動させる場合は、
結局リピートがかかるまでの溜め時間に依存してしまうことになる。
そこで、これを解消するために、出現時間の際に入力があった場合にのみ
リピートカウンタを少し加えてやれば良い。
例えば、標準の出現時間が15フレーム、
横移動の入力からリピートがかかるまでの時間を10フレーム
と定義した場合を考える。
出現時間開始から2フレームで横移動を開始すると仮定すると、
当然「出現時間開始からリピート開始までの時間」は
出現時間と同じ15フレームとなる。
では、待機時間中の入力により
リピートカウンタが3だけ加算されるとする。
それを上と同じ条件で横移動を開始すると、
プレイヤーの入力により出現時間がキャンセルされ、
リピート時間も3フレーム短縮され、
合計9フレームでリピートがかかることになり
前者と比べると6フレームの短縮になる。
このフレーム数の定義は、実際にプレイしながら調整していくのが良いと言える。
}
|