148 lines
3.4 KiB
C++
148 lines
3.4 KiB
C++
#include <chrono>
|
|
#include <thread>
|
|
#include "game.h"
|
|
#include "play_mode.h"
|
|
|
|
#define WININIT window("space invader du turfu", nsGraphics::Vec2D(1280, 720), nsGraphics::Vec2D(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");
|
|
}
|
|
}
|
|
|
|
void Game::managedGames() {
|
|
|
|
playMode = NONE;
|
|
|
|
while(playMode!=EXIT){
|
|
if(playMode==NONE){
|
|
playMode = initialMenuHandler();
|
|
}else{
|
|
playGame(); // will read the playMode
|
|
cout << "END OF GAME" << endl;
|
|
break; // TODO remove
|
|
if(!deathMenuHandler()) playMode = NONE; // back to the main menu
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// TODO maybe directly call theses from pm and do not use getters ?
|
|
|
|
/**
|
|
* @return the mode the use chose, we he clicks it
|
|
*/
|
|
PlayMode Game::initialMenuHandler(){
|
|
switch(pm.showInitialMenu()){
|
|
case 0:{
|
|
return PlayMode::SINGLE;
|
|
}
|
|
case 1:{
|
|
return PlayMode::TWO_LOCAL;
|
|
}
|
|
case 2:{
|
|
return PlayMode::TWO_TCPIP;
|
|
}
|
|
}
|
|
return PlayMode::EXIT;
|
|
}
|
|
|
|
/**
|
|
* @return if true, the user wants to play again, same mode, false if he wants to go back to the main menu
|
|
*/
|
|
bool Game::deathMenuHandler(){
|
|
return pm.showDeathMenu();
|
|
}
|
|
|
|
bool Game::invadersTouchPlayer(){
|
|
for(invadersColumn& line : grid){
|
|
if(basePos.getY()+ line.size() * confData.invadersSize >= pm.getScreenHeight() - PLAYER_HEIGHT){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 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::playGame(){ // returns when game is finished
|
|
// INIT
|
|
// we assume the game has been played before, and so we need to clean used members
|
|
grid = confData.grid; // will copy the vector
|
|
|
|
|
|
if(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;
|
|
|
|
basePos = position(0,0);
|
|
|
|
// GAMELOOP
|
|
|
|
#define FPS 1000
|
|
while(true){
|
|
auto targetTime = chrono::high_resolution_clock::now() + chrono::duration<double, ratio<1, FPS>>(1);
|
|
|
|
pm.startFrame();
|
|
|
|
managePlayers();
|
|
if(manageInvaders() && invadersTouchPlayer())return WinValue::INVADERS;
|
|
|
|
moveMissiles();
|
|
remCollidingProjectiles();
|
|
moveTorpedos();
|
|
remCollidingProjectiles();
|
|
|
|
if(checkMissilesAndPlayers())return INVADERS;
|
|
if(checkTorpedosAndInvaders())return PLAYERS;
|
|
|
|
display();
|
|
|
|
pm.endFrame();
|
|
|
|
this_thread::sleep_until(targetTime);
|
|
}
|
|
}
|
|
|
|
/** Displays the screen once, and returns
|
|
*
|
|
*/
|
|
void Game::display() {
|
|
for (unsigned i = 0; i < this->grid.size(); ++i){
|
|
for (unsigned j = 0; j < this->grid[i].size(); ++j){
|
|
nsGraphics::Vec2D vec(
|
|
basePos.getX() + i * confData.invadersSize + i * confData.invadersDistance,
|
|
basePos.getY() + j * confData.invadersSize + j * confData.invadersDistance
|
|
);
|
|
switch(grid[i][j]){
|
|
case 0:{
|
|
pm.dessinerInvader1(vec, confData.invadersSize);
|
|
break;
|
|
}
|
|
case 1:{
|
|
pm.dessinerInvader2(vec, confData.invadersSize);
|
|
break;
|
|
}
|
|
case 2:{
|
|
pm.dessinerInvader3(vec, confData.invadersSize);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(size_t i=0;i<players.size();++i){
|
|
pm.dessinerJoueur(position(players[i].x, 0), confData.playersWidth, confData.playerDefs[i].color);
|
|
}
|
|
} |