SuperSpaceInvaderTurboApoca.../src/game/gameBasics.cpp

162 lines
4.0 KiB
C++

/*!
*
* @file gameBasics.cpp
* @author RUBINI Thomas
* @author SIMAILA Djalim
* @date January 2022
* @version 1.0
* @brief game basic mechanisms
*
*/
#include <chrono>
#include <thread>
#include "game.h"
#include "playMode.h"
#define WININIT window("SUPER Space Invader : Turbo Apocalypse DX - VS GOD", Position(1280, 720), Position(128, 128), nsGraphics::KBlack)
Game::Game() : WININIT, pm(window) {
if(!reloadConfig()){
throw runtime_error("Initial config loading failed. Please check the error above and fix the configuration");
}
sm.readFile();
}
bool Game::updateColumns(){
while(true){
if(grid.empty())return true;
if(grid.at(0).hasNoValid()){
grid.erase(grid.begin());
basePos+=confData.invadersSize+confData.invadersDistance;
}else break;
}
while(grid.at(grid.size() - 1).hasNoValid()){
grid.erase(grid.end()-1);
}
return false;
}
void Game::handleScoreSaving(){
cout << players[0].score << endl; // will remove
string pName;
pm.askPlayerNameMenu(0, pName);
sm.inputScore(pName, players[0].score);
if(playMode==PlayMode::TWO_LOCAL){
string pName2;
pm.askPlayerNameMenu(1, pName2);
sm.inputScore(pName, players[1].score);
}
sm.writeFile();
}
void Game::managedGames() {
playMode = PlayMode::NONE;
god.state = GodState::NONE;
while(playMode!=PlayMode::EXIT){
if(playMode==PlayMode::NONE){
playMode = pm.showInitialMenu();
}else{
initGame();
enterGameLoop(); // will read the playMode
handleScoreSaving();
cout << "END OF GAME" << endl;
playMode = pm.showDeathMenu();
}
}
}
// 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
updateColumns(); // Would have liked to to that in the "config grid", but.. I'm lazy
// 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();
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<players.size();++i){
players[i].id = i;
players[i].lives = confData.playersLives;
}
basePos = Position(200, 0);
}
/**
* Plays the game, and returns once the game is finished
*
* @return @WinValue::PLAYERS if the players won, @WinValue::INVADERS is the invaders won, WinValue::NOBODY else (also in case of error)
*/
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 = {};
while(window.isOpen()){
MyTimePoint startTime = chrono::high_resolution_clock::now();
if(fpsStartTime.time_since_epoch()==chrono::seconds(0)){
fpsStartTime = startTime;
}
pm.startFrame();
managePlayers();
if(manageInvaders()) { // if they went down
if (invadersTouchPlayer())return WinValue::INVADERS;
// TODO abstract this ?
if (basePos.getY() > 100 /*lambda value*/ && god.state==GodState::NONE) {
awakeGod();
}
}
manageGod();
moveMissiles();
remCollidingProjectiles();
moveTorpedos();
remCollidingProjectiles();
if(checkMissilesAndPlayers())return WinValue::INVADERS;
if(checkTorpedosAndInvaders())return WinValue::PLAYERS;
displayAll(fps);
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));
}