Skip to content

Commit

Permalink
screen size handling, v1
Browse files Browse the repository at this point in the history
  • Loading branch information
WhySoBad committed Jul 7, 2022
1 parent 9d3d276 commit 2d9fa2c
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 116 deletions.
8 changes: 3 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
SET(PROJECT_NAME console-tetris)
PROJECT(${PROJECT_NAME})

set(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD 17)

# FIND_LIBRARY(Curses REQUIRED)
# INCLUDE_DIRECTORIES(${CURSES_INCLUDE_DIR})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")

ADD_EXECUTABLE(${PROJECT_NAME} src/Game.cpp src/main.cpp src/Tetris.cpp src/helper/TetrisHelper.cpp src/helper/TetrisHelper.h src/helper/DrawHelper.cpp src/helper/DrawHelper.h src/helper/FontHelper.cpp src/helper/FontHelper.h src/helper/ConfigHelper.cpp src/helper/ConfigHelper.h src/geometry/Point.cpp src/geometry/Point.h src/geometry/BoundingBox.cpp src/geometry/BoundingBox.h src/tetromino/TetrominoI.cpp src/tetromino/TetrominoI.h src/tetromino/TetrominoJ.cpp src/tetromino/TetrominoJ.h src/tetromino/TetrominoL.cpp src/tetromino/TetrominoL.h src/tetromino/TetrominoO.cpp src/tetromino/TetrominoO.h src/tetromino/TetrominoS.cpp src/tetromino/TetrominoS.h src/tetromino/TetrominoT.cpp src/tetromino/TetrominoT.h src/tetromino/TetrominoZ.cpp src/tetromino/TetrominoZ.h)
# TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CURSES_LIBRARIES})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ncurses)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ncurses)

6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# output binary name
NAME=tetris
NAME=console-tetris

# output directory name
DIRECTORY=build
DIRECTORY=bin

# log prefix
PREFIX=[tetris]
Expand All @@ -13,7 +13,7 @@ all: directory compile
# script to compile the project
compile:
@echo "$(PREFIX) Compiling source code"
@g++ -fdiagnostics-color=always -g src/*.cpp -o ${DIRECTORY}/${NAME} -lncursesw
@g++ -fdiagnostics-color=always -g src/*.cpp src/geometry/*.cpp src/helper/*.cpp src/tetromino/*.cpp -o ${DIRECTORY}/${NAME} -lncursesw
@echo "$(PREFIX) Saved binary file to '${CURDIR}/${DIRECTORY}/${NAME}'"

# script to create the output directory
Expand Down
68 changes: 16 additions & 52 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,20 @@ Game::Game() {
}

void Game::draw() {
// get current key
timeout(0); // don't wait for user input
int key = getch();
int key = getch(); // get current key
flushinp(); // clear input buffer

if (key == 'p' && !paused && !gameover) {
paused = true;
key = -1; // make sure the key information isn't used twice
} else if(key == 'r') return reset(); // reset the game

// TODO -> "Custom" font adjustable to the point size
// TODO -> Auto adjust to screen size -> Error when terminal is too small

} else if(key == 'r') return reset();
else if(key == 'e') {
stop();
exit(0);
}

if (!gameover && !paused) {
// draw active object
if (step >= getDroppingFrames()) {
if (TetrisHelper::canTetrisMove(active, Direction::vertical, 1)) {
DrawHelper::clearTetris(active);
Expand Down Expand Up @@ -105,19 +103,17 @@ void Game::draw() {
DrawHelper::drawTetris(active);
}
break;
};
}

if (key == KEY_UP || key == KEY_DOWN || key == KEY_RIGHT || key == KEY_LEFT || step >= getDroppingFrames()) {
if (!TetrisHelper::canTetrisMove(active, Direction::vertical, 1)) fixActive();
}
} else if (paused) {
if (key == 'p') {
// restore game progress
DrawHelper::clearUpcoming();
DrawHelper::drawUpcoming(upcoming);
// drawPaused(true);
paused = false; // unpause game
} else /*drawPaused();*/ DrawHelper::drawPaused();
paused = false;
} else DrawHelper::drawPaused();
}

DrawHelper::drawStatistics(score, level, cleared);
Expand All @@ -140,39 +136,8 @@ void Game::start() {
}

void Game::stop() {
running = false; // stop the game cycle
endwin(); // stop the ncurses mode and reenter the default terminal
}

void Game::drawPaused(bool clear) {
const int pausedWidth = 3;
const int pausedHeight = 3;

// calculate the padding of the paused icon
int _paddingX = (FIELD_WIDTH - 3) / 2 + 1;
int _paddingY = (FIELD_HEIGHT - 3) / 2;

for (int i = 0; i < FIELD_HEIGHT; i++) {
array<short, FIELD_WIDTH> row = TetrisHelper::getFixedLine(i);
for (int j = 0; j < row.size(); j++) {
if (row[j]) {
Point point = Point(j, i);
DrawHelper::drawPoint(&point, clear ? OCCUPIED_SPACE : EMPTY_SPACE, clear ? row[j] : -1);
}
}
}
DrawHelper::drawTetris(active, clear ? OCCUPIED_SPACE : EMPTY_SPACE, clear ? active->getType() + 1 : -1);
if (!clear) DrawHelper::drawPreviewLine(active, EMPTY_SPACE);

for (int i = 0; i < pausedWidth * pausedHeight; i++) {
int row = i / pausedWidth;
int rest = i % pausedWidth;
Point point = Point(_paddingX + rest, _paddingY + row);
if (rest == 0 || rest == pausedWidth - 1)
DrawHelper::drawPoint(&point, clear ? EMPTY_SPACE : OCCUPIED_SPACE, clear ? -1 : 9);
}

if (clear) DrawHelper::drawPreviewLine(active);
running = false; // stop the game cycle
endwin(); // stop the ncurses mode and reenter the default terminal
}


Expand All @@ -183,7 +148,7 @@ void Game::fixActive() {
vector<int> modifiedRows = vector<int>();
for (Point point: active->getPoints()) { // update fixed points in the array
if (point.getY() >= 0)
TetrisHelper::setFixedPoint(point.getX(), point.getY(), active->getType() + 1); // store color for the point
TetrisHelper::setFixedPoint(point.getX(), point.getY(), static_cast<short>(active->getType() + 1)); // store color for the point
else outOfScreen = true;

bool existing = false;
Expand Down Expand Up @@ -223,8 +188,7 @@ void Game::fixActive() {
}
}

// sort full rows in ascending order
sort(fullRows.begin(), fullRows.end());
sort(fullRows.begin(), fullRows.end()); // sort full rows in ascending order

for (int row: fullRows) {
int highestY = FIELD_HEIGHT;
Expand Down Expand Up @@ -258,7 +222,7 @@ void Game::fixActive() {

// update level and score

cleared += fullRows.size();
cleared += static_cast<int>(fullRows.size());
if (level == 0 ? cleared >= 10 : cleared >= level * 30) level++;

switch (fullRows.size()) {
Expand Down Expand Up @@ -328,8 +292,8 @@ int Game::getDroppingFrames() const {
void Game::gameOver() {
ConfigHelper::addRound();
DrawHelper::clearUpcoming();
int paddingX = DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_WIDTH * POINT_SIZE + POINT_WIDTH;
int paddingY = DrawHelper::getPaddingY() + (UPCOMING_HEIGHT * POINT_SIZE) / 2;
int paddingX = DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_WIDTH * DrawHelper::getUiSize() + POINT_WIDTH;
int paddingY = DrawHelper::getPaddingY() + (UPCOMING_HEIGHT * DrawHelper::getUiSize()) / 2;
DrawHelper::printAt(paddingX, paddingY - 2, "Gameover!");
DrawHelper::printAt(paddingX, paddingY, "Press 'r' to");
DrawHelper::printAt(paddingX, paddingY + 1, "replay!");
Expand Down
9 changes: 1 addition & 8 deletions src/Game.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,11 @@ class Game {

void fixActive();

/**
* Draw the paused screen
* @param clear boolean whether the paused screen should be cleared
*/

void drawPaused(bool clear = false);

/**
* Handle a game over
*/

void gameOver();
static void gameOver();

/**
* Update method
Expand Down
2 changes: 1 addition & 1 deletion src/helper/ConfigHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void ConfigHelper::readConfig() {
}
input.close();

auto getItem = [&config](std::string key) -> int {
auto getItem = [&config](const std::string& key) -> int {
try {
return config.at(key);
} catch(...) {
Expand Down
82 changes: 41 additions & 41 deletions src/helper/DrawHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ void DrawHelper::clearTetris(Tetris *tetris) {
}

void DrawHelper::clearField() {
for (int k = 0; k < FIELD_HEIGHT * POINT_SIZE; ++k) {
for (int m = 0; m < FIELD_WIDTH * POINT_SIZE * POINT_WIDTH; ++m) {
for (int k = 0; k < FIELD_HEIGHT * DrawHelper::getUiSize(); ++k) {
for (int m = 0; m < FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH; ++m) {
int x = DrawHelper::getPaddingX() + m;
int y = DrawHelper::getPaddingY() + k;
DrawHelper::printAt(x, y, EMPTY_SPACE);
Expand All @@ -46,11 +46,11 @@ void DrawHelper::clearField() {
}

void DrawHelper::drawPoint(Point *point, const char *character, int color, bool ignore, bool letter) {
int scale = letter ? LETTER_SIZE : POINT_SIZE;
int scale = letter ? LETTER_SIZE : DrawHelper::getUiSize();
if(ignore || TetrisHelper::isPointInScreen(point)) {
DrawHelper::useColor(color);
for (int k = 0; k < pow(scale, 2) * POINT_WIDTH; ++k) {
int row = k / POINT_WIDTH / POINT_SIZE;
int row = k / POINT_WIDTH / DrawHelper::getUiSize();
int x = POINT_WIDTH * scale * point->getX() + DrawHelper::getPaddingX() + k - row * POINT_WIDTH * scale;
if(point->getX() > FIELD_WIDTH && point->getX() < FIELD_WIDTH + MENU_WIDTH) x++;
int y = scale * point->getY() + DrawHelper::getPaddingY() + row;
Expand All @@ -65,8 +65,8 @@ void DrawHelper::drawBorder() {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
int height = size.ws_row;
int width = size.ws_col;
int totalFieldHeight = FIELD_HEIGHT * POINT_SIZE + 2;
int totalFieldWidth = (FIELD_WIDTH + MENU_WIDTH) * POINT_SIZE * POINT_WIDTH + 3;
int totalFieldHeight = FIELD_HEIGHT * DrawHelper::getUiSize() + 2;
int totalFieldWidth = (FIELD_WIDTH + MENU_WIDTH) * DrawHelper::getUiSize() * POINT_WIDTH + 3;

// calculate field padding on both axes
if(width > totalFieldWidth) paddingX = (int) (width - totalFieldWidth) / 2;
Expand All @@ -90,19 +90,19 @@ void DrawHelper::drawBorder() {

// draw menu separator line
for (int k = 0; k < totalFieldHeight; ++k) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_SIZE * POINT_WIDTH;
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH;
int y = DrawHelper::getPaddingY() + k - 1;
if(k == 0) DrawHelper::printAt(x, y, TOP_CROSSING_BORDER);
else if(k == totalFieldHeight - 1) DrawHelper::printAt(x, y, BOTTOM_CROSSING_BORDER);
else DrawHelper::printAt(x, y, VERTICAL_BORDER);
}

// draw upcoming separator line
for (int k = 0; k < MENU_WIDTH * POINT_SIZE * POINT_WIDTH + 2; ++k) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_SIZE * POINT_WIDTH + k;
int y = DrawHelper::getPaddingY() + UPCOMING_HEIGHT * POINT_SIZE;
for (int k = 0; k < MENU_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + 2; ++k) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + k;
int y = DrawHelper::getPaddingY() + UPCOMING_HEIGHT * DrawHelper::getUiSize();
if(k == 0) DrawHelper::printAt(x, y, LEFT_CROSSING_BORDER);
else if(k == MENU_WIDTH * POINT_SIZE * POINT_WIDTH + 1) DrawHelper::printAt(x, y, RIGHT_CROSSING_BORDER);
else if(k == MENU_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + 1) DrawHelper::printAt(x, y, RIGHT_CROSSING_BORDER);
else DrawHelper::printAt(x, y, HORIZONTAL_BORDER);
}
}
Expand Down Expand Up @@ -130,18 +130,18 @@ void DrawHelper::drawUpcoming(Tetris *tetris) {
}

void DrawHelper::clearUpcoming() {
for (int k = 0; k < UPCOMING_HEIGHT * POINT_SIZE; ++k) {
for (int m = 0; m < MENU_WIDTH * POINT_SIZE * POINT_WIDTH; ++m) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_SIZE * POINT_WIDTH + 1 + m;
for (int k = 0; k < UPCOMING_HEIGHT * DrawHelper::getUiSize(); ++k) {
for (int m = 0; m < MENU_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH; ++m) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + 1 + m;
int y = DrawHelper::getPaddingY() + k;
DrawHelper::printAt(x, y, EMPTY_SPACE);
}
}
}

void DrawHelper::drawStatistics(int score, int level, int lines) {
auto * point = new Point(DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_SIZE * POINT_WIDTH + 2, DrawHelper::getPaddingY() + UPCOMING_HEIGHT * POINT_SIZE + 1 * POINT_SIZE);
auto * scPoint = new Point(DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_SIZE * POINT_WIDTH + 2, DrawHelper::getPaddingY() + FIELD_HEIGHT * POINT_SIZE - 1 * POINT_SIZE);
auto * point = new Point(DrawHelper::getPaddingX() + FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + 2, DrawHelper::getPaddingY() + UPCOMING_HEIGHT * DrawHelper::getUiSize() + 1 * DrawHelper::getUiSize());
auto * scPoint = new Point(DrawHelper::getPaddingX() + FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + 2, DrawHelper::getPaddingY() + FIELD_HEIGHT * DrawHelper::getUiSize() - 1 * DrawHelper::getUiSize());
auto drawStatistic = [&point](const char * name, int value) {
attron(A_BOLD);
DrawHelper::printAt(point->getX(), point->getY(), name);
Expand All @@ -156,31 +156,17 @@ void DrawHelper::drawStatistics(int score, int level, int lines) {
point->moveY(2);
};

auto drawShortcut = [&scPoint](const std::string& shortcut) {
std::string firstLetter = shortcut.substr(0, 1);
DrawHelper::printAt(scPoint->getX(), scPoint->getY(), "[");
DrawHelper::printAt(scPoint->getX() + 1, scPoint->getY(), shortcut.substr(0, 1).c_str());
DrawHelper::printAt(scPoint->getX() + 2, scPoint->getY(), "]");
DrawHelper::printAt(scPoint->getX() + 3, scPoint->getY(), std::string(shortcut).substr(1, shortcut.length() - 1).c_str());
scPoint->moveY(-2);
};

drawStatistic("Score", score);
drawStatistic("Highscore", ConfigHelper::getHighscore());
drawStatistic("Level", level);
drawStatistic("Lines", lines);

// add shortcut hints
/* drawShortcut("Exit");
drawShortcut("Reset");
drawShortcut("Pause");*/
}

void DrawHelper::clearStatistics() {
for (int k = 0; k < (FIELD_HEIGHT - UPCOMING_HEIGHT) * POINT_SIZE - 1; ++k) {
for (int m = 0; m < MENU_WIDTH * POINT_SIZE * POINT_WIDTH; ++m) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * POINT_SIZE * POINT_WIDTH + 1 + m;
int y = DrawHelper::getPaddingY() + UPCOMING_HEIGHT * POINT_SIZE + 1 + k;
for (int k = 0; k < (FIELD_HEIGHT - UPCOMING_HEIGHT) * DrawHelper::getUiSize() - 1; ++k) {
for (int m = 0; m < MENU_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH; ++m) {
int x = DrawHelper::getPaddingX() + FIELD_WIDTH * DrawHelper::getUiSize() * POINT_WIDTH + 1 + m;
int y = DrawHelper::getPaddingY() + UPCOMING_HEIGHT * DrawHelper::getUiSize() + 1 + k;
DrawHelper::printAt(x, y, EMPTY_SPACE);
}
}
Expand All @@ -197,14 +183,26 @@ void DrawHelper::printAt(int x, int y, const char *characters) {
mvprintw(y, x, "%s", characters);
}


void DrawHelper::initialize() {
struct winsize size{};
ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
int height = size.ws_row, width = size.ws_col;
paddingX = 0;
paddingY = 0;

setlocale(LC_ALL, "");
auto fitsScreen = [&height, &width](int &uiSize) {
return height >= FIELD_HEIGHT * uiSize + 2 && width >= (FIELD_WIDTH + MENU_WIDTH) * uiSize * POINT_WIDTH + 3;
};

while(!fitsScreen(uiSize) && uiSize > 0) uiSize--;
if(uiSize == 0) {
printf("Your terminal doesn't fit the required dimensions! [height: %i -> required: %i; width: %i -> required: %i]\n", height, FIELD_HEIGHT + 2, width, FIELD_WIDTH + MENU_WIDTH + 3);
fflush(stdout);
exit(0);
}

setlocale(LC_ALL, ""); // enable unicodes

// setup ncurses
WINDOW *win = newwin(height, width, 0, 0); // create a new ncurses window
Expand All @@ -218,20 +216,18 @@ void DrawHelper::initialize() {
nodelay(win, TRUE); // disable key wait delay

// add color pairs
init_color(9, 1000, 533, 0); // orange color
init_color(10, 309, 309, 309); // light gray color
init_color(24, 1000, 533, 0); // orange color -> used in L-Tetromino
init_color(25, 309, 309, 309); // light gray color -> used in preview dot

init_pair(1, -1, COLOR_CYAN); // I-Tetromino
init_pair(2, -1, COLOR_BLUE); // J-Tetromino
init_pair(3, -1, 9); // L-Tetromino
init_pair(3, -1, 24); // L-Tetromino
init_pair(4, -1, COLOR_YELLOW); // O-Tetromino
init_pair(5, -1, COLOR_GREEN); // S-Tetromino
init_pair(6, -1, COLOR_MAGENTA); // T-Tetromino
init_pair(7, -1, COLOR_RED); // Z-Tetromino
init_pair(8, 10, -1); // preview dot
init_pair(8, 25, -1); // preview dot
init_pair(9, -1, COLOR_WHITE); // menu stuff


}

int DrawHelper::getPaddingX() {
Expand All @@ -242,5 +238,9 @@ int DrawHelper::getPaddingY() {
return paddingY;
}

int DrawHelper::getUiSize() {
return uiSize;
}



Loading

0 comments on commit 2d9fa2c

Please sign in to comment.