/*! * * @file gameBasics.cpp * @author RUBINI Thomas * @author SIMAILA Djalim * @date January 2022 * @version 1.0 * @brief game basic mechanisms * */ #include #include #include #include "game.h" #include "playMode.h" #include "pixelManager/goodPixelManager.h" #define WININIT window("SUPER Space Invader : Turbo Apocalypse DX - VS GOD", Position(1280, 720), Position(128, 128), nsGraphics::KBlack) Game::Game() : WININIT { if(!reloadConfig()){ // Config throw runtime_error("Initial config loading failed. Please check the error above and fix the configuration"); } // Pixel Manager if(confData.theme=="good"){ pm = std::make_unique(window); }else if(confData.theme=="bad"){ pm = std::make_unique(window); }else throw runtime_error("Invalid theme value : "+confData.theme+ "\nValid values are : good,bad"); cout << "Loading sprites..." << endl; vector tasks; chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now(); pm->loadSprites(tasks); for(future& f : tasks)f.wait(); // We just do that for one sprite, so I didn't bother creating an 'API' for that pm->leftHand.mirror(pm->rightHand); chrono::high_resolution_clock::duration elapsed = chrono::high_resolution_clock::now()-start; cout << "Done ! Time : " << chrono::duration_cast(elapsed).count() << "ms" << endl; sm.readFile(); // Score manager } bool Game::areThereInvadersLeft(){ return grid.validColsNumber() > 0; } void Game::handleScoreSaving(){ for(unsigned i=0;iaskPlayerNameMenu(i, players[i].score, pName); sm.inputScore(move(pName), players[i].score); } sm.writeFile(); } void Game::managedGames() { playMode = PlayMode::NONE; while(playMode!=PlayMode::EXIT){ if(playMode==PlayMode::NONE){ playMode = pm->showInitialMenu(); }else{ DEBUG_MSG("Starting game") initGame(); enterGameLoop(); // will read the playMode DEBUG_MSG("END End of game") handleScoreSaving(); if(!pm->showDeathMenu(sm.scores))playMode = PlayMode::NONE; } } } // we assume the game has been played before, and so we need to clean used members void Game::initGame(){ grid = confData.grid; // will copy the grid // we re-construct players objects, we don't have to clear all members and can rely on the construction value (set in .h file) players.clear(); missiles.clear(); god.state = GodState::NONE; torpedos.clear(); if(playMode==PlayMode::SINGLE){ players.resize(1); }else{ players.resize(2); // mirror the start X Position for the other players[1].x = pm->getScreenWidth() - confData.startXPosition - confData.playersWidth; } players[0].x = confData.startXPosition; for(unsigned i=0;i(chrono::high_resolution_clock::now()-debugTime).count()) WinValue Game::enterGameLoop(){ // returns when game is finished // computed in advance for performance reasons chrono::milliseconds maxFrameTime = chrono::milliseconds(1000/confData.maxFPS); unsigned tmpFps = 0; unsigned fps = 0; typedef chrono::high_resolution_clock::time_point MyTimePoint; MyTimePoint fpsStartTime = {}; DEBUG_INSTR(MyTimePoint debugTime); while(window.isOpen()){ DEBUG_INSTR(fflush(stdout)); DEBUG_MSG("------------") MyTimePoint startTime = chrono::high_resolution_clock::now(); if(fpsStartTime.time_since_epoch()==chrono::seconds(0)){ fpsStartTime = startTime; } pm->startFrame(); START_TIMER() managePlayers(); PRINT_TIMER("manage players") START_TIMER() if(manageInvaders()) { // if they went down if (invadersTouchPlayer())return WinValue::INVADERS; tryAwakeGod(); } PRINT_TIMER("manage invaders") START_TIMER() if(manageGod())return WinValue::PLAYERS; if(arePlayersDead())return WinValue::GOD; PRINT_TIMER("god") START_TIMER() moveMissiles(); remCollidingProjectiles(); moveTorpedos(); remCollidingProjectiles(); PRINT_TIMER("self collisions") START_TIMER() checkMissilesAndPlayers(); if(checkTorpedosAndInvaders())return WinValue::PLAYERS; PRINT_TIMER("collisions between entities") if(arePlayersDead())return WinValue::INVADERS; START_TIMER() displayAll(fps); PRINT_TIMER("display") pm->endFrame(); MyTimePoint endTime = chrono::high_resolution_clock::now(); // This code is counted as part of frames, but that's not really something we can control if(fpsStartTime+chrono::seconds(1) < endTime){ fps = tmpFps; tmpFps = 0; fpsStartTime = {}; }else ++tmpFps; this_thread::sleep_until(startTime+maxFrameTime); } return WinValue::NOBODY; } Position Game::invIndexToPos(unsigned x, unsigned y) const { return basePos+Position(INV_GET_POS(x), INV_GET_POS(y)); } bool Game::arePlayersDead() { return all_of(players.begin(), players.end(), [](Player& p) -> bool {return p.isEliminated();}); }