game/tetris/functions.cpp
2020-09-26 20:23:03 +02:00

419 lines
17 KiB
C++

#include "functions.hpp"
#include "custom_classes.hpp"
#include "global_vars.hpp"
#include "scenes.hpp"
#include <thread>
bool validPos(SDLPP::Scene &scene, std::shared_ptr<TetrisPiece> piece) {
for ( auto &x : piece->getObjects() ) {
auto collisions = scene.getCollisions( *x, { BRICK_ID, FLOOR_ID, BORDER_LEFT_ID, BORDER_RIGHT_ID } );
if ( collisions.size() > 1 )
return false;
}
return true;
}
void updateShadow(SDLPP::Scene &scene) {
if(!g_cur_object) {
g_cur_shadow->destroy();
g_cur_shadow.reset();
return;
}
if(!g_cur_shadow)
return;
g_cur_shadow->setPos(g_cur_object->getPos());
double shadow_drop = BOTTOM_BORDER;
auto &invalid_objects = g_cur_object->getObjects();
for( auto &x : g_cur_shadow->getObjects() ) {
auto block_pos = x->getPos();
if(BOTTOM_BORDER - block_pos.second < shadow_drop)
shadow_drop = BOTTOM_BORDER - block_pos.second;
// set colider column's position to current block's X position
g_shadow_colider->setPos(block_pos.first, TOP_BORDER);
auto collisions = scene.getCollisions( *g_shadow_colider, { BRICK_ID } );
auto curY = block_pos.second;
for(auto &col : collisions) {
// if collision with g_cur_object, ignore
if(std::find(invalid_objects.begin(), invalid_objects.end(), col) != invalid_objects.end())
continue;
auto possible_drop = col->getPos().second - curY;
if(possible_drop < shadow_drop && possible_drop >= 0)
shadow_drop = possible_drop;
}
}
// we want the shadow to rest on top of the nearest floor
shadow_drop -= BLOCK_SIZE;
auto shadow_pos = g_cur_shadow->getPos();
g_cur_shadow->setPos(shadow_pos.first, shadow_pos.second + shadow_drop);
}
void moveThem( std::shared_ptr< SDLPP::Scene > scene, int ticks ) {
if ( !g_cur_object )
return;
// get movement generated by player
auto movement = g_cur_object->getMovement();
g_ticks_till_fall -= ticks;
if ( g_cur_object->isDescending() )
g_ticks_till_descend -= ticks;
if ( g_cur_object->isMoving() )
g_ticks_till_movement -= ticks;
if ( g_ticks_till_fall > 0 ) {
if ( g_cur_object->isMoving() && g_ticks_till_movement <= 0 ) {
g_ticks_till_movement = TICKS_TILL_MOVE;
g_cur_object->movePiece(movement.first * BLOCK_SIZE, 0);
if(!validPos(*scene, g_cur_object)) {
g_cur_object->movePiece(movement.first * -BLOCK_SIZE, 0);
return;
} else
goto check_floor;
}
if ( g_cur_object->isDescending() && g_ticks_till_descend <= 0 ) {
g_ticks_till_descend = TICKS_TILL_DESCEND;
g_cur_object->movePiece(0, movement.second * BLOCK_SIZE);
if(!validPos(*scene, g_cur_object)) {
g_cur_object->movePiece(0, movement.second * -BLOCK_SIZE);
return;
} else
goto check_floor;
}
return;
}
g_ticks_till_fall = TICKS_TILL_FALL;
g_cur_object->movePiece(0, BLOCK_SIZE);
check_floor:
bool fell = false;
for ( auto &x : g_cur_object->getObjects() ) {
auto collisions = scene->getCollisions( *x, { BRICK_ID, FLOOR_ID } );
// we get 1 collision every time with ourselves
if ( collisions.size() > 1 ) {
fell = true;
break;
}
}
if ( fell ) {
g_cur_object->movePiece(0, -BLOCK_SIZE);
for ( auto &block : g_cur_object->getObjects() ) {
if ( scene->getCollisions( *block, { GAME_OVER } ).size() > 0 ) {
g_game_over_scene->updateSizeAndPosition();
g_active_scenes.push_back( g_game_over_scene );
g_input_functions.push_back(gameOverSceneInput);
break;
}
}
g_cur_object.reset();
}
updateShadow(*scene);
}
void quitGame() {
std::cout << "Quitting!" << std::endl;
g_quit = true;
}
void resetGame() {
g_cur_object.reset();
g_checked_line = true;
g_next_object.reset();
g_score = 0;
g_update_score = true;
g_main_scene->resetScene();
g_main_scene->setPrevTicks( SDL_GetTicks() );
g_active_scenes = {g_main_scene};
g_input_functions = {mainSceneInput};
for(int i = 0; i < 7; i++)
g_bag[i] = 28;
}
int crashFlags( std::shared_ptr<TetrisPiece> piece, std::shared_ptr<TetrisBlock> block, SDLPP::Scene &scene, int left, int right, int bottom) {
int retFlags = 0;
auto collisions = scene.getCollisions(*block, {BORDER_LEFT_ID, BORDER_RIGHT_ID, FLOOR_ID});
for(auto &col : collisions) {
switch(col->getId()) {
case BORDER_LEFT_ID:
retFlags |= left;
break;
case BORDER_RIGHT_ID:
retFlags |= right;
break;
case FLOOR_ID:
retFlags |= bottom;
default:
break;
}
}
collisions = scene.getCollisions(*block, {BRICK_ID});
if(collisions.size() > 1) {
for(auto &col : collisions) {
if(piece->isLeft(*col))
retFlags |= left;
else if(piece->isRight(*col))
retFlags |= right;
else
retFlags |= bottom;
}
}
return retFlags;
}
bool checkRotation( std::shared_ptr<TetrisPiece> piece, SDLPP::Scene &scene ) {
int crash = 0;
int cur_left = 0x01;
int cur_right = 0x02;
int was_left = 0x04;
int was_right = 0x08;
int bottom = 0x10;
int counter = 0;
do {
counter++;
if(counter > 5) {
piece->revert();
return false;
}
crash = 0;
for(auto &block : piece->getObjects()) {
crash |= crashFlags(piece, block, scene, cur_left, cur_right, bottom);
}
if(crash & bottom || (crash & cur_left && crash & cur_right) ||
(crash & cur_left && crash & was_right) || (crash & cur_right && crash & was_left)) {
piece->revert();
return false;
}
crash &= ~(was_left | was_right);
if(crash & cur_left) {
piece->movePiece(BLOCK_SIZE, 0);
crash &= ~cur_left;
crash |= was_left;
}
if(crash & cur_right) {
piece->movePiece(-BLOCK_SIZE, 0);
crash &= ~cur_right;
crash |= was_right;
}
} while(crash);
return true;
}
std::shared_ptr< TetrisBlock >
createTetrisBlock( double x, double y, const std::string &color,
const std::string &outline, int index,
std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto ret = std::make_shared< TetrisBlock >( x, y, BLOCK_SIZE, BLOCK_SIZE,
renderer, color, true, index, scene, g_bag );
ret->setOutlineColor( outline );
ret->addCollision( SDLPP::Rect( 0.1, 0.1, 0.8, 0.8 ) );
ret->setId( BRICK_ID );
ret->centerX();
scene->addObject( ret );
return ret;
}
std::shared_ptr< TetrisPiece >
tetrisBrick( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_brick"];
auto outline = colors["piece_brick_out"];
retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_BRICK, renderer,
scene ),
-1, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline,
TETRIS_BRICK, renderer, scene ),
0, 0 );
retPiece->addPiece(
createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_BRICK, renderer, scene ),
-1, 1 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_BRICK, renderer,
scene ),
0, 1 );
retPiece->disableRotation();
return retPiece;
}
std::shared_ptr< TetrisPiece >
tetrisT( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_T"];
auto outline = colors["piece_T_out"];
retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE,
TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_T, renderer, scene ),
-1, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_T, renderer, scene ),
0, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline,
TETRIS_T, renderer, scene ),
0, -1 );
retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE,
TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_T, renderer, scene ),
1, 0 );
return retPiece;
}
std::shared_ptr< TetrisPiece >
tetrisLRight( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_L_right"];
auto outline = colors["piece_L_right_out"];
retPiece->addPiece(
createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_L_RIGHT, renderer, scene ),
-2, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_L_RIGHT, renderer,
scene ),
-1, 0 );
retPiece->addPiece(
createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_L_RIGHT, renderer, scene ),
0, 0 );
retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_L_RIGHT, renderer,
scene ),
0, -1 );
return retPiece;
}
std::shared_ptr< TetrisPiece >
tetrisZRight( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_Z_right"];
auto outline = colors["piece_Z_right_out"];
retPiece->addPiece(
createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_Z_RIGHT, renderer, scene ),
-1, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_Z_RIGHT, renderer,
scene ),
0, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline,
TETRIS_Z_RIGHT, renderer, scene ),
0, -1 );
retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_Z_RIGHT, renderer,
scene ),
1, -1 );
return retPiece;
}
std::shared_ptr< TetrisPiece >
tetrisLine( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_line"];
auto outline = colors["piece_line_out"];
retPiece->addPiece( createTetrisBlock( 0.5 - 2 * BLOCK_SIZE, TOP_BORDER,
color, outline, TETRIS_LINE,
renderer, scene ),
-1, 0 );
retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_LINE, renderer,
scene ),
0, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline,
TETRIS_LINE, renderer, scene ),
1, 0 );
retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_LINE, renderer,
scene ),
2, 0 );
return retPiece;
}
std::shared_ptr< TetrisPiece >
tetrisLLeft( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_L_left"];
auto outline = colors["piece_L_left_out"];
retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_L_LEFT, renderer,
scene ),
0, -1 );
retPiece->addPiece(
createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_L_LEFT, renderer, scene ),
0, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_L_LEFT, renderer,
scene ),
1, 0 );
retPiece->addPiece(
createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_L_LEFT, renderer, scene ),
2, 0 );
return retPiece;
}
std::shared_ptr< TetrisPiece >
tetrisZLeft( std::shared_ptr< SDLPP::Renderer > renderer,
std::shared_ptr< SDLPP::Scene > scene ) {
auto retPiece = std::make_shared< TetrisPiece >();
auto color = colors["piece_Z_left"];
auto outline = colors["piece_Z_left_out"];
retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color,
outline, TETRIS_Z_LEFT, renderer,
scene ),
-1, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline,
TETRIS_Z_LEFT, renderer, scene ),
0, 0 );
retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_Z_LEFT, renderer,
scene ),
0, 1 );
retPiece->addPiece(
createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color,
outline, TETRIS_Z_LEFT, renderer, scene ),
1, 1 );
return retPiece;
}
void updateColors() {
for(auto &x : g_main_scene->getObjects({BRICK_ID})) {
x->specialAction(PIECE_ACTION_UPDATE_COLOR);
}
for(auto &x : g_main_scene->getObjects({BARRIER_ID})) {
x->setColor(colors["barrier"]);
}
for(auto &x : g_main_scene->getObjects({BACKGROUND_ID})) {
x->setColor(colors["background"]);
}
for(auto &x : g_main_scene->getObjects({SHADOW_ID})) {
x->setColor(colors["shadow"]);
}
for(auto &x : g_main_scene->getObjects({LINE_ID})) {
x->setColor(colors["line"]);
}
for(auto &x : g_main_scene->getObjects({TEXT_ID})) {
std::dynamic_pointer_cast<SDLPP::TextRenderer>(x)->setTextColor(*g_font, colors["text"], colors["text_out"], 5);
}
g_menu_options[g_menu_select]->setColor(colors["menu_item_background"]);
g_game_over_options[g_game_over_select]->setColor(colors["menu_item_background"]);
g_options_options[g_options_select]->setColor(colors["menu_item_background"]);
for(auto &x : g_menu_scene->getObjects({MENU_BACKGROUND_ID})) {
x->setColor(colors["menu_background"]);
}
for(auto &x : g_game_over_scene->getObjects({MENU_BACKGROUND_ID})) {
x->setColor(colors["menu_background"]);
}
for(auto &x : g_options_scene->getObjects({MENU_BACKGROUND_ID})) {
x->setColor(colors["menu_background"]);
}
for(auto &x : g_options_scene->getObjects({MENU_ITEM_ID})) {
std::dynamic_pointer_cast<SDLPP::TextRenderer>(x)->setTextColor(*g_font, colors["text"], colors["text_out"]);
}
}