#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(); }