はかせのラボ

私の頭の中を書いていく雑記ブログです

落ちモノパズル Tスピン判定を無理やり実装してみた

あいさつ

どうも、はかせです。
今回はTスピンの判定を実装してみたので
実装方法を上げます。

まず前回のおさらい

まず前回のおさらいです。
ここで書くことの詳細が知りたい方は前回の記事を見てください。
hakase0274.hatenablog.com

前回はTスピン判定を付けようと思いましたが、
一体この判定を誰に持たせるべきか悩み結局答えが出ずに終わってしまいました。

この判定には
①最後の操作
②テトリミノ周囲の情報

これらが必要でこれらを持っているクラスが
①テトリミノクラス
②テトリミノ回転クラス
③盤面管理クラス

この3つでした。
ただそれぞれのクラスがやってることが多すぎて
管理が乱雑になり過ぎる問題がありました。

結局誰が持つことになったのか

色々悩みましたが結局テトリミノクラスが持つことになりました。

理由は単純で
このクラスで判定するのが一番スッキリしたからです。
このクラスはテトリミノの状態管理と
操作インターフェースの提供をしています。

テトリミノの状態管理の部分に
Tスピンしているかという判定をねじ込みましたw

ただあくまでTスピンの判定を行っているだけで
スコアの計算などの処理はこのクラスに対して参照を持っているクラスが
判定結果を取得し動作しています。

実装

まずは外部から判定を取得する部分です。

//外部からTスピン判定を呼ぶ
bool TetriMino::GetIsTspin()
{
   //最後の処理が回転でなければTスピンではない
   if (mLastAction != Rotation) return false;
   return IsTspin();
}

bool TetriMino::GetIsTspinMini()
{
   //TスピンしてなければTスピンミニはありえない
   if (!mIsTspin) return false;
   return IsTspinMini();
}

この段階で最後の処理が回転かどうかを見ています。
最後の処理が回転でなければ他の判定を行う必要はありませんからね。

では実際の判定の中身です。

bool TetriMino::IsTspin()
{
	//4隅のピース数をカウント
	auto pieceCount = 0;
	//中央のピース
	auto centerPiece = mPiecePositions[0];
	//4隅のピースの状態取得
	auto rightUpState = mFieldManager->GetPieceState(centerPiece.x - 1, centerPiece.y + 1);
	auto leftUpState = mFieldManager->GetPieceState(centerPiece.x + 1, centerPiece.y + 1);
	auto rightDownState = mFieldManager->GetPieceState(centerPiece.x - 1, centerPiece.y - 1);
	auto leftDownState = mFieldManager->GetPieceState(centerPiece.x + 1, centerPiece.y - 1);
	//取得したピースの状態が盤面固定されたピースであればカウントアップ
	if (rightUpState == FieldLock) pieceCount++;
	if (leftUpState == FieldLock) pieceCount++;
	if (rightDownState == FieldLock) pieceCount++;
	if (leftDownState == FieldLock) pieceCount++;
	//4隅のピースが3つ以上あればTスピンである
	if (pieceCount >= 3)
	{
		mIsTspin = true;
		return true;
	}
	else return false;
}

bool TetriMino::IsTspinMini()
{
	//中央のピース
	auto centerPiece = mPiecePositions[0];
	//中央の背後のピースの状態
	auto centerBackPieceState = Space;
	//ピースの回転状態によって背後のピースを求める
	switch (mRotationState)
	{
	case A:
		centerBackPieceState = mFieldManager->GetPieceState(centerPiece.x, centerPiece.y - 1);
		break;
	case B:
		centerBackPieceState = mFieldManager->GetPieceState(centerPiece.x + 1, centerPiece.y);
		break;
	case C:
		centerBackPieceState = mFieldManager->GetPieceState(centerPiece.x, centerPiece.y + 1);
		break;
	case D:
		centerBackPieceState = mFieldManager->GetPieceState(centerPiece.x - 1, centerPiece.y);
		break;
	default:
		break;
	}
	//背後のピースが盤面固定されていれば
	if (centerBackPieceState == FieldLock) 
	{
		mIsTspin = false;
		mIsTspinMini = true;
		return true;
	}
	else return false;
}

前回話したTスピンの条件を素直にコードに起こしただけですね。

あとがき

今回は無理やりTスピン判定を付けた話でした。
テトリミノクラスがどんどん肥大化してしまっているので
どっかで責任分けなければなぁと思っていますorz
(まぁそれは裏側でやるかまたリファクタリング記事でも上げてするとします)

今直面している問題としてはエフェクトをどうやってつけるかですね。
前回の弾幕シューティングと違ってエフェクトが出たら
一旦止まってエフェクトが終わり次第次へという流れが必要です。

ただエフェクトがでた→ゲーム全体ストップではありません。
(そうするとエフェクトも止まってしまいますからね)

待つものと待たないものがいるわけです。
全てがどちらか一方なら楽なんですけどね。
まぁ難しいからこそ腕の見せ所であり、
価値があるわけですよね。

それでは今回はこの辺でノシ

今回作ったものはgithubに上げました
github.com