#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> pause_options; std::shared_ptr font; std::shared_ptr active_scene; std::shared_ptr pause_scene; void doInput(std::shared_ptr scene); void doInputPause(); class Player : public SDLPP::RectangleRender { public: Player(double x, double y, double w, double h, std::shared_ptr &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(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(cur_gravity_time)/static_cast(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; y_ += grav * time_portion; 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 &r) : SDLPP::RectangleRender(x,y,w,h,r) {} Destroyable(double x, double y, double w, double h, std::shared_ptr &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; bool quit = false; void addStuff(SDLPP::Scene &scene, std::shared_ptr &r) { auto bg = std::make_shared(0,0,10,10,r,"#ebdbb2FF", true); bg->setId(123); bg->setPermanent(true); scene.addObject(bg); std::shared_ptr stone; double posx = 0; while(posx < 3) { stone = std::make_shared(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(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(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(0, 0, 0.2, 0.1, r); y->setTexture(*font, "DEMO", "#FFFFFF", "#000000", 5); y->setId(0); scene.addObject(y); } void addPause(SDLPP::Scene &scene, std::shared_ptr &r) { auto bg = std::make_shared(0,0,10,10,r,"#00000080", true); bg->setId(123); bg->setPermanent(true); scene.addObject(bg); auto y = std::make_shared(0.25, 0.1, 0.5, 0.3, r); y->setTexture(*font, "PAUSED", "#FFFFFF", "#000000", 5); y->setId(0); y->centerX(); scene.addObject(y); auto resume = std::make_shared(0.4, 0.5, 0.2, 0.1, r); resume->setTexture(*font, "Resume", "#FFFFFF", "#000000", 5); resume->setColor("#FFFFFF40"); resume->centerX(); scene.addObject(resume); pause_options.push_back(resume); auto quit = std::make_shared(0.4, 0.7, 0.2, 0.1, r); quit->setTexture(*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 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(w); renderer->setBlendMode(SDL_BLENDMODE_BLEND); auto main_scene = std::make_shared(renderer); active_scene = main_scene; font = std::make_shared("testfont.ttf", 96); addStuff(*main_scene, renderer); player->setMovementSpeed(0.3); player->enableGravity(); pause_scene = std::make_shared(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; } } }