diff --git a/sdlpp.hpp b/sdlpp.hpp index 99239bb..8af1edf 100644 --- a/sdlpp.hpp +++ b/sdlpp.hpp @@ -432,14 +432,14 @@ protected: std::shared_ptr< Texture > texture; std::shared_ptr< Renderer > renderer; std::shared_ptr< CollisionPolygon > polygon; - double movementSpeed; - std::pair< int, int > movementDirection; + double movementSpeed = 0; + std::pair< int, int > movementDirection = {0,0}; std::vector< std::shared_ptr< RenderObject > > colidedWith; - uint64_t id; + uint64_t id = -1; bool hidden = false; bool kill = false; std::tuple< int, int, int, int > colider_color = { 0x00, 0xFF, 0xFF, 0xFF }; - uint64_t scene_id; + uint64_t scene_id = -1; bool permanent = false; bool is_static = true; @@ -517,6 +517,15 @@ public: std::vector< std::shared_ptr< RenderObject > > getObjects() { return render_objects; } + std::vector< std::shared_ptr< RenderObject > > getObjects(const std::unordered_set< int > &objectIDs) { + std::vector< std::shared_ptr< RenderObject > > ret{}; + for ( const auto &x : render_objects ) { + if ( objectIDs.find( x->getId() ) != objectIDs.end() ) { + ret.push_back( x ); + } + } + return ret; + } void movement() { checkKilled(); render_mutex.lock(); @@ -980,7 +989,6 @@ public: pixel_x2 = std::round(x2_ * dimension); pixel_y1 = std::round(y1_ * dimension); pixel_y2 = std::round(y2_ * dimension); - std::cout << "x1: " << pixel_x1 << ", y1: " << pixel_y1 << ", x2: " << pixel_x2 << ", y2: " << pixel_y2 << std::endl; for ( auto &x : collisions ) { x->updateCollision( collisionPushX(), collisionPushY(), collisionWidth(), collisionHeight() ); @@ -1245,9 +1253,21 @@ public: const std::string &color = "FFFFFF", const std::string &outline_color = "000000", int outline_size = -1 ) { - setTexture( font, text, color, outline_color, outline_size ); + _text = text; + setTextColor(font, color, outline_color, outline_size); + } + void setTextColor( Font &font, const std::string &color = "FFFFFF", + const std::string &outline_color = "000000", + int outline_size = -1) { + std::cout << "TEXT: " << _text << ", COLOR: " << color << ", OUTLINE_COLOR: " << outline_color << ", OUTLINE_SIZE: " << outline_size << std::endl; + setTexture( font, _text, color, outline_color, outline_size ); updateDstRect(); } + void changeText( const std::string &text ) { + std::cout << _text << std::endl; + _text = text; + std::cout << _text << std::endl; + } void setFlags( int flags ) { position_flags = flags; updateDstRect(); @@ -1315,6 +1335,7 @@ private: dst_rect.y = rect.y + rect.h - dst_rect.h; } } + std::string _text{}; int position_flags = 0; SDL_Rect dst_rect{}; }; diff --git a/tetris/Makefile b/tetris/Makefile index 0d419aa..ff2890c 100644 --- a/tetris/Makefile +++ b/tetris/Makefile @@ -6,12 +6,20 @@ LDFLAGS ?= -lSDL2 -lSDL2_image -lSDL2_gfx -lSDL2_ttf -pthread .PHONY: default default: tetris -tetris: tetris.o sdlpp.o +tetris: tetris.o sdlpp.o scenes.o config.o functions.o global_vars.o $(CXX) $(CFLAGS) -o $@ $^ ${LDFLAGS} sdlpp.o: ../sdlpp.cpp ../sdlpp.hpp $(CXX) $(CFLAGS) -c -o $@ $< -tetris.o: tetris.cpp ../sdlpp.hpp config.hpp +tetris.o: tetris.cpp ../sdlpp.hpp config.hpp custom_classes.hpp scenes.hpp + $(CXX) $(CFLAGS) -c -o $@ $< +scenes.o: scenes.cpp ../sdlpp.hpp config.hpp scenes.hpp + $(CXX) $(CFLAGS) -c -o $@ $< +config.o: config.cpp config.hpp + $(CXX) $(CFLAGS) -c -o $@ $< +functions.o: functions.cpp config.hpp functions.hpp + $(CXX) $(CFLAGS) -c -o $@ $< +global_vars.o: global_vars.cpp config.hpp global_vars.hpp $(CXX) $(CFLAGS) -c -o $@ $< clean: diff --git a/tetris/config.cpp b/tetris/config.cpp new file mode 100644 index 0000000..4a1ee17 --- /dev/null +++ b/tetris/config.cpp @@ -0,0 +1,79 @@ +#include "config.hpp" + +std::map> color_schemes = { + { "default", { + {"piece_brick", "#FF0000"}, + {"piece_brick_out", "#AA0000"}, + {"piece_T", "#00FF00"}, + {"piece_T_out", "#00AA00"}, + {"piece_L_right", "#0000FF"}, + {"piece_L_right_out", "#0000AA"}, + {"piece_Z_right", "#FF00FF"}, + {"piece_Z_right_out", "#AA00AA"}, + {"piece_line", "#FFFF00"}, + {"piece_line_out", "#AAAA00"}, + {"piece_L_left", "#00FFFF"}, + {"piece_L_left_out", "#00AAAA"}, + {"piece_Z_left", "#FFFFFF"}, + {"piece_Z_left_out", "#AAAAAA"}, + {"shadow", "#AAAAAAAA"}, + {"background", "#222222"}, + {"line", "#888888"}, + {"barrier", "#AA0000"}, + {"text", "#FFFFFF"}, + {"text_out", "#000000"}, + {"menu_background", "#00000080"}, + {"menu_item_background", "#FFFFFF40"}, + }}, + { "gruvbox_dark", { + {"piece_brick", "#cc241d"}, + {"piece_brick_out", "#fb4934"}, + {"piece_T", "#98971a"}, + {"piece_T_out", "#b8bb26"}, + {"piece_L_right", "#458588"}, + {"piece_L_right_out", "#83a598"}, + {"piece_Z_right", "#b16286"}, + {"piece_Z_right_out", "#d3869b"}, + {"piece_line", "#d79921"}, + {"piece_line_out", "#fabd2f"}, + {"piece_L_left", "#689d6a"}, + {"piece_L_left_out", "#8ec07c"}, + {"piece_Z_left", "#a89984"}, + {"piece_Z_left_out", "#ebdbb2"}, + {"shadow", "#bdae9380"}, + {"background", "#282828"}, + {"line", "#fbf1c7"}, + {"barrier", "#d65d0e"}, + {"text", "#ebdbb2"}, + {"text_out", "#1d2021"}, + {"menu_background", "#28282880"}, + {"menu_item_background", "#d5c4a180"}, + }}, + { "blackandwhite", { + {"piece_brick", "#FFFFFF"}, + {"piece_brick_out", "#000000"}, + {"piece_T", "#FFFFFF"}, + {"piece_T_out", "#000000"}, + {"piece_L_right", "#FFFFFF"}, + {"piece_L_right_out", "#000000"}, + {"piece_Z_right", "#FFFFFF"}, + {"piece_Z_right_out", "#000000"}, + {"piece_line", "#FFFFFF"}, + {"piece_line_out", "#000000"}, + {"piece_L_left", "#FFFFFF"}, + {"piece_L_left_out", "#000000"}, + {"piece_Z_left", "#FFFFFF"}, + {"piece_Z_left_out", "#000000"}, + {"shadow", "#FFFFFF80"}, + {"background", "#000000"}, + {"line", "#FFFFFF"}, + {"barrier", "#FFFFFF"}, + {"text", "#FFFFFF"}, + {"text_out", "#000000"}, + {"menu_background", "#00000080"}, + {"menu_item_background", "#FFFFFF40"}, + }}, +}; +std::vector color_schemes_names = { "default", "gruvbox_dark", "blackandwhite" }; +long unsigned int selected_color_scheme = 0; +bool g_show_shadow = true; diff --git a/tetris/config.hpp b/tetris/config.hpp index 809b33d..4f3c939 100644 --- a/tetris/config.hpp +++ b/tetris/config.hpp @@ -1,78 +1,62 @@ +#ifndef TETRIS_CONFIG_H +#define TETRIS_CONFIG_H #include #include #include -std::map> color_schemes = { - { "default", { - {"piece_brick", "#FF0000"}, - {"piece_brick_out", "#AA0000"}, - {"piece_T", "#00FF00"}, - {"piece_T_out", "#00AA00"}, - {"piece_L_right", "#0000FF"}, - {"piece_L_right_out", "#0000AA"}, - {"piece_Z_right", "#FF00FF"}, - {"piece_Z_right_out", "#AA00AA"}, - {"piece_line", "#FFFF00"}, - {"piece_line_out", "#AAAA00"}, - {"piece_L_left", "#00FFFF"}, - {"piece_L_left_out", "#00AAAA"}, - {"piece_Z_left", "#FFFFFF"}, - {"piece_Z_left_out", "#AAAAAA"}, - {"shadow", "#AAAAAAAA"}, - {"background", "#222222"}, - {"line", "#888888"}, - {"barrier", "#AA0000"}, - {"text", "#FFFFFF"}, - {"text_out", "#000000"}, - {"menu_background", "#00000080"}, - {"menu_item_background", "#FFFFFF40"}, - }}, - { "gruvbox_dark", { - {"piece_brick", "#cc241d"}, - {"piece_brick_out", "#fb4934"}, - {"piece_T", "#98971a"}, - {"piece_T_out", "#b8bb26"}, - {"piece_L_right", "#458588"}, - {"piece_L_right_out", "#83a598"}, - {"piece_Z_right", "#b16286"}, - {"piece_Z_right_out", "#d3869b"}, - {"piece_line", "#d79921"}, - {"piece_line_out", "#fabd2f"}, - {"piece_L_left", "#689d6a"}, - {"piece_L_left_out", "#8ec07c"}, - {"piece_Z_left", "#a89984"}, - {"piece_Z_left_out", "#ebdbb2"}, - {"shadow", "#bdae9380"}, - {"background", "#282828"}, - {"line", "#fbf1c7"}, - {"barrier", "#d65d0e"}, - {"text", "#ebdbb2"}, - {"text_out", "#1d2021"}, - {"menu_background", "#28282880"}, - {"menu_item_background", "#d5c4a180"}, - }}, - { "blackandwhite", { - {"piece_brick", "#FFFFFF"}, - {"piece_brick_out", "#000000"}, - {"piece_T", "#FFFFFF"}, - {"piece_T_out", "#000000"}, - {"piece_L_right", "#FFFFFF"}, - {"piece_L_right_out", "#000000"}, - {"piece_Z_right", "#FFFFFF"}, - {"piece_Z_right_out", "#000000"}, - {"piece_line", "#FFFFFF"}, - {"piece_line_out", "#000000"}, - {"piece_L_left", "#FFFFFF"}, - {"piece_L_left_out", "#000000"}, - {"piece_Z_left", "#FFFFFF"}, - {"piece_Z_left_out", "#000000"}, - {"shadow", "#FFFFFF80"}, - {"background", "#000000"}, - {"line", "#FFFFFF"}, - {"barrier", "#FFFFFF"}, - {"text", "#FFFFFF"}, - {"text_out", "#000000"}, - {"menu_background", "#00000080"}, - {"menu_item_background", "#FFFFFF40"}, - }}, -}; +#define COLIDER_ID 0x00000001 +#define BRICK_ID 0x00000002 +#define GAME_OVER 0x00000003 +#define SHADOW_ID 0x00000004 +#define BORDER_LEFT_ID 0x00000005 +#define BORDER_RIGHT_ID 0x00000006 +#define FLOOR_ID 0x00000007 +#define SCORE_TEXTURE_ID 0x00000008 +#define BACKGROUND_ID 0x00000009 +#define LINE_ID 0x0000000A +#define BARRIER_ID 0x0000000B +#define TEXT_ID 0x0000000C + +#define MENU_ITEM_ID 0x00000001 +#define MENU_BACKGROUND_ID 0x00000002 +#define MENU_TEXT_ID 0x00000003 + +#define LEFT_BORDER 0.3 +#define RIGHT_BORDER 0.7 +#define BOTTOM_BORDER 1 +#define TOP_BORDER 0.16 +#define BLOCK_SIZE 0.04 + +#define PIECE_BRICK 0 +#define PIECE_T 1 +#define PIECE_L_RIGHT 2 +#define PIECE_Z_RIGHT 3 +#define PIECE_LINE 4 +#define PIECE_L_LEFT 5 +#define PIECE_Z_LEFT 6 + +#define TICKS_TILL_FALL 500 +#define TICKS_TILL_DESCEND 50 +#define TICKS_TILL_MOVE 100 + +#define PAUSE_PAUSE 1 +#define PAUSE_GAME_OVER 2 + +#define TETRIS_BRICK 0 +#define TETRIS_T 1 +#define TETRIS_L_RIGHT 2 +#define TETRIS_Z_RIGHT 3 +#define TETRIS_LINE 4 +#define TETRIS_L_LEFT 5 +#define TETRIS_Z_LEFT 6 + +#define PIECE_ACTION_UPDATE_COLOR 0 + +#define colors color_schemes[color_schemes_names[selected_color_scheme]] + +extern std::map> color_schemes; +extern std::vector color_schemes_names; +extern long unsigned int selected_color_scheme; +extern bool g_show_shadow; + +#endif diff --git a/tetris/custom_classes.hpp b/tetris/custom_classes.hpp new file mode 100644 index 0000000..31e41f3 --- /dev/null +++ b/tetris/custom_classes.hpp @@ -0,0 +1,267 @@ +#ifndef TETRIS_CUSTOM_CLASSES_H +#define TETRIS_CUSTOM_CLASSES_H + +#include "../sdlpp.hpp" +#include "config.hpp" + +class TetrisBlock : public SDLPP::RectangleRender { +public: + TetrisBlock() = delete; + TetrisBlock( double x, double y, double w, double h, + const std::shared_ptr< SDLPP::Renderer > &r, + const std::string &img_or_color, bool is_polygon, + int index, std::shared_ptr scene, std::vector &bag ) + : RectangleRender( x, y, w, h, r, img_or_color, is_polygon ), pieces_bag(bag) { + _index = index; + pieces_bag[_index]--; + _scene = scene; + } + TetrisBlock( const TetrisBlock &other ) : TetrisBlock(other.getDoubleRect().first.first,other.getDoubleRect().first.second,other.getDoubleRect().second.first,other.getDoubleRect().second.second,other.getRenderer(), other.getColor(), true, other._index, other._scene, other.pieces_bag) {} + ~TetrisBlock() { + pieces_bag[_index]++; + } + virtual std::shared_ptr copySelf() override { + return std::make_shared(*this); + } + std::shared_ptr copyInScene() { + auto ret = std::shared_ptr(new TetrisBlock(*this)); + _scene->addObject(ret); + return ret; + } + bool isSamePos(const SDLPP::RenderObject &other) const { + auto mypos = getPos(); + auto otherpos = other.getPos(); + auto diff1 = mypos.first - otherpos.first; + diff1 = (diff1 < 0) * (-1) * diff1 + (diff1 > 0) * diff1; + auto diff2 = mypos.second - otherpos.second; + diff2 = (diff2 < 0) * (-1) * diff2 + (diff2 > 0) * diff2; + return diff1 < 0.0001 && diff2 < 0.0001; + } + virtual void specialAction( int code ) override { + switch(code) { + case PIECE_ACTION_UPDATE_COLOR: { + auto piece_name = getPieceName(); + setColor(colors[piece_name]); + setOutlineColor(colors[piece_name + "_out"]); + } + default: + break; + } + } + +private: + std::string getPieceName() { + switch(_index) { + case PIECE_BRICK: + return "piece_brick"; + case PIECE_T: + return "piece_T"; + case PIECE_L_RIGHT: + return "piece_L_right"; + case PIECE_Z_RIGHT: + return "piece_Z_right"; + case PIECE_LINE: + return "piece_line"; + case PIECE_L_LEFT: + return "piece_L_left"; + case PIECE_Z_LEFT: + return "piece_Z_left"; + default: + break; + } + return ""; + } + int _index = 0; + std::shared_ptr _scene; + std::vector &pieces_bag; +}; + +class TetrisPiece { +public: + TetrisPiece() { + original_pos.reserve( 4 ); + } + void addPiece( std::shared_ptr< TetrisBlock > piece, int x, + int y ) { + pieces.push_back( piece ); + pieces_rel_position.push_back( { 0, 0, 0, 0 } ); + // done this way for SPEEEEEEED + // left + pieces_rel_position.back()[0] = ( x < 0 ) * ( -1 ) * x; + // right + pieces_rel_position.back()[1] = ( x > 0 ) * x; + // top + pieces_rel_position.back()[2] = ( y < 0 ) * ( -1 ) * y; + // bottom + pieces_rel_position.back()[3] = ( y > 0 ) * y; + } + void rotate() { + if(!rotate_allowed) + return; + for ( unsigned long i = 0; i < pieces.size(); i++ ) { + auto &piece = pieces[i]; + auto &positions = pieces_rel_position[i]; + auto position = piece->getPos(); + original_pos[i] = position; + position.first += positions[0] * BLOCK_SIZE; + position.first -= positions[1] * BLOCK_SIZE; + position.second += positions[2] * BLOCK_SIZE; + position.second -= positions[3] * BLOCK_SIZE; + auto bottom = positions[3]; + auto top = positions[2]; + positions[3] = positions[1]; + positions[2] = positions[0]; + positions[1] = top; + positions[0] = bottom; + position.first -= positions[0] * BLOCK_SIZE; + position.first += positions[1] * BLOCK_SIZE; + position.second -= positions[2] * BLOCK_SIZE; + position.second += positions[3] * BLOCK_SIZE; + piece->setPos( position.first, position.second ); + } + } + void revert() { + for ( unsigned long i = 0; i < pieces.size(); i++ ) { + auto &piece = pieces[i]; + auto &positions = pieces_rel_position[i]; + piece->setPos( original_pos[i].first, original_pos[i].second ); + auto top = positions[1]; + auto bottom = positions[0]; + positions[1] = positions[3]; + positions[0] = positions[2]; + positions[2] = top; + positions[3] = bottom; + } + } + std::vector< std::shared_ptr< TetrisBlock > > &getObjects() { + return pieces; + } + void setPos( double x, double y ) { + for ( unsigned long i = 0; i < pieces.size(); i++ ) { + auto &piece = pieces[i]; + auto &positions = pieces_rel_position[i]; + std::pair pos = {x, y}; + pos.first -= positions[0] * BLOCK_SIZE; + pos.first += positions[1] * BLOCK_SIZE; + pos.second -= positions[2] * BLOCK_SIZE; + pos.second += positions[3] * BLOCK_SIZE; + piece->setPos( pos.first, pos.second ); + } + } + void setPos(const std::pair &pos) { + setPos(pos.first, pos.second); + } + std::pair getPos() { + auto &piece = pieces[0]; + auto &relpositions = pieces_rel_position[0]; + auto pos = piece->getPos(); + pos.first += relpositions[0] * BLOCK_SIZE; + pos.first -= relpositions[1] * BLOCK_SIZE; + pos.second += relpositions[2] * BLOCK_SIZE; + pos.second -= relpositions[3] * BLOCK_SIZE; + return pos; + } + void clear() { + pieces.clear(); + pieces_rel_position.clear(); + } + void startDescend() { + descend = true; + } + void stopDescend() { + descend = false; + } + void startMovement() { + userMovement += 1; + } + void stopMovement() { + userMovement -= 1; + } + bool isDescending() { + return descend; + } + bool isMoving() { + return userMovement > 0; + } + bool isLeft(const SDLPP::RenderObject &block) const { + return isPosition(block, 0); + } + bool isRight(const SDLPP::RenderObject &block) const { + return isPosition(block, 1); + } + void movePiece(double x, double y) { + for ( auto &block : getObjects() ) { + auto pos = block->getPos(); + block->setPos( pos.first + x, pos.second + y ); + } + } + void disableRotation() { + rotate_allowed = false; + } + + void turnIntoShadow() { + for(auto &block : getObjects() ) { + block->setId(SHADOW_ID); + block->setColor(colors["shadow"]); + } + setHidden(!g_show_shadow); + } + std::shared_ptr copySelf() { + auto ret = std::make_shared(); + for(int i = 0; i < 4; i++) { + auto block = pieces[i]->copyInScene(); + block->centerX(); + ret->addBlockInPos(block, pieces_rel_position[i]); + } + return ret; + } + void destroy() { + for(auto &x : getObjects()) { + x->destroy(); + } + } + void addMovement(int x, int y) { + movement.first += x; + movement.second += y; + } + std::pair getMovement() const { + return movement; + } + void setHidden(bool hidden) { + _hidden = hidden; + for(auto &x : getObjects()) { + x->setHidden(hidden); + } + } + bool getHidden() { + return _hidden; + } + +private: + bool isPosition(const SDLPP::RenderObject &block, int pos) const { + for(int i = 0; i < 4; i++) { + if(pieces[i]->isSamePos(block)) { + return pieces_rel_position[i][pos] != 0; + } + } + return false; + } + void resetBlock(int index, std::shared_ptr< TetrisBlock > piece) { + piece->setPos(pieces[index]->getPos()); + pieces[index] = piece; + } + void addBlockInPos(std::shared_ptr piece, const std::vector &relpos) { + pieces.push_back( piece ); + pieces_rel_position.push_back(relpos); + } + std::vector< std::vector< int > > pieces_rel_position; + std::vector< std::shared_ptr< TetrisBlock > > pieces; + std::vector< std::pair< double, double > > original_pos; + bool descend = false; + int userMovement = 0; + bool rotate_allowed = true; + std::pair movement = {0,0}; + bool _hidden = false; +}; + +#endif diff --git a/tetris/functions.cpp b/tetris/functions.cpp new file mode 100644 index 0000000..1d881ff --- /dev/null +++ b/tetris/functions.cpp @@ -0,0 +1,414 @@ +#include "functions.hpp" +#include "custom_classes.hpp" +#include "global_vars.hpp" +#include "scenes.hpp" +#include + +bool validPos(SDLPP::Scene &scene, std::shared_ptr piece) { + auto ret = true; + for ( auto &x : piece->getObjects() ) { + auto collisions = scene.getCollisions( *x, { BRICK_ID, FLOOR_ID, BORDER_LEFT_ID, BORDER_RIGHT_ID } ); + if ( collisions.size() > 1 ) { + ret = false; + break; + } + } + return ret; +} + +void updateShadow(SDLPP::Scene &scene) { + if(!g_cur_object) { + g_cur_shadow->destroy(); + g_cur_shadow.reset(); + 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() ) { + if(BOTTOM_BORDER - x->getPos().second < shadow_drop) + shadow_drop = BOTTOM_BORDER - x->getPos().second; + g_shadow_colider->setPos(x->getPos().first, TOP_BORDER); + auto collisions = scene.getCollisions( *g_shadow_colider, { BRICK_ID } ); + auto curY = x->getPos().second; + for(auto &col : collisions) { + auto colY = col->getPos().second; + if(std::find(invalid_objects.begin(), invalid_objects.end(), col) != invalid_objects.end()) + continue; + auto possible_drop = colY - curY; + if(possible_drop < shadow_drop && possible_drop >= 0) + shadow_drop = colY - curY; + } + } + shadow_drop -= BLOCK_SIZE; + g_cur_shadow->setPos(g_cur_shadow->getPos().first, g_cur_shadow->getPos().second + shadow_drop); +} + +void moveThem( std::shared_ptr< SDLPP::Scene > scene, int ticks ) { + 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->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; + } + 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; + } + 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 } ); + 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_pause = PAUSE_GAME_OVER; + 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_pause = 0; + 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_next_object = g_tetrisFunctions[std::rand() / ( ( RAND_MAX + 1u ) / 7 )]( + g_main_scene->getRendererShared(), g_main_scene ); + g_next_object->setPos( 0.9, 0.5 ); + g_active_scenes.push_back( g_main_scene ); + g_active_scenes = {g_main_scene}; + g_input_functions = {mainSceneInput}; +} + +int crashFlags( std::shared_ptr piece, std::shared_ptr 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 |= right; + 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 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(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(x)->setTextColor(*g_font, colors["text"], colors["text_out"]); + } + +} diff --git a/tetris/functions.hpp b/tetris/functions.hpp new file mode 100644 index 0000000..424a7c8 --- /dev/null +++ b/tetris/functions.hpp @@ -0,0 +1,37 @@ +#ifndef TETRIS_FUNCTIONS_H +#define TETRIS_FUNCTIONS_H + +#include "../sdlpp.hpp" +#include "custom_classes.hpp" + +void moveThem( std::shared_ptr< SDLPP::Scene > scene, int ticks ); +bool validPos(SDLPP::Scene &scene, std::shared_ptr piece); +void updateShadow(SDLPP::Scene &scene); +void quitGame(); +void resetGame(); +bool checkRotation( std::shared_ptr piece, SDLPP::Scene &scene ); + +std::shared_ptr< TetrisPiece > +tetrisBrick( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +std::shared_ptr< TetrisPiece > +tetrisT( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +std::shared_ptr< TetrisPiece > +tetrisLRight( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +std::shared_ptr< TetrisPiece > +tetrisZRight( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +std::shared_ptr< TetrisPiece > +tetrisLine( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +std::shared_ptr< TetrisPiece > +tetrisLLeft( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +std::shared_ptr< TetrisPiece > +tetrisZLeft( std::shared_ptr< SDLPP::Renderer > renderer, + std::shared_ptr< SDLPP::Scene > scene ); +void updateColors(); + +#endif diff --git a/tetris/global_vars.cpp b/tetris/global_vars.cpp new file mode 100644 index 0000000..197cd19 --- /dev/null +++ b/tetris/global_vars.cpp @@ -0,0 +1,53 @@ +#include "global_vars.hpp" +#include "config.hpp" +#include "functions.hpp" + +int g_ticks_till_fall = TICKS_TILL_FALL; +int g_ticks_till_descend = TICKS_TILL_DESCEND; +int g_ticks_till_movement = TICKS_TILL_MOVE; +int g_pause = 0; + +int g_menu_select = 0; +int g_menu_max = 3; +int g_game_over_select = 0; +int g_game_over_max = 1; +int g_options_select = 0; +int g_options_max = 2; +std::vector< std::shared_ptr< SDLPP::RectangleRender > > g_menu_options{}; +std::vector< std::shared_ptr< SDLPP::RectangleRender > > g_game_over_options{}; +std::vector< std::shared_ptr< SDLPP::RectangleRender > > g_options_options{}; +std::shared_ptr< SDLPP::TextRenderer > g_score_texture{}; +std::shared_ptr< SDLPP::Renderer > g_active_renderer{}; +int g_score = 0; +bool g_update_score = false; +bool g_update_colors = false; +bool g_checked_line = false; +bool g_wait_for_anim = false; + +std::vector< int > g_bag = { 28, 28, 28, 28, 28, 28, 28 }; + +std::shared_ptr< SDLPP::Scene > g_main_scene{}; +std::shared_ptr< SDLPP::Scene > g_menu_scene{}; +std::shared_ptr< SDLPP::Scene > g_game_over_scene{}; +std::shared_ptr< SDLPP::Scene > g_options_scene{}; + +std::shared_ptr< TetrisPiece > g_cur_object{}; +bool g_object_falling = false; +std::shared_ptr< TetrisPiece > g_next_object{}; +std::shared_ptr< TetrisPiece > g_cur_shadow{}; +std::shared_ptr< SDLPP::RectangleRender > g_shadow_colider{}; + +std::mutex g_movement_mutex{}; + +bool g_quit = false; +std::vector, int, std::vector>&)>>g_input_functions{}; +std::vector> g_active_scenes{}; + +std::vector< std::shared_ptr< TetrisPiece > ( * )( + std::shared_ptr< SDLPP::Renderer >, std::shared_ptr< SDLPP::Scene > ) > + g_tetrisFunctions = { + tetrisBrick, tetrisT, tetrisLRight, tetrisZRight, + tetrisLine, tetrisLLeft, tetrisZLeft, + }; + +std::shared_ptr g_font{}; diff --git a/tetris/global_vars.hpp b/tetris/global_vars.hpp new file mode 100644 index 0000000..d8c37aa --- /dev/null +++ b/tetris/global_vars.hpp @@ -0,0 +1,56 @@ +#ifndef TETRIS_GLOBAL_VARS_H +#define TETRIS_GLOBAL_VARS_H + +#include "../sdlpp.hpp" +#include "custom_classes.hpp" + +#include + +extern int g_ticks_till_fall; +extern int g_ticks_till_descend; +extern int g_ticks_till_movement; +extern int g_pause; + +extern int g_menu_select; +extern int g_menu_max; +extern int g_game_over_select; +extern int g_game_over_max; +extern int g_options_select; +extern int g_options_max; +extern std::vector< std::shared_ptr< SDLPP::RectangleRender > > g_menu_options; +extern std::vector< std::shared_ptr< SDLPP::RectangleRender > > g_game_over_options; +extern std::vector< std::shared_ptr< SDLPP::RectangleRender > > g_options_options; +extern std::shared_ptr< SDLPP::TextRenderer > g_score_texture; +extern std::shared_ptr< SDLPP::Renderer > g_active_renderer; +extern int g_score; +extern bool g_update_score; +extern bool g_update_colors; +extern bool g_checked_line; +extern bool g_wait_for_anim; + +extern std::vector< int > g_bag; + +extern std::shared_ptr< SDLPP::Scene > g_main_scene; +extern std::shared_ptr< SDLPP::Scene > g_menu_scene; +extern std::shared_ptr< SDLPP::Scene > g_game_over_scene; +extern std::shared_ptr< SDLPP::Scene > g_options_scene; + +extern std::shared_ptr< TetrisPiece > g_cur_object; +extern bool g_object_falling; +extern std::shared_ptr< TetrisPiece > g_next_object; +extern std::shared_ptr< TetrisPiece > g_cur_shadow; +extern std::shared_ptr< SDLPP::RectangleRender > g_shadow_colider; + +extern std::mutex g_movement_mutex; + +extern bool g_quit; +extern std::vector, int, std::vector>&)>>g_input_functions; +extern std::vector> g_active_scenes; + +extern std::vector< std::shared_ptr< TetrisPiece > ( * )( + std::shared_ptr< SDLPP::Renderer >, std::shared_ptr< SDLPP::Scene > ) > + g_tetrisFunctions; + +extern std::shared_ptr g_font; + +#endif diff --git a/tetris/scenes.cpp b/tetris/scenes.cpp new file mode 100644 index 0000000..274b940 --- /dev/null +++ b/tetris/scenes.cpp @@ -0,0 +1,678 @@ +#include "scenes.hpp" +#include "config.hpp" +#include "functions.hpp" +#include "global_vars.hpp" + +#include + +// Scene preparation + +void addMainSceneItems( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r, std::shared_ptr font ) { + auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, + colors["background"], true ); + bg->setPermanent(); + bg->setId(BACKGROUND_ID); + scene.addObject( bg ); + + // create coliders for counting blocks in line + double posy = 1; + for ( int i = 0; i < 20; i++ ) { + posy -= BLOCK_SIZE; + auto colider = std::make_shared< SDLPP::RectangleRender >( + LEFT_BORDER, posy, RIGHT_BORDER - LEFT_BORDER, BLOCK_SIZE, r ); + colider->addCollision(SDLPP::Rect( 0.01, 0.1, 0.98, 0.8 )); + colider->setId( COLIDER_ID ); + colider->setStatic(); + colider->centerX(); + scene.addObject( colider ); + } + + // create lines on playing field + posy = 1; + for ( int i = 0; i < 20; i++ ) { + posy -= BLOCK_SIZE; + auto line = std::make_shared< SDLPP::LineRenderer >( LEFT_BORDER, posy, RIGHT_BORDER, posy, r, colors["line"] ); + line->setStatic(); + line->centerX(); + line->setId(LINE_ID); + scene.addObject( line ); + } + + auto posx = RIGHT_BORDER; + for ( int i = 0; i < 9; i++ ) { + posx -= BLOCK_SIZE; + auto line = std::make_shared< SDLPP::LineRenderer >( posx, TOP_BORDER + BLOCK_SIZE, posx, BOTTOM_BORDER, r, colors["line"] ); + line->setStatic(); + line->centerX(); + line->setId(LINE_ID); + scene.addObject( line ); + } + + auto left_barrier = std::make_shared< SDLPP::RectangleRender >( + LEFT_BORDER - 0.02, 0, 0.02, BOTTOM_BORDER, r, colors["barrier"], true ); + left_barrier->centerX(); + left_barrier->setStatic(); + left_barrier->setId(BARRIER_ID); + scene.addObject( left_barrier ); + + auto right_barrier = std::make_shared< SDLPP::RectangleRender >( + RIGHT_BORDER, 0, 0.02, BOTTOM_BORDER, r, colors["barrier"], true ); + right_barrier->centerX(); + right_barrier->setStatic(); + right_barrier->setId(BARRIER_ID); + scene.addObject( right_barrier ); + + auto bottom_barrier = std::make_shared< SDLPP::RectangleRender >( + LEFT_BORDER - 0.02, BOTTOM_BORDER, RIGHT_BORDER - LEFT_BORDER + 0.04, + 0.02, r, colors["barrier"], true ); + bottom_barrier->centerX(); + bottom_barrier->setStatic(); + bottom_barrier->setId(BARRIER_ID); + scene.addObject( bottom_barrier ); + + auto tetris = std::make_shared< SDLPP::TextRenderer >( + 0.4, 0, 0.2, 0.1, r, *font, "TETRIS", colors["text"], colors["text_out"], 5 ); + tetris->centerX(); + tetris->setStatic(); + tetris->setId(TEXT_ID); + scene.addObject( tetris ); + + auto next = std::make_shared< SDLPP::TextRenderer >( + RIGHT_BORDER + 0.1, 0.35, 0.2, 0.1, r, *font, "NEXT", colors["text"], colors["text_out"], 5, SDLPP_TEXT_CENTER ); + next->centerX(); + next->setStatic(); + next->setId(TEXT_ID); + scene.addObject( next ); + + // gameover colider + auto gameover = std::make_shared< SDLPP::RectangleRender >( + 0.5, 0, 0, TOP_BORDER + BLOCK_SIZE, r ); + auto gameover_collision = SDLPP::Rect( -1, 0, -1, 0.9 ); + gameover_collision.setInfinite(); + gameover->addCollision( gameover_collision ); + gameover->setId( GAME_OVER ); + gameover->setColiderColor( "FF0000" ); + gameover->setStatic(); + scene.addObject( gameover ); + + auto score_text = std::make_shared< SDLPP::TextRenderer >( + RIGHT_BORDER + 0.1, 0.1, 0.2, 0.1, r, *font, "SCORE", colors["text"], colors["text_out"], 5, SDLPP_TEXT_CENTER ); + score_text->centerX(); + score_text->setStatic(); + score_text->setId(TEXT_ID); + scene.addObject( score_text ); + + auto score_texture = std::make_shared< SDLPP::TextRenderer >( + RIGHT_BORDER + 0.1, 0.2, 0.2, 0.1, r, *font, "0", + colors["text"], colors["text_out"], 5, SDLPP_TEXT_TOP ); + score_texture->centerX(); + score_texture->setStatic(); + score_texture->setId(SCORE_TEXTURE_ID); + scene.addObject( score_texture ); + + + auto border = std::make_shared< SDLPP::RectangleRender >( LEFT_BORDER - 1, 0, 1, BOTTOM_BORDER, r); + border->setId( BORDER_LEFT_ID ); + border->setStatic(); + border->centerX(); + border->addCollision(SDLPP::Rect( 0, 0, 0.99, 1)); + border->setColiderColor("#FF00FF"); + scene.addObject(border); + + border = std::make_shared< SDLPP::RectangleRender >( RIGHT_BORDER, 0, 1, BOTTOM_BORDER, r); + border->setId( BORDER_RIGHT_ID ); + border->setStatic(); + border->centerX(); + border->addCollision(SDLPP::Rect( 0.01, 0, 1, 1)); + border->setColiderColor("#FF00FF"); + scene.addObject(border); + + auto floor = std::make_shared< SDLPP::RectangleRender >( LEFT_BORDER, BOTTOM_BORDER, RIGHT_BORDER - LEFT_BORDER, 1, r); + floor->setId( FLOOR_ID ); + floor->setStatic(); + floor->centerX(); + floor->addCollision(SDLPP::Rect(0, 0.01, 1, 1)); + floor->setColiderColor("#00FF00"); + scene.addObject(floor); +} + +void addMenuSceneItems( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r, std::shared_ptr font ) { + auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, + colors["menu_background"], true ); + bg->setId(MENU_BACKGROUND_ID); + bg->setPermanent( true ); + scene.addObject( bg ); + auto y = std::make_shared< SDLPP::TextRenderer >( 0.25, 0.1, 0.5, 0.3, r ); + y->setText( *font, "PAUSED", colors["text"], colors["text_out"], 5 ); + y->setId( MENU_TEXT_ID ); + y->centerX(); + scene.addObject( y ); + auto resume = + std::make_shared< SDLPP::TextRenderer >( 0.4, 0.46, 0.2, 0.08, r ); + resume->setText( *font, "Resume", colors["text"], colors["text_out"], 5 ); + resume->setColor( colors["menu_item_background"] ); + resume->centerX(); + resume->setId(MENU_ITEM_ID); + g_menu_options.push_back(resume); + scene.addObject( resume ); + auto options = std::make_shared< SDLPP::TextRenderer >(0.4, 0.56, 0.2, 0.08, r); + options->setText(*font, "Options", colors["text"], colors["text_out"], 5); + options->centerX(); + options->setId(MENU_ITEM_ID); + g_menu_options.push_back(options); + scene.addObject(options); + auto restart = + std::make_shared< SDLPP::TextRenderer >( 0.4, 0.66, 0.2, 0.08, r ); + restart->setText( *font, "Restart", colors["text"], colors["text_out"], 5 ); + restart->centerX(); + restart->setId(MENU_ITEM_ID); + g_menu_options.push_back(restart); + scene.addObject( restart ); + auto quit = + std::make_shared< SDLPP::TextRenderer >( 0.4, 0.76, 0.2, 0.08, r ); + quit->setText( *font, "Quit Game", colors["text"], colors["text_out"], 5 ); + quit->centerX(); + quit->setId(MENU_ITEM_ID); + g_menu_options.push_back(quit); + scene.addObject( quit ); +} + +void addGameOverSceneItems( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r, std::shared_ptr font ) { + auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, + colors["menu_background"], true ); + bg->setId( MENU_BACKGROUND_ID ); + bg->setPermanent( true ); + scene.addObject( bg ); + auto y = std::make_shared< SDLPP::TextRenderer >( 0.25, 0.1, 0.5, 0.3, r ); + y->setText( *font, "GAME OVER", colors["text"], colors["text_out"], 5 ); + y->setId( 0 ); + y->centerX(); + scene.addObject( y ); + auto restart = + std::make_shared< SDLPP::TextRenderer >( 0.4, 0.5, 0.2, 0.1, r ); + restart->setText( *font, "Restart", colors["text"], colors["text_out"], 5 ); + restart->centerX(); + restart->setColor( colors["menu_item_background"] ); + restart->setId(MENU_ITEM_ID); + g_game_over_options.push_back(restart); + scene.addObject( restart ); + auto quit = + std::make_shared< SDLPP::TextRenderer >( 0.4, 0.7, 0.2, 0.1, r ); + quit->setText( *font, "Quit Game", colors["text"], colors["text_out"], 5 ); + quit->centerX(); + quit->setId(MENU_ITEM_ID); + g_game_over_options.push_back(quit); + scene.addObject( quit ); +} + +void addOptionsSceneItems( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r, std::shared_ptr font ) { + auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, + colors["menu_background"], true ); + bg->setId( MENU_BACKGROUND_ID ); + bg->setPermanent( true ); + scene.addObject( bg ); + auto y = std::make_shared< SDLPP::TextRenderer >( 0.25, 0.1, 0.5, 0.3, r ); + y->setText( *font, "OPTIONS", colors["text"], colors["text_out"], 5 ); + y->setId( 0 ); + y->centerX(); + scene.addObject( y ); + auto color_scheme = + std::make_shared< SDLPP::TextRenderer >( 0.35, 0.4, 0.3, 0.09, r ); + color_scheme->setText( *font, "Color scheme: " + color_schemes_names[selected_color_scheme], colors["text"], colors["text_out"], 5 ); + color_scheme->centerX(); + color_scheme->setColor( colors["menu_item_background"] ); + color_scheme->setId(MENU_ITEM_ID); + g_options_options.push_back(color_scheme); + scene.addObject( color_scheme ); + auto shadow = + std::make_shared< SDLPP::TextRenderer >( 0.4, 0.5, 0.2, 0.09, r ); + shadow->setText( *font, "Show shadow: YES", colors["text"], colors["text_out"], 5 ); + shadow->centerX(); + shadow->setId(MENU_ITEM_ID); + g_options_options.push_back(shadow); + scene.addObject(shadow); + auto save = + std::make_shared< SDLPP::TextRenderer >( 0.45, 0.6, 0.1, 0.09, r ); + save->setText( *font, "SAVE", colors["text"], colors["text_out"], 5 ); + save->centerX(); + save->setId(MENU_ITEM_ID); + g_options_options.push_back(save); + scene.addObject( save ); +} + +std::shared_ptr prepareMainScene(std::shared_ptr renderer, std::shared_ptr font) { + auto scene = std::make_shared< SDLPP::Scene >( renderer ); + addMainSceneItems( *scene, renderer, font ); + return scene; +} + +std::shared_ptr prepareMenuScene(std::shared_ptr renderer, std::shared_ptr font) { + auto scene = std::make_shared< SDLPP::Scene >( renderer ); + addMenuSceneItems(*scene, renderer, font); + return scene; +} + +std::shared_ptr prepareGameOverScene(std::shared_ptr renderer, std::shared_ptr font) { + auto scene = std::make_shared< SDLPP::Scene >( renderer ); + addGameOverSceneItems(*scene, renderer, font); + return scene; +} + +std::shared_ptr prepareOptionsScene(std::shared_ptr renderer, std::shared_ptr font) { + auto scene = std::make_shared< SDLPP::Scene >( renderer ); + addOptionsSceneItems(*scene, renderer, font); + return scene; +} + +// Input handling + +void handleKeyDownMain( SDL_Keycode key, SDLPP::Scene &scene ) { + switch ( key ) { + case SDLK_ESCAPE: + g_pause = PAUSE_PAUSE; + g_menu_scene->updateSizeAndPosition(); + g_active_scenes.push_back( g_menu_scene ); + g_input_functions.push_back(menuSceneInput); + break; + case SDLK_LEFT: + case SDLK_a: + if(!g_cur_object) + break; + g_cur_object->movePiece(-BLOCK_SIZE, 0); + if(!validPos(scene, g_cur_object)) + g_cur_object->movePiece(BLOCK_SIZE, 0); + updateShadow(scene); + + g_ticks_till_movement = 2*TICKS_TILL_MOVE; + g_cur_object->startMovement(); + g_cur_object->addMovement(-1,0); + break; + case SDLK_RIGHT: + case SDLK_d: + if(!g_cur_object) + break; + g_cur_object->movePiece(BLOCK_SIZE, 0); + if(!validPos(scene, g_cur_object)) + g_cur_object->movePiece(-BLOCK_SIZE, 0); + updateShadow(scene); + + g_ticks_till_movement = 2*TICKS_TILL_MOVE; + g_cur_object->startMovement(); + g_cur_object->addMovement(1,0); + break; + case SDLK_DOWN: + case SDLK_s: + if(!g_cur_object) + break; + g_cur_object->startDescend(); + g_cur_object->addMovement(0,1); + break; + case SDLK_UP: + case SDLK_w: + if(!g_cur_object) + break; + g_cur_object->rotate(); + if( checkRotation( g_cur_object, scene ) ) + g_cur_shadow->rotate(); + updateShadow(scene); + break; + case SDLK_r: + scene.getRenderer().setRenderColiders( + !scene.getRenderer().getRenderColiders() ); + default: + break; + } +} + +void handleKeyUpMain( SDL_Keycode key ) { + switch(key) { + case SDLK_DOWN: + case SDLK_s: + if(!g_cur_object) + break; + if(g_cur_object->isDescending()) { + g_cur_object->stopDescend(); + g_cur_object->addMovement(0,-1); + g_ticks_till_descend = TICKS_TILL_DESCEND; + } + break; + case SDLK_LEFT: + case SDLK_a: + if(!g_cur_object) + break; + if(g_cur_object->isMoving()) { + g_cur_object->stopMovement(); + g_cur_object->addMovement(1,0); + if(g_cur_object->isMoving()) + g_ticks_till_movement = TICKS_TILL_MOVE; + } + break; + case SDLK_RIGHT: + case SDLK_d: + if(!g_cur_object) + break; + if(g_cur_object->isMoving()) { + g_cur_object->stopDescend(); + g_cur_object->addMovement(-1,0); + if(g_cur_object->isMoving()) + g_ticks_till_movement = TICKS_TILL_MOVE; + } + default: + break; + } +} + + +void pollEventsMain( SDLPP::Scene &scene ) { + SDL_Event event; + while ( SDL_PollEvent( &event ) != 0 ) { + switch ( event.type ) { + case SDL_QUIT: + quitGame(); + break; + case SDL_KEYDOWN: + if ( !event.key.repeat ) + handleKeyDownMain( event.key.keysym.sym, scene ); + break; + case SDL_KEYUP: + handleKeyUpMain( event.key.keysym.sym ); + break; + case SDL_WINDOWEVENT: + if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) { + for(auto &x : g_active_scenes) + x->updateSizeAndPosition(); + } + default: + break; + } + } +} + +void mainSceneInput( std::shared_ptr< SDLPP::Scene > scene, int base, std::vector> &line_coliders ) { + std::lock_guard< std::mutex > guard( g_movement_mutex ); + pollEventsMain( *scene ); + if ( g_cur_object ) { + moveThem( scene, SDL_GetTicks() - base ); + return; + } + for ( auto &colider : line_coliders ) { + auto collisions = scene->getCollisions( *colider, { BRICK_ID } ); + while ( collisions.size() == 10 ) { + g_score += 10; + g_update_score = true; + for ( auto &col : collisions ) { + col->destroy(); + } + auto colider_y = colider->getPos().second; + for ( auto &elem : scene->getObjects() ) { + if ( elem->getId() != BRICK_ID ) + continue; + auto pos = elem->getPos(); + if ( pos.second < colider_y && pos.first >= LEFT_BORDER && pos.first <= RIGHT_BORDER ) { + elem->setPos( pos.first, pos.second + BLOCK_SIZE ); + } + } + using namespace std::chrono_literals; + g_wait_for_anim = true; + while ( g_wait_for_anim ) { + std::this_thread::sleep_for( 0.1s ); + } + collisions = scene->getCollisions( *colider, { BRICK_ID } ); + } + } + g_checked_line = true; +} + +void handleKeyDownMenu( SDL_Keycode key ) { + switch ( key ) { + case SDLK_ESCAPE: { + g_pause = 0; + g_main_scene->setPrevTicks( SDL_GetTicks() ); + g_active_scenes.pop_back(); + g_input_functions.pop_back(); + } break; + case SDLK_r: + g_main_scene->getRenderer().setRenderColiders( + !g_main_scene->getRenderer().getRenderColiders() ); + break; + case SDLK_s: + case SDLK_DOWN: + g_menu_options[g_menu_select]->unsetColor(); + g_menu_select++; + if ( g_menu_select > g_menu_max ) + g_menu_select = 0; + g_menu_options[g_menu_select]->setColor( colors["menu_item_background"] ); + break; + case SDLK_w: + case SDLK_UP: + g_menu_options[g_menu_select]->unsetColor(); + g_menu_select--; + if ( g_menu_select < 0 ) + g_menu_select = g_menu_max; + g_menu_options[g_menu_select]->setColor( colors["menu_item_background"] ); + break; + case SDLK_RETURN: + switch ( g_menu_select ) { + case 0: { + g_pause = 0; + g_main_scene->setPrevTicks( SDL_GetTicks() ); + g_active_scenes.pop_back(); + g_input_functions.pop_back(); + } break; + case 1: + g_pause = PAUSE_PAUSE; + g_options_scene->updateSizeAndPosition(); + g_active_scenes.push_back(g_options_scene); + g_input_functions.push_back(optionsSceneInput); + break; + case 2: + resetGame(); + break; + case 3: + quitGame(); + default: + break; + } + default: + break; + } +} + +void pollEventsMenu() { + SDL_Event event; + while ( SDL_PollEvent( &event ) != 0 ) { + switch ( event.type ) { + case SDL_QUIT: + quitGame(); + break; + case SDL_KEYDOWN: + if ( !event.key.repeat ) + handleKeyDownMenu( event.key.keysym.sym ); + break; + case SDL_WINDOWEVENT: + if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) { + for(auto &x : g_active_scenes) + x->updateSizeAndPosition(); + } + default: + break; + } + } +} + +void menuSceneInput( std::shared_ptr< SDLPP::Scene > /*UNUSED*/, int /*UNUSED*/, std::vector> &/*UNUSED*/ ) { + pollEventsMenu(); +} + +void handleKeyDownGameOver( SDL_Keycode key ) { + switch ( key ) { + case SDLK_r: + g_main_scene->getRenderer().setRenderColiders( + !g_main_scene->getRenderer().getRenderColiders() ); + break; + case SDLK_s: + case SDLK_DOWN: + g_game_over_options[g_game_over_select]->unsetColor(); + g_game_over_select++; + if ( g_game_over_select > g_game_over_max ) + g_game_over_select = 0; + g_game_over_options[g_game_over_select]->setColor( colors["menu_item_background"] ); + break; + case SDLK_w: + case SDLK_UP: + g_game_over_options[g_game_over_select]->unsetColor(); + g_game_over_select--; + if ( g_game_over_select < 0 ) + g_game_over_select = g_game_over_max; + g_game_over_options[g_game_over_select]->setColor( colors["menu_item_background"] ); + break; + case SDLK_RETURN: + switch ( g_game_over_select ) { + case 0: + resetGame(); + break; + case 1: + quitGame(); + default: + break; + } + default: + break; + } +} + +void pollEventsGameOver() { + SDL_Event event; + while ( SDL_PollEvent( &event ) != 0 ) { + switch ( event.type ) { + case SDL_QUIT: + quitGame(); + break; + case SDL_KEYDOWN: + if ( !event.key.repeat ) + handleKeyDownGameOver( event.key.keysym.sym ); + break; + case SDL_WINDOWEVENT: + if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) { + for(auto &x : g_active_scenes) + x->updateSizeAndPosition(); + } + default: + break; + } + } +} + +void gameOverSceneInput( std::shared_ptr< SDLPP::Scene > /*UNUSED*/, int /*UNUSED*/, std::vector> &/*UNUSED*/ ) { + pollEventsGameOver(); +} + +void handleKeyDownOptions( SDL_Keycode key ) { + switch ( key ) { + case SDLK_r: + g_main_scene->getRenderer().setRenderColiders( + !g_main_scene->getRenderer().getRenderColiders() ); + break; + case SDLK_s: + case SDLK_DOWN: + g_options_options[g_options_select]->unsetColor(); + g_options_select++; + if ( g_options_select > g_options_max ) + g_options_select = 0; + g_options_options[g_options_select]->setColor( colors["menu_item_background"] ); + break; + case SDLK_w: + case SDLK_UP: + g_options_options[g_options_select]->unsetColor(); + g_options_select--; + if ( g_options_select < 0 ) + g_options_select = g_options_max; + g_options_options[g_options_select]->setColor( colors["menu_item_background"] ); + break; + case SDLK_RIGHT: + case SDLK_d: + switch( g_options_select ) { + case 0: + selected_color_scheme++; + if(selected_color_scheme >= color_schemes_names.size()) + selected_color_scheme = 0; + std::dynamic_pointer_cast(g_options_options[0])->changeText("Color scheme: " + color_schemes_names[selected_color_scheme]); + g_update_colors = true; + break; + case 1: + g_show_shadow = !g_show_shadow; + std::dynamic_pointer_cast(g_options_options[1])->changeText(std::string("Show shadow: ") + (g_show_shadow ? "YES" : "NO")); + g_update_colors = true; + default: + break; + } + break; + case SDLK_LEFT: + case SDLK_a: + switch( g_options_select ) { + case 0: + if(selected_color_scheme == 0) + selected_color_scheme = color_schemes_names.size(); + selected_color_scheme--; + std::dynamic_pointer_cast(g_options_options[0])->changeText("Color scheme: " + color_schemes_names[selected_color_scheme]); + g_update_colors = true; + break; + case 1: + g_show_shadow = !g_show_shadow; + std::dynamic_pointer_cast(g_options_options[1])->changeText(std::string("Show shadow: ") + (g_show_shadow ? "YES" : "NO")); + g_update_colors = true; + default: + break; + } + break; + case SDLK_RETURN: + switch ( g_options_select ) { + case 2: + g_update_colors = true; + g_cur_shadow->setHidden(!g_show_shadow); + g_pause = 0; + g_main_scene->setPrevTicks( SDL_GetTicks() ); + g_active_scenes.pop_back(); + g_input_functions.pop_back(); + break; + default: + break; + } + break; + case SDLK_ESCAPE: + g_update_colors = true; + g_cur_shadow->setHidden(!g_show_shadow); + g_pause = 0; + g_main_scene->setPrevTicks( SDL_GetTicks() ); + g_active_scenes.pop_back(); + g_input_functions.pop_back(); + default: + break; + } +} + +void pollEventsOptions() { + SDL_Event event; + while ( SDL_PollEvent( &event ) != 0 ) { + switch ( event.type ) { + case SDL_QUIT: + quitGame(); + break; + case SDL_KEYDOWN: + if ( !event.key.repeat ) + handleKeyDownOptions( event.key.keysym.sym ); + break; + case SDL_WINDOWEVENT: + if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) { + for(auto &x : g_active_scenes) + x->updateSizeAndPosition(); + } + default: + break; + } + } +} + +void optionsSceneInput( std::shared_ptr< SDLPP::Scene > /*UNUSED*/, int /*UNUSED*/, std::vector> &/*UNUSED*/ ) { + pollEventsOptions(); +} diff --git a/tetris/scenes.hpp b/tetris/scenes.hpp new file mode 100644 index 0000000..695bb07 --- /dev/null +++ b/tetris/scenes.hpp @@ -0,0 +1,16 @@ +#ifndef TETRIS_MAIN_SCENE +#define TETRIS_MAIN_SCENE + +#include "../sdlpp.hpp" + +std::shared_ptr prepareMainScene(std::shared_ptr renderer, std::shared_ptr font); +std::shared_ptr prepareMenuScene(std::shared_ptr renderer, std::shared_ptr font); +std::shared_ptr prepareGameOverScene(std::shared_ptr renderer, std::shared_ptr font); +std::shared_ptr prepareOptionsScene(std::shared_ptr renderer, std::shared_ptr font); + +void mainSceneInput( std::shared_ptr< SDLPP::Scene > scene, int base, std::vector> &line_coliders ); +void menuSceneInput( std::shared_ptr< SDLPP::Scene > scene, int base, std::vector> &line_coliders ); +void gameOverSceneInput( std::shared_ptr< SDLPP::Scene > scene, int base, std::vector> &line_coliders ); +void optionsSceneInput( std::shared_ptr< SDLPP::Scene > scene, int base, std::vector> &line_coliders ); + +#endif diff --git a/tetris/tetris.cpp b/tetris/tetris.cpp index e492012..813b485 100644 --- a/tetris/tetris.cpp +++ b/tetris/tetris.cpp @@ -1,1244 +1,120 @@ #include "../sdlpp.hpp" #include "config.hpp" +#include "custom_classes.hpp" +#include "scenes.hpp" +#include "global_vars.hpp" +#include "functions.hpp" #include #include #include #include -#define COLIDER_ID 0x00000001 -#define BRICK_ID 0x00000002 -#define GAME_OVER 0x00000003 -#define SHADOW_ID 0x00000004 -#define BORDER_LEFT_ID 0x00000005 -#define BORDER_RIGHT_ID 0x00000006 -#define FLOOR_ID 0x00000007 +std::vector< std::shared_ptr< SDLPP::RenderObject > > line_coliders{}; -#define LEFT_BORDER 0.3 -#define RIGHT_BORDER 0.7 -#define BOTTOM_BORDER 1 -#define TOP_BORDER 0.16 -#define BLOCK_SIZE 0.04 - -#define TICKS_TILL_FALL 500 -#define TICKS_TILL_DESCEND 50 -#define TICKS_TILL_MOVE 100 - -#define TETRIS_BRICK 0 -#define TETRIS_T 1 -#define TETRIS_L_RIGHT 2 -#define TETRIS_Z_RIGHT 3 -#define TETRIS_LINE 4 -#define TETRIS_L_LEFT 5 -#define TETRIS_Z_LEFT 6 - -#define PAUSE_PAUSE 1 -#define PAUSE_GAME_OVER 2 - -int pause = 0; -int pause_select = 0; -int pause_max = 2; -int game_over_select = 0; -int game_over_max = 1; -int ticks_till_fall = TICKS_TILL_FALL; -int ticks_till_descend = TICKS_TILL_DESCEND; -int ticks_till_movement = TICKS_TILL_MOVE; -std::vector< std::shared_ptr< SDLPP::RectangleRender > > pause_options; -std::vector< std::shared_ptr< SDLPP::RectangleRender > > game_over_options; -std::shared_ptr< SDLPP::TextRenderer > score_texture; -std::shared_ptr< SDLPP::Renderer > active_renderer; -int score = 0; -bool update_score = false; -bool checked_line = false; -bool wait_for_anim = false; - -auto &colors = color_schemes["gruvbox_dark"]; - -std::vector< int > bag = { 28, 28, 28, 28, 28, 28, 28 }; - -std::shared_ptr< SDLPP::Font > font; -std::shared_ptr< SDLPP::Scene > active_scene; -std::shared_ptr< SDLPP::Scene > pause_scene; -std::shared_ptr< SDLPP::Scene > game_over_scene; - -class TetrisBlock : public SDLPP::RectangleRender { -public: - TetrisBlock() = delete; - TetrisBlock( double x, double y, double w, double h, - const std::shared_ptr< SDLPP::Renderer > &r, - const std::string &img_or_color, bool is_polygon, - int index, std::shared_ptr scene ) - : RectangleRender( x, y, w, h, r, img_or_color, is_polygon ) { - _index = index; - bag[_index]--; - _scene = scene; - } - TetrisBlock( const TetrisBlock &other ) : TetrisBlock(other.getDoubleRect().first.first,other.getDoubleRect().first.second,other.getDoubleRect().second.first,other.getDoubleRect().second.second,other.getRenderer(), other.getColor(), true, other._index, other._scene) {} - ~TetrisBlock() { - bag[_index]++; - } - virtual std::shared_ptr copySelf() { - return std::make_shared(*this); - } - std::shared_ptr copyInScene() { - auto ret = std::shared_ptr(new TetrisBlock(*this)); - _scene->addObject(ret); - return ret; - } - bool isSamePos(const SDLPP::RenderObject &other) const { - auto mypos = getPos(); - auto otherpos = other.getPos(); - auto diff1 = mypos.first - otherpos.first; - diff1 = (diff1 < 0) * (-1) * diff1 + (diff1 > 0) * diff1; - auto diff2 = mypos.second - otherpos.second; - diff2 = (diff2 < 0) * (-1) * diff2 + (diff2 > 0) * diff2; - return diff1 < 0.0001 && diff2 < 0.0001; - } - -private: - int _index = 0; - std::shared_ptr _scene; -}; - -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 ); - 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; +void updateScore(std::shared_ptr font) { + g_score_texture->setText( *font, std::to_string( g_score ), colors["text"], colors["text_out"], 5 ); } -class TetrisPiece { -public: - TetrisPiece() { - original_pos.reserve( 4 ); - } - void addPiece( std::shared_ptr< TetrisBlock > piece, int x, - int y ) { - pieces.push_back( piece ); - pieces_rel_position.push_back( { 0, 0, 0, 0 } ); - // done this way for SPEEEEEEED - // left - pieces_rel_position.back()[0] = ( x < 0 ) * ( -1 ) * x; - // right - pieces_rel_position.back()[1] = ( x > 0 ) * x; - // top - pieces_rel_position.back()[2] = ( y < 0 ) * ( -1 ) * y; - // bottom - pieces_rel_position.back()[3] = ( y > 0 ) * y; - } - void rotate() { - if(!rotate_allowed) - return; - for ( unsigned long i = 0; i < pieces.size(); i++ ) { - auto &piece = pieces[i]; - auto &positions = pieces_rel_position[i]; - auto position = piece->getPos(); - original_pos[i] = position; - position.first += positions[0] * BLOCK_SIZE; - position.first -= positions[1] * BLOCK_SIZE; - position.second += positions[2] * BLOCK_SIZE; - position.second -= positions[3] * BLOCK_SIZE; - auto bottom = positions[3]; - auto top = positions[2]; - positions[3] = positions[1]; - positions[2] = positions[0]; - positions[1] = top; - positions[0] = bottom; - position.first -= positions[0] * BLOCK_SIZE; - position.first += positions[1] * BLOCK_SIZE; - position.second -= positions[2] * BLOCK_SIZE; - position.second += positions[3] * BLOCK_SIZE; - piece->setPos( position.first, position.second ); - } - } - void revert() { - for ( unsigned long i = 0; i < pieces.size(); i++ ) { - auto &piece = pieces[i]; - auto &positions = pieces_rel_position[i]; - piece->setPos( original_pos[i].first, original_pos[i].second ); - auto top = positions[1]; - auto bottom = positions[0]; - positions[1] = positions[3]; - positions[0] = positions[2]; - positions[2] = top; - positions[3] = bottom; - } - } - std::vector< std::shared_ptr< TetrisBlock > > &getObjects() { - return pieces; - } - void setPos( double x, double y ) { - for ( unsigned long i = 0; i < pieces.size(); i++ ) { - auto &piece = pieces[i]; - auto &positions = pieces_rel_position[i]; - std::pair pos = {x, y}; - pos.first -= positions[0] * BLOCK_SIZE; - pos.first += positions[1] * BLOCK_SIZE; - pos.second -= positions[2] * BLOCK_SIZE; - pos.second += positions[3] * BLOCK_SIZE; - piece->setPos( pos.first, pos.second ); - } - } - void setPos(const std::pair &pos) { - setPos(pos.first, pos.second); - } - std::pair getPos() { - auto &piece = pieces[0]; - auto &relpositions = pieces_rel_position[0]; - auto pos = piece->getPos(); - pos.first += relpositions[0] * BLOCK_SIZE; - pos.first -= relpositions[1] * BLOCK_SIZE; - pos.second += relpositions[2] * BLOCK_SIZE; - pos.second -= relpositions[3] * BLOCK_SIZE; - return pos; - } - void clear() { - pieces.clear(); - pieces_rel_position.clear(); - } - void startDescend() { - descend = true; - } - void stopDescend() { - descend = false; - } - void startMovement() { - userMovement += 1; - } - void stopMovement() { - userMovement -= 1; - } - bool isDescending() { - return descend; - } - bool isMoving() { - return userMovement > 0; - } - bool isLeft(const SDLPP::RenderObject &block) const { - return isPosition(block, 0); - } - bool isRight(const SDLPP::RenderObject &block) const { - return isPosition(block, 1); - } - void movePiece(double x, double y) { - for ( auto &block : getObjects() ) { - auto pos = block->getPos(); - block->setPos( pos.first + x, pos.second + y ); - } - } - void disableRotation() { - rotate_allowed = false; - } - - void turnIntoShadow() { - for(auto &block : getObjects() ) { - block->setId(SHADOW_ID); - block->setColor(colors["shadow"]); - } - } - std::shared_ptr copySelf() { - auto ret = std::make_shared(); - for(int i = 0; i < 4; i++) { - auto block = pieces[i]->copyInScene(); - block->centerX(); - ret->addBlockInPos(block, pieces_rel_position[i]); - } - return ret; - } - void destroy() { - for(auto &x : getObjects()) { - x->destroy(); - } - } - void addMovement(int x, int y) { - movement.first += x; - movement.second += y; - } - std::pair getMovement() const { - return movement; - } - -private: - bool isPosition(const SDLPP::RenderObject &block, int pos) const { - for(int i = 0; i < 4; i++) { - if(pieces[i]->isSamePos(block)) { - return pieces_rel_position[i][pos] != 0; - } - } - return false; - } - void resetBlock(int index, std::shared_ptr< TetrisBlock > piece) { - piece->setPos(pieces[index]->getPos()); - pieces[index] = piece; - } - void addBlockInPos(std::shared_ptr piece, const std::vector &relpos) { - pieces.push_back( piece ); - pieces_rel_position.push_back(relpos); - } - std::vector< std::vector< int > > pieces_rel_position; - std::vector< std::shared_ptr< TetrisBlock > > pieces; - std::vector< std::pair< double, double > > original_pos; - bool descend = false; - int userMovement = 0; - bool rotate_allowed = true; - std::pair movement = {0,0}; -}; - -std::vector< std::shared_ptr< SDLPP::RectangleRender > > line_coliders; -std::shared_ptr< TetrisPiece > cur_object; -std::shared_ptr< TetrisPiece > next_object; -std::shared_ptr< TetrisPiece > cur_shadow; -std::shared_ptr< SDLPP::RectangleRender > shadow_colider; - -void doInput( std::shared_ptr< SDLPP::Scene > scene ); -void doInputPause(); -void doInputGameOver(); -bool quit = false; - -std::mutex movement_mutex; - -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; -} - -std::vector< std::shared_ptr< TetrisPiece > ( * )( - std::shared_ptr< SDLPP::Renderer >, std::shared_ptr< SDLPP::Scene > ) > - tetrisFunctions = { - tetrisBrick, tetrisT, tetrisLRight, tetrisZRight, - tetrisLine, tetrisLLeft, tetrisZLeft, - }; - -void addStuff( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r ) { - auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, - colors["background"], true ); - bg->setPermanent(); - scene.addObject( bg ); - - double posy = 1; - for ( int i = 0; i < 20; i++ ) { - posy -= BLOCK_SIZE; - auto colider = std::make_shared< SDLPP::RectangleRender >( - LEFT_BORDER, posy, RIGHT_BORDER - LEFT_BORDER, BLOCK_SIZE, r ); - colider->addCollision(SDLPP::Rect( 0.01, 0.1, 0.98, 0.8 )); - colider->setId( COLIDER_ID ); - colider->setStatic(); - colider->centerX(); - line_coliders.push_back( colider ); - scene.addObject( colider ); - } - - posy = 1; - for ( int i = 0; i < 20; i++ ) { - posy -= BLOCK_SIZE; - auto line = std::make_shared< SDLPP::LineRenderer >( LEFT_BORDER, posy, RIGHT_BORDER, posy, r, colors["line"] ); - line->setStatic(); - line->centerX(); - scene.addObject( line ); - } - - auto posx = RIGHT_BORDER; - for ( int i = 0; i < 9; i++ ) { - posx -= BLOCK_SIZE; - auto line = std::make_shared< SDLPP::LineRenderer >( posx, TOP_BORDER + BLOCK_SIZE, posx, BOTTOM_BORDER, r, colors["line"] ); - line->setStatic(); - line->centerX(); - scene.addObject( line ); - } - - auto left_barrier = std::make_shared< SDLPP::RectangleRender >( - LEFT_BORDER - 0.02, 0, 0.02, BOTTOM_BORDER, r, colors["barrier"], true ); - left_barrier->centerX(); - left_barrier->setStatic(); - scene.addObject( left_barrier ); - auto right_barrier = std::make_shared< SDLPP::RectangleRender >( - RIGHT_BORDER, 0, 0.02, BOTTOM_BORDER, r, colors["barrier"], true ); - right_barrier->centerX(); - right_barrier->setStatic(); - scene.addObject( right_barrier ); - auto bottom_barrier = std::make_shared< SDLPP::RectangleRender >( - LEFT_BORDER - 0.02, BOTTOM_BORDER, RIGHT_BORDER - LEFT_BORDER + 0.04, - 0.02, r, colors["barrier"], true ); - bottom_barrier->centerX(); - bottom_barrier->setStatic(); - scene.addObject( bottom_barrier ); - auto tetris = std::make_shared< SDLPP::TextRenderer >( - 0.4, 0, 0.2, 0.1, r, *font, "TETRIS", colors["text"], colors["text_out"], 5 ); - tetris->centerX(); - tetris->setStatic(); - scene.addObject( tetris ); - auto next = std::make_shared< SDLPP::TextRenderer >( - RIGHT_BORDER + 0.1, 0.35, 0.2, 0.1, r, *font, "NEXT", colors["text"], colors["text_out"], 5, SDLPP_TEXT_CENTER ); - next->centerX(); - next->setStatic(); - scene.addObject( next ); - auto gameover = std::make_shared< SDLPP::RectangleRender >( - 0.5, 0, 0, TOP_BORDER + BLOCK_SIZE, r ); - auto gameover_collision = SDLPP::Rect( -1, 0, -1, 0.9 ); - gameover_collision.setInfinite(); - gameover->addCollision( gameover_collision ); - gameover->setId( GAME_OVER ); - gameover->setColiderColor( "FF0000" ); - gameover->setStatic(); - scene.addObject( gameover ); - auto score_text = std::make_shared< SDLPP::TextRenderer >( - RIGHT_BORDER + 0.1, 0.1, 0.2, 0.1, r, *font, "SCORE", colors["text"], colors["text_out"], 5, SDLPP_TEXT_CENTER ); - score_text->centerX(); - score_text->setStatic(); - scene.addObject( score_text ); - - score_texture = std::make_shared< SDLPP::TextRenderer >( - RIGHT_BORDER + 0.1, 0.2, 0.2, 0.1, r, *font, std::to_string( score ), - colors["text"], colors["text_out"], 5, SDLPP_TEXT_TOP ); - score_texture->centerX(); - score_texture->setStatic(); - scene.addObject( score_texture ); - - auto shcol = std::make_shared< SDLPP::RectangleRender >( 0, TOP_BORDER, BLOCK_SIZE, BOTTOM_BORDER - TOP_BORDER, r ); - shcol->addCollision(SDLPP::Rect( 0.1, 0.01, 0.8, 0.98 )); - shcol->setId( COLIDER_ID ); - shcol->setStatic(); - shcol->centerX(); - shadow_colider = shcol; - scene.addObject( shadow_colider ); - - auto border = std::make_shared< SDLPP::RectangleRender >( LEFT_BORDER - 1, TOP_BORDER, 1, BOTTOM_BORDER, r); - border->setId( BORDER_LEFT_ID ); - border->setStatic(); - border->centerX(); - border->addCollision(SDLPP::Rect( 0, 0, 0.99, 1)); - border->setColiderColor("#FF00FF"); - scene.addObject(border); - - border = std::make_shared< SDLPP::RectangleRender >( RIGHT_BORDER, TOP_BORDER, 1, BOTTOM_BORDER, r); - border->setId( BORDER_RIGHT_ID ); - border->setStatic(); - border->centerX(); - border->addCollision(SDLPP::Rect( 0.01, 0, 1, 1)); - border->setColiderColor("#FF00FF"); - scene.addObject(border); - - auto floor = std::make_shared< SDLPP::RectangleRender >( LEFT_BORDER, BOTTOM_BORDER, RIGHT_BORDER - LEFT_BORDER, 1, r); - floor->setId( FLOOR_ID ); - floor->setStatic(); - floor->centerX(); - floor->addCollision(SDLPP::Rect(0, 0.01, 1, 1)); - floor->setColiderColor("#00FF00"); - scene.addObject(floor); -} - -void updateScore() { - score_texture->setText( *font, std::to_string( score ), colors["text"], colors["text_out"], 5 ); -} - -void addPause( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r ) { - auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, - colors["menu_background"], true ); - bg->setId( 123 ); - bg->setPermanent( true ); - scene.addObject( bg ); - auto y = std::make_shared< SDLPP::TextRenderer >( 0.25, 0.1, 0.5, 0.3, r ); - y->setText( *font, "PAUSED", colors["text"], colors["text_out"], 5 ); - y->setId( 0 ); - y->centerX(); - scene.addObject( y ); - auto resume = - std::make_shared< SDLPP::TextRenderer >( 0.4, 0.51, 0.2, 0.08, r ); - resume->setText( *font, "Resume", colors["text"], colors["text_out"], 5 ); - resume->setColor( colors["menu_item_background"] ); - resume->centerX(); - scene.addObject( resume ); - pause_options.push_back( resume ); - auto restart = - std::make_shared< SDLPP::TextRenderer >( 0.4, 0.61, 0.2, 0.08, r ); - restart->setText( *font, "Restart", colors["text"], colors["text_out"], 5 ); - restart->centerX(); - scene.addObject( restart ); - pause_options.push_back( restart ); - auto quit = - std::make_shared< SDLPP::TextRenderer >( 0.4, 0.71, 0.2, 0.08, r ); - quit->setText( *font, "Quit Game", colors["text"], colors["text_out"], 5 ); - quit->centerX(); - scene.addObject( quit ); - pause_options.push_back( quit ); -} - -void addGameOver( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r ) { - auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, - colors["menu_background"], true ); - bg->setId( 123 ); - bg->setPermanent( true ); - scene.addObject( bg ); - auto y = std::make_shared< SDLPP::TextRenderer >( 0.25, 0.1, 0.5, 0.3, r ); - y->setText( *font, "GAME OVER", colors["text"], colors["text_out"], 5 ); - y->setId( 0 ); - y->centerX(); - scene.addObject( y ); - auto restart = - std::make_shared< SDLPP::TextRenderer >( 0.4, 0.5, 0.2, 0.1, r ); - restart->setText( *font, "Restart", colors["text"], colors["text_out"], 5 ); - restart->centerX(); - restart->setColor( colors["menu_item_background"] ); - scene.addObject( restart ); - game_over_options.push_back( restart ); - auto quit = - std::make_shared< SDLPP::TextRenderer >( 0.4, 0.7, 0.2, 0.1, r ); - quit->setText( *font, "Quit Game", colors["text"], colors["text_out"], 5 ); - quit->centerX(); - scene.addObject( quit ); - game_over_options.push_back( quit ); -} - -void quitGame() { - std::cout << "Quitting!" << std::endl; - quit = true; -} - -int crashFlags( std::shared_ptr piece, std::shared_ptr 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 |= right; - 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 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; - do { - 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; -} - -void updateShadow(SDLPP::Scene &scene) { - if(!cur_object) { - cur_shadow->destroy(); - cur_shadow.reset(); - return; - } - cur_shadow->setPos(cur_object->getPos()); - double shadow_drop = BOTTOM_BORDER; - auto &invalid_objects = cur_object->getObjects(); - for( auto &x : cur_shadow->getObjects() ) { - if(BOTTOM_BORDER - x->getPos().second < shadow_drop) - shadow_drop = BOTTOM_BORDER - x->getPos().second; - shadow_colider->setPos(x->getPos().first, TOP_BORDER); - auto collisions = scene.getCollisions( *shadow_colider, { BRICK_ID } ); - auto curY = x->getPos().second; - for(auto &col : collisions) { - auto colY = col->getPos().second; - if(std::find(invalid_objects.begin(), invalid_objects.end(), col) != invalid_objects.end()) - continue; - auto possible_drop = colY - curY; - if(possible_drop < shadow_drop && possible_drop >= 0) - shadow_drop = colY - curY; - } - } - shadow_drop -= BLOCK_SIZE; - cur_shadow->setPos(cur_shadow->getPos().first, cur_shadow->getPos().second + shadow_drop); -} - -bool validPos(SDLPP::Scene &scene, std::shared_ptr piece) { - auto ret = true; - for ( auto &x : piece->getObjects() ) { - auto collisions = scene.getCollisions( *x, { BRICK_ID, FLOOR_ID, BORDER_LEFT_ID, BORDER_RIGHT_ID } ); - if ( collisions.size() > 1 ) { - ret = false; - break; - } - } - return ret; -} - -void handleKeyDown( SDL_Keycode key, SDLPP::Scene &scene ) { - switch ( key ) { - case SDLK_ESCAPE: - { - pause = PAUSE_PAUSE; - pause_scene->updateSizeAndPosition(); - std::thread pauseThread( doInputPause ); - pauseThread.detach(); - } break; - case SDLK_LEFT: - case SDLK_a: - if(!cur_object) - break; - cur_object->movePiece(-BLOCK_SIZE, 0); - if(!validPos(scene, cur_object)) - cur_object->movePiece(BLOCK_SIZE, 0); - updateShadow(scene); - - ticks_till_movement = 2*TICKS_TILL_MOVE; - cur_object->startMovement(); - cur_object->addMovement(-1,0); - break; - case SDLK_RIGHT: - case SDLK_d: - if(!cur_object) - break; - cur_object->movePiece(BLOCK_SIZE, 0); - if(!validPos(scene, cur_object)) - cur_object->movePiece(-BLOCK_SIZE, 0); - updateShadow(scene); - - ticks_till_movement = 2*TICKS_TILL_MOVE; - cur_object->startMovement(); - cur_object->addMovement(1,0); - break; - case SDLK_DOWN: - case SDLK_s: - if(!cur_object) - break; - cur_object->startDescend(); - cur_object->addMovement(0,1); - break; - case SDLK_UP: - case SDLK_w: - if(!cur_object) - break; - cur_object->rotate(); - if( checkRotation( cur_object, scene ) ) - cur_shadow->rotate(); - updateShadow(scene); - break; - case SDLK_r: - scene.getRenderer().setRenderColiders( - !scene.getRenderer().getRenderColiders() ); - default: - break; - } -} - -void handleKeyUp( SDL_Keycode key ) { - switch(key) { - case SDLK_DOWN: - case SDLK_s: - if(!cur_object) - break; - if(cur_object->isDescending()) { - cur_object->stopDescend(); - cur_object->addMovement(0,-1); - ticks_till_descend = TICKS_TILL_DESCEND; - } - break; - case SDLK_LEFT: - case SDLK_a: - if(!cur_object) - break; - if(cur_object->isMoving()) { - cur_object->stopMovement(); - cur_object->addMovement(1,0); - if(cur_object->isMoving()) - ticks_till_movement = TICKS_TILL_MOVE; - } - break; - case SDLK_RIGHT: - case SDLK_d: - if(!cur_object) - break; - if(cur_object->isMoving()) { - cur_object->stopDescend(); - cur_object->addMovement(-1,0); - if(cur_object->isMoving()) - ticks_till_movement = TICKS_TILL_MOVE; - } - default: - break; - } -} - -void handleKeyDownPause( SDL_Keycode key ) { - switch ( key ) { - case SDLK_ESCAPE: { - pause = 0; - active_scene->setPrevTicks( SDL_GetTicks() ); - std::thread inputThread( doInput, active_scene ); - inputThread.detach(); - } break; - case SDLK_r: - active_scene->getRenderer().setRenderColiders( - !active_scene->getRenderer().getRenderColiders() ); - break; - case SDLK_s: - case SDLK_DOWN: - pause_options[pause_select]->unsetColor(); - pause_select++; - if ( pause_select > pause_max ) - pause_select = 0; - pause_options[pause_select]->setColor( colors["menu_item_background"] ); - break; - case SDLK_w: - case SDLK_UP: - pause_options[pause_select]->unsetColor(); - pause_select--; - if ( pause_select < 0 ) - pause_select = pause_max; - pause_options[pause_select]->setColor( colors["menu_item_background"] ); - break; - case SDLK_RETURN: - switch ( pause_select ) { - case 0: { - pause = 0; - active_scene->setPrevTicks( SDL_GetTicks() ); - std::thread inputThread( doInput, active_scene ); - inputThread.detach(); - } break; - case 1: - { - pause = 0; - cur_object.reset(); - checked_line = true; - next_object.reset(); - score = 0; - update_score = true; - active_scene->resetScene(); - active_scene->setPrevTicks( SDL_GetTicks() ); - - next_object = tetrisFunctions[std::rand() / ( ( RAND_MAX + 1u ) / 7 )]( - active_scene->getRendererShared(), active_scene ); - next_object->setPos( 0.9, 0.5 ); - std::thread inputThread( doInput, active_scene ); - inputThread.detach(); - } - break; - case 2: - quitGame(); - default: - break; - } - default: - break; - } -} - -void handleKeyDownGameOver( SDL_Keycode key ) { - switch ( key ) { - case SDLK_r: - active_scene->getRenderer().setRenderColiders( - !active_scene->getRenderer().getRenderColiders() ); - break; - case SDLK_s: - case SDLK_DOWN: - game_over_options[game_over_select]->unsetColor(); - game_over_select++; - if ( game_over_select > game_over_max ) - game_over_select = 0; - game_over_options[game_over_select]->setColor( colors["menu_item_background"] ); - break; - case SDLK_w: - case SDLK_UP: - game_over_options[game_over_select]->unsetColor(); - game_over_select--; - if ( game_over_select < 0 ) - game_over_select = game_over_max; - game_over_options[game_over_select]->setColor( colors["menu_item_background"] ); - break; - case SDLK_RETURN: - switch ( game_over_select ) { - case 0: - { - // TODO reset function - pause = 0; - cur_object.reset(); - checked_line = true; - next_object.reset(); - score = 0; - update_score = true; - active_scene->resetScene(); - active_scene->setPrevTicks( SDL_GetTicks() ); - - next_object = tetrisFunctions[std::rand() / ( ( RAND_MAX + 1u ) / 7 )]( - active_scene->getRendererShared(), active_scene ); - next_object->setPos( 0.9, 0.5 ); - std::thread inputThread( doInput, active_scene ); - inputThread.detach(); - } - break; - case 1: - quitGame(); - default: - break; - } - default: - break; - } -} - -void pollEvents( SDLPP::Scene &scene ) { - SDL_Event event; - while ( SDL_PollEvent( &event ) != 0 ) { - switch ( event.type ) { - case SDL_QUIT: - quitGame(); - break; - case SDL_KEYDOWN: - if ( !event.key.repeat ) - handleKeyDown( event.key.keysym.sym, scene ); - break; - case SDL_KEYUP: - handleKeyUp( event.key.keysym.sym ); - break; - case SDL_WINDOWEVENT: - if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) - scene.updateSizeAndPosition(); - default: - break; - } - } -} - -void pollEventsPause() { - SDL_Event event; - while ( SDL_PollEvent( &event ) != 0 ) { - switch ( event.type ) { - case SDL_QUIT: - quitGame(); - break; - case SDL_KEYDOWN: - if ( !event.key.repeat ) - handleKeyDownPause( event.key.keysym.sym ); - break; - case SDL_WINDOWEVENT: - if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) { - active_scene->updateSizeAndPosition(); - pause_scene->updateSizeAndPosition(); - } - default: - break; - } - } -} - -void pollEventsGameOver() { - SDL_Event event; - while ( SDL_PollEvent( &event ) != 0 ) { - switch ( event.type ) { - case SDL_QUIT: - quitGame(); - break; - case SDL_KEYDOWN: - if ( !event.key.repeat ) - handleKeyDownGameOver( event.key.keysym.sym ); - break; - case SDL_WINDOWEVENT: - if ( event.window.event == SDL_WINDOWEVENT_RESIZED ) { - active_scene->updateSizeAndPosition(); - game_over_scene->updateSizeAndPosition(); - } - default: - break; - } - } -} - -void moveThem( std::shared_ptr< SDLPP::Scene > scene, int ticks ) { - auto movement = cur_object->getMovement(); - ticks_till_fall -= ticks; - if ( cur_object->isDescending() ) - ticks_till_descend -= ticks; - if ( cur_object->isMoving() ) - ticks_till_movement -= ticks; - if ( ticks_till_fall > 0 ) { - if ( cur_object->isDescending() && ticks_till_descend <= 0 ) { - ticks_till_descend = TICKS_TILL_DESCEND; - cur_object->movePiece(0, movement.second * BLOCK_SIZE); - if(!validPos(*scene, cur_object)) { - cur_object->movePiece(0, movement.second * -BLOCK_SIZE); - return; - } else - goto check_floor; - } - if ( cur_object->isMoving() && ticks_till_movement <= 0 ) { - ticks_till_movement = TICKS_TILL_MOVE; - cur_object->movePiece(movement.first * BLOCK_SIZE, 0); - if(!validPos(*scene, cur_object)) { - cur_object->movePiece(movement.first * -BLOCK_SIZE, 0); - return; - } else - goto check_floor; - } - return; - } - ticks_till_fall = TICKS_TILL_FALL; - cur_object->movePiece(0, BLOCK_SIZE); -check_floor: - bool fell = false; - for ( auto &x : cur_object->getObjects() ) { - auto collisions = scene->getCollisions( *x, { BRICK_ID, FLOOR_ID } ); - if ( collisions.size() > 1 ) { - fell = true; - break; - } - } - if ( fell ) { - cur_object->movePiece(0, -BLOCK_SIZE); - for ( auto &block : cur_object->getObjects() ) { - if ( scene->getCollisions( *block, { GAME_OVER } ).size() > 0 ) { - pause = PAUSE_GAME_OVER; - game_over_scene->updateSizeAndPosition(); - std::thread pauseThread( doInputGameOver ); - pauseThread.detach(); - } - } - cur_object.reset(); - } - updateShadow(*scene); -} - -void doInput( std::shared_ptr< SDLPP::Scene > scene ) { +void doInput() { FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 200 ); auto base = SDL_GetTicks(); - while ( !quit && !pause ) { + while ( !g_quit ) { base = SDL_GetTicks(); SDL_framerateDelay( &gFPS ); - std::lock_guard< std::mutex > guard( movement_mutex ); - pollEvents( *scene ); - if ( cur_object ) { - moveThem( scene, SDL_GetTicks() - base ); - continue; - } - for ( auto &colider : line_coliders ) { - auto collisions = scene->getCollisions( *colider, { BRICK_ID } ); - while ( collisions.size() == 10 ) { - score += 10; - update_score = true; - for ( auto &col : collisions ) { - col->destroy(); - } - auto colider_y = colider->getPos().second; - for ( auto &elem : scene->getObjects() ) { - if ( elem->getId() != BRICK_ID ) - continue; - auto pos = elem->getPos(); - if ( pos.second < colider_y && pos.first >= LEFT_BORDER && pos.first <= RIGHT_BORDER ) { - elem->setPos( pos.first, pos.second + BLOCK_SIZE ); - } - } - using namespace std::chrono_literals; - wait_for_anim = true; - while ( wait_for_anim ) { - std::this_thread::sleep_for( 0.1s ); - } - collisions = scene->getCollisions( *colider, { BRICK_ID } ); - } - } - checked_line = true; + // TODO here comes the thingy + g_input_functions.back()(g_main_scene, base, line_coliders); } } -void doInputPause() { - FPSmanager gFPS; - SDL_initFramerate( &gFPS ); - SDL_setFramerate( &gFPS, 200 ); - while ( pause ) { - SDL_framerateDelay( &gFPS ); - pollEventsPause(); - if ( !pause ) - break; - } -} - -void doInputGameOver() { - FPSmanager gFPS; - SDL_initFramerate( &gFPS ); - SDL_setFramerate( &gFPS, 200 ); - while ( pause ) { - SDL_framerateDelay( &gFPS ); - pollEventsGameOver(); - if ( !pause ) - break; - } +void prepareShadowColider(std::shared_ptr r) { + g_shadow_colider = std::make_shared< SDLPP::RectangleRender >( 0, TOP_BORDER, BLOCK_SIZE, BOTTOM_BORDER - TOP_BORDER, r ); + g_shadow_colider->addCollision(SDLPP::Rect( 0.1, 0.01, 0.8, 0.98 )); + g_shadow_colider->setId( COLIDER_ID ); + g_shadow_colider->setStatic(); + g_shadow_colider->centerX(); } int main() { SDLPP::init(); SDLPP::Window w( "Tetris clone!" ); w.setResizable(true); - auto renderer = std::make_shared< SDLPP::Renderer >( w ); - active_renderer = renderer; - renderer->setBlendMode( SDL_BLENDMODE_BLEND ); - auto main_scene = std::make_shared< SDLPP::Scene >( renderer ); - active_scene = main_scene; - font = std::make_shared< SDLPP::Font >( "testfont.ttf", 96 ); - addStuff( *main_scene, renderer ); - main_scene->saveScene(); - pause_scene = std::make_shared< SDLPP::Scene >( renderer ); - addPause( *pause_scene, renderer ); - game_over_scene = std::make_shared(renderer); - addGameOver(*game_over_scene, renderer); + auto renderer = std::make_shared< SDLPP::Renderer >( w ); + g_active_renderer = renderer; + renderer->setBlendMode( SDL_BLENDMODE_BLEND ); + prepareShadowColider(renderer); + + g_font = std::make_shared< SDLPP::Font >( "testfont.ttf", 96 ); + + g_main_scene = prepareMainScene(renderer, g_font); + line_coliders = g_main_scene->getObjects( {COLIDER_ID} ); + g_score_texture = std::dynamic_pointer_cast(g_main_scene->getObjects( {SCORE_TEXTURE_ID} )[0]); + g_active_scenes.push_back( g_main_scene ); + g_main_scene->saveScene(); + + g_menu_scene = prepareMenuScene(renderer, g_font); + g_game_over_scene = prepareGameOverScene(renderer, g_font); + g_options_scene = prepareOptionsScene(renderer, g_font); auto base = SDL_GetTicks(); int frames = 0; - std::srand( std::time( nullptr ) ); + FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 60 ); - std::thread inputThread( doInput, main_scene ); + + std::thread inputThread( doInput ); inputThread.detach(); - next_object = tetrisFunctions[std::rand() / ( ( RAND_MAX + 1u ) / 7 )]( - renderer, main_scene ); - next_object->setPos( 0.9, 0.5 ); - while ( !quit ) { + + g_next_object = g_tetrisFunctions[std::rand() / ( ( RAND_MAX + 1u ) / 7 )]( + renderer, g_main_scene ); + g_next_object->setPos( 0.9, 0.5 ); + g_input_functions.push_back(mainSceneInput); + + while ( !g_quit ) { SDL_framerateDelay( &gFPS ); - if ( !cur_object && checked_line ) { - std::lock_guard< std::mutex > guard( movement_mutex ); - cur_object = next_object; - cur_object->setPos( 0.5, TOP_BORDER - BLOCK_SIZE ); - cur_shadow = cur_object->copySelf(); - cur_shadow->turnIntoShadow(); - for(auto &piece : cur_shadow->getObjects()) { - active_scene->moveZ(piece, -4); + if ( !g_cur_object && g_checked_line ) { + std::lock_guard< std::mutex > guard( g_movement_mutex ); + g_cur_object = g_next_object; + g_cur_object->setPos( 0.5, TOP_BORDER - BLOCK_SIZE ); + g_cur_shadow = g_cur_object->copySelf(); + g_cur_shadow->turnIntoShadow(); + for(auto &piece : g_cur_shadow->getObjects()) { + g_main_scene->moveZ(piece, -4); } - updateShadow(*main_scene); + updateShadow(*g_main_scene); auto rand_index = std::rand() / ( ( RAND_MAX + 1u ) / 7 ); int retries = 0; - while ( bag[rand_index] < 4 ) { + while ( g_bag[rand_index] < 4 ) { rand_index = ( rand_index + 1 ) % 7; retries++; if ( retries == 7 ) quitGame(); } - next_object.reset(); - next_object = tetrisFunctions[rand_index]( renderer, main_scene ); - next_object->setPos( 0.9, 0.5 ); - checked_line = false; + g_next_object.reset(); + g_next_object = g_tetrisFunctions[rand_index]( renderer, g_main_scene ); + g_next_object->setPos( 0.9, 0.5 ); + g_checked_line = false; } - if ( update_score ) { - updateScore(); - update_score = false; + if ( g_update_score ) { + updateScore(g_font); + g_update_score = false; + } + if ( g_update_colors ) { + updateColors(); + g_update_colors = false; } - main_scene->renderScene(); - if ( pause == PAUSE_PAUSE ) { - pause_scene->renderScene( false ); - } else if ( pause == PAUSE_GAME_OVER ) { - game_over_scene->renderScene( false ); + g_main_scene->renderScene(); + for(auto &x : g_active_scenes) { + if(x != g_main_scene) + x->renderScene(false); } - main_scene->presentScene(); - wait_for_anim = false; + g_main_scene->presentScene(); + g_wait_for_anim = false; frames++; if ( SDL_GetTicks() - base >= 1000 ) { base = SDL_GetTicks(); @@ -1246,5 +122,6 @@ int main() { frames = 0; } } + return 0; }