#include "sdlpp.hpp" #include #include #include #define PLAYER_ID 0x00000001 #define STONE_ID 0x00000002 #define DEATH 0x00000003 #define DESTROYABLE_DESTROY 0x00000001 bool pause = false; int pause_select = 0; int pause_max = 1; std::vector< std::shared_ptr< SDLPP::RectangleRender > > pause_options; std::shared_ptr< SDLPP::Font > font; std::shared_ptr< SDLPP::Scene > active_scene; std::shared_ptr< SDLPP::Scene > pause_scene; void doInput( std::shared_ptr< SDLPP::Scene > scene ); void doInputPause(); class Player : public SDLPP::RectangleRender { public: Player( double x, double y, double w, double h, std::shared_ptr< SDLPP::Renderer > &r, double _max_gravity = 1.0, uint32_t _max_gravity_time = 1000 ) : SDLPP::RectangleRender( x, y, w, h, r ) { max_gravity = _max_gravity; jump_speed = 2.2 * max_gravity; max_gravity_time = _max_gravity_time; cur_gravity_time = max_gravity_time; } void setGravity( bool grav ) { gravity_enabled = grav; } void enableGravity() { gravity_enabled = true; } void disableGravity() { gravity_enabled = false; } bool isGravityEnabled() { return gravity_enabled; } bool isJumping() { return jumping; } void setLastStand() { cur_gravity_time = max_gravity_time; jumping = false; } void jump() { jumping = true; } virtual void custom_move( int ticks ) override { auto time_portion = ( static_cast< double >( ticks ) / 1000 ); cur_gravity_time -= ticks; auto grav = gravity_enabled * max_gravity * ( max_gravity_time - cur_gravity_time ) / max_gravity_time; if ( grav > max_gravity ) grav = max_gravity; // percentage of how close we are to maximum velocity of gravity (0 = // we've reached max velocity, 1 = we've just started accelerating) double division = static_cast< double >( cur_gravity_time ) / static_cast< double >( max_gravity_time ); // current jump speed auto jump_ = jumping * jump_speed * division; if ( division < 0.75 && division >= 0.72 ) { // in this time frame, just hover in same place jump_ = jumping * grav; } else if ( division < 0.72 ) { // fall slowly jump_ = jumping * jump_speed * division * 0.15; if ( jump_ > grav ) jump_ = grav; } if ( jump_ < 0 || jump_ > jump_speed ) jump_ = 0; og_y += grav * time_portion; og_y -= jump_ * time_portion; } private: double max_gravity = 1.0; double jump_speed = 2.0; uint32_t max_gravity_time = 1000; uint32_t cur_gravity_time = 1000; bool gravity_enabled = false; bool jumping = false; }; class Destroyable : public SDLPP::RectangleRender { public: Destroyable( double x, double y, double w, double h, std::shared_ptr< SDLPP::Renderer > &r ) : SDLPP::RectangleRender( x, y, w, h, r ) {} Destroyable( double x, double y, double w, double h, std::shared_ptr< SDLPP::Renderer > &r, int destruction_time ) : SDLPP::RectangleRender( x, y, w, h, r ) { destruction_countdown = destruction_time; } virtual void specialAction( int code ) override { if ( code == DESTROYABLE_DESTROY ) startDestruction(); } virtual void custom_move( int ticks ) override { if ( destruction ) { destruction_countdown -= ticks; if ( destruction_countdown <= 0 ) destroy(); } } private: void startDestruction() { destruction = true; } bool destruction = false; int destruction_countdown = 3000; }; std::shared_ptr< Player > player; bool quit = false; void addStuff( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r ) { auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, "#ebdbb2FF", true ); bg->setId( 123 ); bg->setPermanent( true ); scene.addObject( bg ); std::shared_ptr< Destroyable > stone; double posx = 0; while ( posx < 3 ) { stone = std::make_shared< Destroyable >( posx, 0.5, 0.15, 0.1, r, 1000 ); stone->addCollision( SDLPP::Rect( 0, 0, 1, 1 ) ); stone->setColor( "#222222FF" ); stone->setId( STONE_ID ); stone->setColiderColor( "FF0000" ); scene.addObject( stone ); posx += 0.45; } auto x = std::make_shared< Player >( 0, 0, 0.2, 0.2, r ); x->addCollision( SDLPP::Rect( 0.3, 0.7, 0.05, 0.31 ) ); x->addCollision( SDLPP::Rect( 0.65, 0.7, 0.05, 0.31 ) ); x->addCollision( SDLPP::Rect( 0.2, 0.3, 0.6, 0.45 ) ); x->addCollision( SDLPP::Circle( 0.5, 0.15, 0.3 ) ); x->setColor( "E164B7" ); x->setId( PLAYER_ID ); x->setColiderColor( "00FF00" ); scene.addObject( x ); player = x; auto z = std::make_shared< SDLPP::RectangleRender >( 0, 2.5, 0, 0, r ); auto z_col = SDLPP::Rect( -1, 0, -1, -1 ); z_col.setInfinite(); z->addCollision( z_col ); z->setId( DEATH ); z->setColiderColor( "FF00FF" ); scene.addObject( z ); auto y = std::make_shared< SDLPP::TextRenderer >( 0, 0, 0.2, 0.1, r ); y->setText( *font, "DEMO", "#FFFFFF", "#000000", 5 ); y->setPermanent( true ); y->setId( 123 ); scene.addObject( y ); } void addPause( SDLPP::Scene &scene, std::shared_ptr< SDLPP::Renderer > &r ) { auto bg = std::make_shared< SDLPP::RectangleRender >( 0, 0, 10, 10, r, "#00000080", 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", "#FFFFFF", "#000000", 5 ); y->setId( 0 ); y->centerX(); scene.addObject( y ); auto resume = std::make_shared< SDLPP::TextRenderer >( 0.4, 0.5, 0.2, 0.1, r ); resume->setText( *font, "Resume", "#FFFFFF", "#000000", 5 ); resume->setColor( "#FFFFFF40" ); resume->centerX(); scene.addObject( resume ); pause_options.push_back( resume ); auto quit = std::make_shared< SDLPP::TextRenderer >( 0.4, 0.7, 0.2, 0.1, r ); quit->setText( *font, "Quit Game", "#FFFFFF", "#000000", 5 ); quit->centerX(); scene.addObject( quit ); pause_options.push_back( quit ); } void quitGame() { std::cout << "Quitting!" << std::endl; quit = true; } void handleKeyDown( SDL_Keycode key, SDLPP::Scene &scene ) { switch ( key ) { case SDLK_ESCAPE: { pause = true; pause_scene->updateSizeAndPosition(); player->resetMovementX(); std::thread pauseThread( doInputPause ); pauseThread.detach(); } break; case SDLK_a: player->addMovement( -1, 0 ); break; case SDLK_d: player->addMovement( 1, 0 ); break; case SDLK_SPACE: case SDLK_w: if ( !player->isJumping() && !pause ) { player->setLastStand(); player->jump(); } break; case SDLK_s: break; case SDLK_r: scene.getRenderer().setRenderColiders( !scene.getRenderer().getRenderColiders() ); default: break; } } void handleKeyDownPause( SDL_Keycode key ) { switch ( key ) { case SDLK_ESCAPE: { pause = false; 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( "FFFFFF40" ); 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( "FFFFFF40" ); break; case SDLK_RETURN: switch ( pause_select ) { case 0: { pause = false; active_scene->setPrevTicks( SDL_GetTicks() ); std::thread inputThread( doInput, active_scene ); inputThread.detach(); } break; case 1: quitGame(); default: break; } default: break; } } void handleKeyUp( SDL_Keycode key ) { switch ( key ) { case SDLK_a: player->addMovement( 1, 0 ); break; case SDLK_d: player->addMovement( -1, 0 ); break; case SDLK_w: case SDLK_s: 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 doInput( std::shared_ptr< SDLPP::Scene > scene ) { FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 200 ); while ( !quit && !pause ) { SDL_framerateDelay( &gFPS ); pollEvents( *scene ); scene->movement(); bool gravity = true; for ( auto &x : scene->getCollisions( *player ) ) { if ( x->getId() == STONE_ID ) { gravity = false; if ( player->isGravityEnabled() ) { auto stoneRect = x->getDoubleRect(); auto playerPos = player->getDoubleRect(); auto newPX = playerPos.first.first; auto newPY = stoneRect.first.second - playerPos.second.second; player->setPos( newPX, newPY ); player->setLastStand(); } x->specialAction( DESTROYABLE_DESTROY ); } if ( x->getId() == DEATH ) { std::cout << "Oh no, you died!" << std::endl; quitGame(); } } player->setGravity( gravity ); auto playerX = player->getRect().x; auto width = scene->getWidth(); auto rightBarrier = width * 0.7; auto leftBarrier = width * 0.3; auto rightmostX = scene->rightmost()->getRect().x + scene->rightmost()->getRect().w; auto leftmostX = scene->leftmost()->getRect().x; scene->moveEverything( ( playerX > rightBarrier && rightmostX > width ) * ( rightBarrier - playerX ) / width, 0 ); scene->moveEverything( ( playerX < leftBarrier && leftmostX < 0 ) * ( leftBarrier - playerX ) / width, 0 ); } } void doInputPause() { FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 200 ); while ( pause ) { SDL_framerateDelay( &gFPS ); pollEventsPause(); if ( !pause ) break; } } int main() { SDLPP::init(); SDLPP::Window w( "Oh yeah, boi!" ); auto renderer = std::make_shared< SDLPP::Renderer >( w ); 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 ); player->setMovementSpeed( 0.3 ); player->enableGravity(); pause_scene = std::make_shared< SDLPP::Scene >( renderer ); addPause( *pause_scene, renderer ); int base = SDL_GetTicks(); int frames = 0; FPSmanager gFPS; SDL_initFramerate( &gFPS ); SDL_setFramerate( &gFPS, 60 ); std::thread inputThread( doInput, main_scene ); inputThread.detach(); while ( !quit ) { // SDL_framerateDelay(&gFPS); main_scene->renderScene(); if ( pause ) { pause_scene->renderScene( false ); } main_scene->presentScene(); frames++; if ( SDL_GetTicks() - base >= 1000 ) { base = SDL_GetTicks(); printf( "FPS: %d\n", frames ); frames = 0; } } }