#include "../sdlpp/sdlpp.hpp" #include "sprites.hpp" #ifdef _WIN32 #include "../sdlpp/SDL2/SDL2_framerate.h" #include #include #include #else #include #endif // UNIX #include #include #include #include "global_vars.hpp" #include "objectids.hpp" #include "blocks.hpp" #include "maploader.hpp" #include "mario.hpp" #include "visitors/visitor_generator.hpp" bool quit = false; bool update = false; std::shared_ptr< Mario > mario = nullptr; std::shared_ptr< SDLPP::RectangleRender > leftStop = nullptr; std::shared_ptr< SDLPP::Renderer > renderer = nullptr; std::shared_ptr< SDLPP::TextRenderer > fps = nullptr; std::shared_ptr< SDLPP::TextRenderer > coins = nullptr; int coin_count = 0; int global_frames = 0; std::vector< std::shared_ptr< MarioBlock > > moving_objects = {}; std::mutex render_mutex; void handleKeyDown( SDL_Keycode key, SDLPP::Scene &scene ) { switch ( key ) { case SDLK_ESCAPE: quit = true; break; case SDLK_a: mario->walkLeft(); break; case SDLK_d: mario->walkRight(); break; case SDLK_SPACE: case SDLK_w: mario->jump(); break; case SDLK_s: break; case SDLK_r: scene.getRenderer().setRenderColiders( !scene.getRenderer().getRenderColiders() ); break; case SDLK_f: if ( fps ) { fps->setHidden( !fps->getHidden() ); } default: break; } } void handleKeyUp( SDL_Keycode key ) { switch ( key ) { case SDLK_a: mario->walkRight(); break; case SDLK_d: mario->walkLeft(); break; case SDLK_SPACE: case SDLK_w: mario->stopJump(); default: break; } } void moveToMarioPosition( SDLPP::Scene &scene, SDLPP::Vec2D< double > &prev_mario ) { auto rendDims = renderer->getDoubleDimensions(); if ( leftStop ) { auto left = rendDims.getX() < 2.0 ? -( rendDims.getX() - 1 ) / 2.0 - 0.1 : -0.5; leftStop->setPos( left, 0 ); } auto mario_pos_difference = prev_mario - mario->getAbsolutePos(); // sometimes there is a concurrency problem and prev_pos == cur_pos, in // that case move everything so Mario is standing on the left edge of the // screen if(mario_pos_difference.getX() < 0.01 && mario_pos_difference.getX() > -0.01) { // 0.01 is the width of visible leftStop scene.moveEverything(-(mario->getAbsolutePos().getX() - 0.01), 0); } else { scene.moveEverything( mario_pos_difference.getX(), 0 ); } scene.updateSizeAndPosition(); auto left_stop_rightmost = leftStop->getDoubleRect().first.getX() + leftStop->getDoubleRect().second.getX(); if ( mario->getPos().getX() < left_stop_rightmost ) { mario->setPos( left_stop_rightmost, mario->getPos().getY() ); } } void pollEvents( SDLPP::Scene &scene ) { SDL_Event event; while ( SDLPP::getSDLEvent( event ) ) { switch ( event.type ) { case SDL_QUIT: quit = true; 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 ) { auto prev_mario_pos = mario->getAbsolutePos(); scene.updateSizeAndPosition(); moveToMarioPosition( scene, prev_mario_pos ); } default: break; } } } void doInput( std::shared_ptr< SDLPP::Scene > scene ) { FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 200 ); while ( !quit ) { SDL_framerateDelay( &gFPS ); pollEvents( *scene ); std::lock_guard< std::mutex > lock( render_mutex ); scene->updateScene(); auto prev_coin_count = coin_count; auto rightmost_x = renderer->getDoubleDimensions().getX(); for(size_t i = 0; i < moving_objects.size(); i++) { moving_objects[i]->checkVisibility(rightmost_x); if(!moving_objects[i]->wasVisible()) { continue; } auto visitor = getVisitor( *moving_objects[i], *scene, quit, coin_count, moving_objects ); scene->visitCollisions( *moving_objects[i], *visitor ); moving_objects[i]->handleVisitor( *visitor ); auto rightmost_pos = moving_objects[i]->getAbsolutePos().getX() + moving_objects[i]->getDoubleRect().second.getX(); if(rightmost_pos < 0) { moving_objects[i]->destroy(); } } std::vector killed_indices{}; for(size_t i = 0; i < moving_objects.size(); i++) { if(moving_objects[i]->getKilled()) { killed_indices.push_back(i); } } std::reverse( killed_indices.begin(), killed_indices.end() ); for(auto &index : killed_indices) { moving_objects.erase(moving_objects.begin() + index); } if ( coin_count != prev_coin_count ) { coins->changeText( std::to_string( coin_count ) + " COINS" ); } // if player is > 0.7 of playground, move everything left auto playerX = mario->getRect().x; auto width = scene->getWidth(); auto rightBarrier = width * 0.7; auto rightmostX = scene->rightmost()->getRect().x + scene->rightmost()->getRect().w; scene->moveEverything( ( playerX > rightBarrier && rightmostX > width ) * ( rightBarrier - playerX ) / width, 0 ); update = playerX > rightBarrier && rightmostX > width; global_frames++; } } #ifdef _WIN32 int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR szCmdLine, int nCmdShow ) { #else int main() { #endif SDLPP::init(); SDLPP::Window w( "Mario clone!" ); w.setResizable( true ); renderer = std::make_shared< SDLPP::Renderer >( w ); renderer->setBlendMode( SDL_BLENDMODE_BLEND ); // prepare global vars g_terrain_texture = std::make_shared< SDLPP::Texture >( renderer, "sprites/terrain.png", MARIO_OVERWORLD_COLORKEY ); auto scene = std::make_shared< SDLPP::Scene >( renderer ); g_playground = scene; auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, renderer, MARIO_OVERWORLD_COLORKEY, true ); bg->setPermanent(); bg->setStatic(); bg->setId( 1 ); scene->addObject( bg ); g_mario_texture = std::make_shared< SDLPP::Texture >( renderer, "sprites/mario.png", MARIO_OVERWORLD_COLORKEY ); g_translucent_terrain_texture = std::make_shared< SDLPP::Texture >( renderer, "sprites/terrain.png", MARIO_OVERWORLD_COLORKEY ); g_translucent_terrain_texture->setAlpha( 100 ); mario = std::make_shared< Mario >( renderer ); scene->addObject( mario ); auto defeat = std::make_shared< SDLPP::RectangleRender >( 0, 1.01, 0, 0, renderer ); defeat->setId( DEATH_ID ); defeat->setAlignment( SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER ); defeat->setPermanent(); auto defeatCol = SDLPP::RectColider( -1, 0, -1, -1 ); defeatCol.setInfinite(); defeat->addCollision( defeatCol ); scene->addObject( defeat ); leftStop = std::make_shared< SDLPP::RectangleRender >( -0.1, 0, 0.11, 0, renderer ); leftStop->setId( STOP_MOVEMENT ); leftStop->setAlignment( SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER ); leftStop->setPermanent(); auto leftStopCol = SDLPP::RectColider( 0, -1, 1, -1 ); leftStopCol.setInfinite(); leftStop->addCollision( leftStopCol ); leftStop->setColiderColor( "#FF00FF" ); scene->addObject( leftStop ); loadMap( scene, mario, "test_binary2.bin" ); auto font = std::make_shared< SDLPP::Font >( "testfont.ttf", 36 ); fps = std::make_shared< SDLPP::TextRenderer >( 0.2, 0, 0.78, 0.1, renderer, font, "0fps", "#FFFFFF", "#000000", 0.1, SDLPP_TEXT_RIGHT ); fps->setAlignment( SDLPP::OBJ_END, SDLPP::OBJ_START ); fps->setId( 0 ); fps->setPermanent(); fps->setHidden( true ); scene->addObject( fps ); coins = std::make_shared< SDLPP::TextRenderer >( 0.2, 0, 0.78, 0.1, renderer, font, "0 COINS", "#FFFFFF", "#000000", 0.1, SDLPP_TEXT_RIGHT ); coins->setAlignment( SDLPP::OBJ_START, SDLPP::OBJ_START ); coins->setId( 0 ); coins->setPermanent(); scene->addObject( coins ); FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 60 ); auto base = SDL_GetTicks(); int frames = 0; std::thread inputThread( doInput, scene ); scene->moveEverything( -mario->getDoubleRect().first.getX() + 0.2, 0 ); update = true; moving_objects.push_back(mario); std::unordered_set background_ids = { HILL_INCLINE_ID, HILL_DECLINE_ID, HILL_DOTS_RIGHT_ID, HILL_DOTS_LEFT_ID, HILL_FILL_ID, HILL_TOP_ID, BUSH_LEFT_ID, BUSH_MIDDLE_ID, BUSH_RIGHT_ID, CLOUD_LEFT_BOTTOM_ID, CLOUD_MIDDLE_BOTTOM_ID, CLOUD_RIGHT_BOTTOM_ID, CLOUD_LEFT_TOP_ID, CLOUD_MIDDLE_TOP_ID, CLOUD_RIGHT_TOP_ID, CASTLE_LEFT_ID, CASTLE_RIGHT_ID, CASTLE_BLACK_ID, CASTLE_ENTRY_ID, CASTLE_TOWER_ID, CASTLE_TOWER_FILLED_ID, WATER_TOP_ID, WATER_FILL_ID }; scene->setBackgroundObjectIDs(background_ids); scene->updateBackgroundObjectZIndex(); while ( !quit ) { SDL_PumpEvents(); SDL_framerateDelay( &gFPS ); std::lock_guard< std::mutex > lock( render_mutex ); mario->setStanding(); if ( update ) { scene->updateSizeAndPosition(); update = false; } scene->renderScene(); renderer->presentRenderer(); frames++; if ( SDL_GetTicks() - base >= 1000 ) { if ( global_frames < frames ) { frames = global_frames; } global_frames = 0; fps->changeText( std::to_string( frames ) + " fps" ); frames = 0; base = SDL_GetTicks(); } } inputThread.join(); return 0; }