CyberMatris port for Miyoo Mini Plus
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

189 lines
5.4 KiB

#pragma once
#include <vector>
#include <random>
enum class PieceType {
I = 0, O, T, S, Z, J, L, NONE
};
struct Point {
int x;
int y;
};
// Coordinates for all 7 Tetromino types in their 4 rotation states (0, 1, 2, 3)
// Pivot anchor is (0,0). Screen space has Y-down, X-right.
inline const Point TETROMINO_CELLS[7][4][4] = {
// 0: I Piece
{
{ {-1, 0}, {0, 0}, {1, 0}, {2, 0} }, // rot 0
{ {1, -1}, {1, 0}, {1, 1}, {1, 2} }, // rot 1
{ {-1, 1}, {0, 1}, {1, 1}, {2, 1} }, // rot 2
{ {0, -1}, {0, 0}, {0, 1}, {0, 2} } // rot 3
},
// 1: O Piece
{
{ {0, 0}, {1, 0}, {0, 1}, {1, 1} }, // rot 0
{ {0, 0}, {1, 0}, {0, 1}, {1, 1} }, // rot 1
{ {0, 0}, {1, 0}, {0, 1}, {1, 1} }, // rot 2
{ {0, 0}, {1, 0}, {0, 1}, {1, 1} } // rot 3
},
// 2: T Piece
{
{ {-1, 0}, {0, 0}, {1, 0}, {0, 1} }, // rot 0
{ {0, -1}, {0, 0}, {0, 1}, {-1, 0} }, // rot 1
{ {-1, 0}, {0, 0}, {1, 0}, {0, -1} }, // rot 2
{ {0, -1}, {0, 0}, {0, 1}, {1, 0} } // rot 3
},
// 3: S Piece
{
{ {0, 0}, {1, 0}, {-1, 1}, {0, 1} }, // rot 0
{ {0, -1}, {0, 0}, {1, 0}, {1, 1} }, // rot 1
{ {0, -1}, {1, -1}, {-1, 0}, {0, 0} }, // rot 2
{ {-1, -1}, {-1, 0}, {0, 0}, {0, 1} } // rot 3
},
// 4: Z Piece
{
{ {-1, 0}, {0, 0}, {0, 1}, {1, 1} }, // rot 0
{ {1, -1}, {1, 0}, {0, 0}, {0, 1} }, // rot 1
{ {-1, -1}, {0, -1}, {0, 0}, {1, 0} }, // rot 2
{ {0, -1}, {0, 0}, {-1, 0}, {-1, 1} } // rot 3
},
// 5: J Piece
{
{ {-1, 0}, {0, 0}, {1, 0}, {-1, 1} }, // rot 0
{ {0, -1}, {0, 0}, {0, 1}, {-1, -1} }, // rot 1
{ {-1, 0}, {0, 0}, {1, 0}, {1, -1} }, // rot 2
{ {0, -1}, {0, 0}, {0, 1}, {1, 1} } // rot 3
},
// 6: L Piece
{
{ {-1, 0}, {0, 0}, {1, 0}, {1, 1} }, // rot 0
{ {0, -1}, {0, 0}, {0, 1}, {-1, 1} }, // rot 1
{ {-1, 0}, {0, 0}, {1, 0}, {-1, -1} }, // rot 2
{ {0, -1}, {0, 0}, {0, 1}, {1, -1} } // rot 3
}
};
enum class GameState {
START,
PLAYING,
PAUSED,
GAME_OVER
};
class Game {
public:
static constexpr int BOARD_WIDTH = 10;
static constexpr int BOARD_HEIGHT = 20;
Game();
~Game() = default;
void init();
void reset();
// Core game loop update (handles gravity, lock delay, game states)
// Returns true if lines were cleared in this frame
bool update(float dt);
// Gameplay commands (inputs)
bool moveLeft();
bool moveRight();
bool rotate(int dir); // dir = 1 (CW), -1 (CCW)
void softDrop();
bool hardDrop(); // Returns true if piece locked
void holdPiece();
// Query states
GameState getState() const { return mState; }
void setState(GameState state) { mState = state; }
int getScore() const { return mScore; }
int getLinesCleared() const { return mLinesCleared; }
int getLevel() const { return mLevel; }
int getCombo() const { return mCombo; }
PieceType getCell(int x, int y) const {
if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) return PieceType::NONE;
return mBoard[y][x];
}
PieceType getActivePieceType() const { return mActiveType; }
int getActiveX() const { return mActiveX; }
int getActiveY() const { return mActiveY; }
int getActiveRotation() const { return mActiveRot; }
// Relative cell coordinates of current falling block
std::vector<Point> getActiveCells() const;
// Absolute cell coordinates of where active piece would land (ghost projection)
std::vector<Point> getGhostCells() const;
PieceType getHoldPieceType() const { return mHoldType; }
bool canHold() const { return mCanHold; }
std::vector<PieceType> getNextQueue() const { return mNextQueue; }
// Inter-thread game sound effects triggers
bool flagMoveSFX = false;
bool flagRotateSFX = false;
bool flagLandSFX = false;
bool flagLineClearSFX = false;
bool flagTetrisClearSFX = false;
bool flagLevelUpSFX = false;
bool flagGameOverSFX = false;
// Screen shake parameters
float getScreenShakeIntensity() const { return mShakeIntensity; }
void resetScreenShake() { mShakeIntensity = 0.0f; }
// List of lines cleared on the current tick (for particle animations)
std::vector<int> mClearedLinesThisTick;
std::vector<Point> mLastLockedCells;
private:
GameState mState = GameState::START;
// The grid: index y=0 is top, y=19 is bottom
PieceType mBoard[BOARD_HEIGHT][BOARD_WIDTH];
// Falling piece details
PieceType mActiveType = PieceType::NONE;
int mActiveX = 0;
int mActiveY = 0;
int mActiveRot = 0;
// Hold slot details
PieceType mHoldType = PieceType::NONE;
bool mCanHold = true;
// 7-piece bag randomizer
std::vector<PieceType> mNextQueue;
std::vector<PieceType> mBag;
std::mt19937 mRng;
// Score metrics
int mScore = 0;
int mLinesCleared = 0;
int mLevel = 1;
int mCombo = -1;
// Fall & Lock delay timers
float mFallTimer = 0.0f;
float mLockTimer = 0.0f;
bool mIsLocking = false;
float mShakeIntensity = 0.0f;
float getFallDelay() const;
void spawnPiece();
void fillBag();
PieceType popNextPiece();
bool checkCollision(const std::vector<Point>& cells, int dx, int dy) const;
bool fits(PieceType type, int rot, int cx, int cy) const;
void lockPiece();
void clearLines();
};