diff --git a/README b/README index b9a2049..01e1edf 100644 --- a/README +++ b/README @@ -1,8 +1,10 @@ Conventions à suivre : -camelCase pour les noms de variables/fonctions/fichiers +camelCase pour les noms de variables/fonctions PascalCase pour les noms de classes/structures +snake case pour les noms de fichiers Nommage en anglais Pas de fonctions de +100 lignes +Les guards sont de cette forme : GUARD__H écran : constante 1280x720 diff --git a/config.yaml b/config.yaml index 45a200f..7ebb652 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ -# User config -users: +# Players config +players: width: 250 startPositionX: 0 speed: 5 diff --git a/headers/config.h b/headers/config.h index 40af069..5913878 100644 --- a/headers/config.h +++ b/headers/config.h @@ -1,11 +1,14 @@ -#ifndef GUARD_CONFIG -#define GUARD_CONFIG +#ifndef GUARD_CONFIG_H +#define GUARD_CONFIG_H #include #include "utils.h" +#include "player_def.h" using namespace std; +typedef string configKey; + class Config{ public: aliensGrid grid; @@ -22,7 +25,14 @@ public: unsigned alien_speed; unsigned player_speed; + PlayerDef p1Def; + PlayerDef p2Def; + unsigned startXPosition; + bool loadConfig(); + string getString(configKey& key); + int getInt(configKey& key); + nsGraphics::RGBAcolor getColor(configKey& key); }; #endif \ No newline at end of file diff --git a/headers/game.h b/headers/game.h index 5492985..dd670c7 100644 --- a/headers/game.h +++ b/headers/game.h @@ -6,6 +6,9 @@ #include "config.h" #include "utils.h" #include "position.h" +#include "player_def.h" +#include "player.h" +#include "play_mode.h" using namespace std; @@ -21,27 +24,31 @@ private: vector missiles; vector torpedos; - unsigned playerX; - void managePlayer(); + PlayMode playMode; + Player p1; + Player p2; + + void managePlayers(); bool manageInvaders(); void display(); // collision thingies - unsigned manageAllCollisions(); void remCollidingProjectiles(); void moveMissiles(); void moveTorpedos(); - bool checkMissilesAndPlayer(); + bool checkMissilesAndPlayers(); bool checkTorpedosAndInvaders(); - bool invadersTouchFloor(); + bool invadersTouchPlayer(); + + void managePlayerMoves(PlayerDef&, unsigned&); public: // in case someone wants to mess with the code, here's a minimal API, costs nothing to us Game(); void managedGames(); - unsigned playGame(); - void initialMenuHandler(); - void deathMenuHandler(); + WinValue playGame(); + PlayMode initialMenuHandler(); + bool deathMenuHandler(); }; diff --git a/headers/pixel_manager.h b/headers/pixel_manager.h index 8b86229..3e82171 100644 --- a/headers/pixel_manager.h +++ b/headers/pixel_manager.h @@ -1,5 +1,5 @@ -#ifndef GUARD_DRAWENGINE -#define GUARD_DRAWENGINE +#ifndef GUARD_DRAWENGINE_H +#define GUARD_DRAWENGINE_H #include "mingl/mingl.h" #include "mingl/shape/line.h" @@ -14,7 +14,7 @@ public: void dessinerInvader1(const nsGraphics::Vec2D& baseVector, unsigned size); void dessinerInvader2(const nsGraphics::Vec2D& baseVector, unsigned size); void dessinerInvader3(const nsGraphics::Vec2D& baseVector, unsigned size); - void dessinerJoueur(const nsGraphics::Vec2D& baseVector, unsigned size); + void dessinerJoueur(const nsGraphics::Vec2D& baseVector, unsigned size, const nsGraphics::RGBAcolor&); unsigned showInitialMenu(); unsigned showDeathMenu(); diff --git a/headers/play_mode.h b/headers/play_mode.h new file mode 100644 index 0000000..56286e0 --- /dev/null +++ b/headers/play_mode.h @@ -0,0 +1,13 @@ +#ifndef GUARD_PLAYMODE_H +#define GUARD_PLAYMODE_H + +enum PlayMode { + NONE, + SINGLE, + TWO_LOCAL, + TWO_TCPIP, + EXIT, +}; + + +#endif diff --git a/headers/player.h b/headers/player.h new file mode 100644 index 0000000..a9fbeac --- /dev/null +++ b/headers/player.h @@ -0,0 +1,9 @@ +#ifndef GUARD_PLAYER_H +#define GUARD_PLAYER_H + +struct Player{ + unsigned lives; + unsigned x; +}; + +#endif \ No newline at end of file diff --git a/headers/player_def.h b/headers/player_def.h new file mode 100644 index 0000000..7eb2886 --- /dev/null +++ b/headers/player_def.h @@ -0,0 +1,17 @@ +#ifndef GUARD_PLAYER_DEF_H +#define GUARD_PLAYER_DEF_H + +#include "mingl/graphics/rgbacolor.h" + +struct PlayerKeys { + char right; + char left; + char shoot; +}; + +struct PlayerDef { + nsGraphics::RGBAcolor color; + PlayerKeys keys; +}; + +#endif diff --git a/headers/position.h b/headers/position.h index 1718b29..e757520 100644 --- a/headers/position.h +++ b/headers/position.h @@ -1,5 +1,5 @@ -#ifndef SPACE_POSITION_H -#define SPACE_POSITION_H +#ifndef GUARD_POSITION_H +#define GUARD_POSITION_H #include @@ -10,4 +10,4 @@ public: bool isColliding(position& p, int rx, int ry); }; -#endif //SPACE_POSITION_H +#endif diff --git a/headers/utils.h b/headers/utils.h index b396f82..5634574 100644 --- a/headers/utils.h +++ b/headers/utils.h @@ -1,17 +1,20 @@ -#ifndef SPACE_STRUCTS_H -#define SPACE_STRUCTS_H +#ifndef GUARD_STRUCTS_H +#define GUARD_STRUCTS_H #include #include #include "position.h" // hardcoded values -#define PLAYER_WINS 1 -#define INVADERS_WINS 2 -#define PLAYER_HEIGHT 100 #define PLAYER_HEIGHT 100 #define PROJ_LENGTH_FACTOR 2 +enum WinValue{ + NOBODY, // should never be used, but hey + PLAYERS, + INVADERS, +}; + using namespace std; typedef unsigned Alien; diff --git a/src/config.cpp b/src/config.cpp index 23755fb..89addb3 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -18,6 +18,36 @@ bool Config::loadConfig() { torpedo_length = 15; player_width = 1000; + startXPosition = 0; + p1Def.color = nsGraphics::KTeal; return true; } + +int Config::getInt(configKey& key) { +} + +string Config::getString(configKey& key) { +} + +nsGraphics::RGBAcolor Config::getColor(configKey& key) { + // switch do not work with strings, and I don't want to implement a constexpr hash function + string colorStr = getString(key); + if (colorStr == "black")return nsGraphics::KBlack; + else if (colorStr == "white")return nsGraphics::KWhite; + else if (colorStr == "red")return nsGraphics::KRed; + else if (colorStr == "lime")return nsGraphics::KLime; + else if (colorStr == "blue")return nsGraphics::KBlue; + else if (colorStr == "yellow")return nsGraphics::KYellow; + else if (colorStr == "cyan")return nsGraphics::KCyan; + else if (colorStr == "magenta")return nsGraphics::KMagenta; + else if (colorStr == "silver")return nsGraphics::KSilver; + else if (colorStr == "gray")return nsGraphics::KGray; + else if (colorStr == "maroon")return nsGraphics::KMaroon; + else if (colorStr == "olive")return nsGraphics::KOlive; + else if (colorStr == "green")return nsGraphics::KGreen; + else if (colorStr == "purple")return nsGraphics::KPurple; + else if (colorStr == "teal")return nsGraphics::KTeal; + else if (colorStr == "navy")return nsGraphics::KNavy; + else throw runtime_error("Invalid color string : "+colorStr); +} diff --git a/src/game_basics.cpp b/src/game_basics.cpp index b11916a..469254b 100644 --- a/src/game_basics.cpp +++ b/src/game_basics.cpp @@ -1,8 +1,9 @@ #include #include #include "game.h" +#include "play_mode.h" -#define WININIT window("space invader du turfu ma gueule", nsGraphics::Vec2D(1280, 720), nsGraphics::Vec2D(128, 128), nsGraphics::KBlack) +#define WININIT window("space invader du turfu", nsGraphics::Vec2D(1280, 720), nsGraphics::Vec2D(128, 128), nsGraphics::KBlack) Game::Game() : WININIT, pm(window) { @@ -11,37 +12,47 @@ Game::Game() : WININIT, pm(window) { void Game::managedGames() { - initialMenuHandler(); // returns when user clicked plays + playMode = NONE; - while(true){ - playGame(); - cout << "END OF GAME" << endl; - break; - deathMenuHandler(); // returns when user clicked replay + 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 + + } } } -void Game::initialMenuHandler(){ + +// 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:{ // play - return; + case 0:{ + return PlayMode::SINGLE; } // potential options... } + return PlayMode::EXIT; } -void Game::deathMenuHandler(){ - switch(pm.showDeathMenu()){ - case 0:{ // play - return; - } - // potential options... - } +/** + * @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::invadersTouchFloor(){ +bool Game::invadersTouchPlayer(){ for(aliensLine& line : grid){ - if(basePos.getY()+line.size()*conf.alien_size>=pm.getScreenHeight()){ + if(basePos.getY()+line.size()*conf.alien_size>=pm.getScreenHeight()-PLAYER_HEIGHT){ return true; } } @@ -51,31 +62,46 @@ bool Game::invadersTouchFloor(){ /** * Plays the game, and returns once the game is finished * - * @return 1 if the player won, 2 is the invaders won, any other value can be returned in case of a problem + * @return WinValue::PLAYERS if the players won, WinValue::INVADERS is the invaders won, WinValue::NOBODY else (also in case of error) */ -unsigned Game::playGame(){ // returns when game is finished +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 = conf.grid; // will copy the vector - playerX = 0; + + p1.x = conf.startXPosition; + + if(playMode!=SINGLE){ + // mirror the start X position for the other + p2.x = pm.getScreenWidth()-conf.startXPosition-conf.player_width; + } + basePos = position(0,0); // GAMELOOP #define FPS 1000 while(true){ - auto target = chrono::high_resolution_clock::now() + chrono::duration>(1); + auto targetTime = chrono::high_resolution_clock::now() + chrono::duration>(1); pm.startFrame(); - managePlayer(); - if(manageInvaders() && invadersTouchFloor())return INVADERS_WINS; - unsigned res = manageAllCollisions(); // also moves missiles + torpedos - if(res!=0)return res; + 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(target); + this_thread::sleep_until(targetTime); } } @@ -105,5 +131,7 @@ void Game::display() { } } } - pm.dessinerJoueur(position(playerX, 0), conf.player_width); + cout << p1.x << endl; + pm.dessinerJoueur(position(p1.x, 0), conf.player_width, conf.p1Def.color); + if(playMode!=SINGLE)pm.dessinerJoueur(position(p2.x, 0), conf.player_width, conf.p2Def.color); } \ No newline at end of file diff --git a/src/game_managers.cpp b/src/game_managers.cpp index 605d2bc..63827bb 100644 --- a/src/game_managers.cpp +++ b/src/game_managers.cpp @@ -4,22 +4,29 @@ #define MISSILE_SPEED 5 #define TORPEDO_SPEED MISSILE_SPEED -/** Makes the player play once -*/ -void Game::managePlayer(){ - if (window.isPressed({'q', false})){ +#define ISPRESSED(X) window.isPressed({X, false}) + +void Game::managePlayerMoves(PlayerDef& pdef, unsigned& playerX){ + if (ISPRESSED(pdef.keys.left)){ if(playerX < conf.player_speed) playerX = 0; else playerX = playerX-conf.player_speed; } - if (window.isPressed({'d', false})){ + if (ISPRESSED(pdef.keys.right)){ if(playerX+conf.player_speed>=pm.getScreenWidth()) playerX = pm.getScreenWidth()-1; else playerX = playerX+conf.player_speed; } - if(window.isPressed({' ', false})){ + if(ISPRESSED(pdef.keys.shoot)){ torpedos.emplace_back(playerX+conf.player_width/2, pm.getScreenHeight()-PLAYER_HEIGHT); } } +/** Makes the players play once +*/ +void Game::managePlayers(){ + managePlayerMoves(conf.p1Def, p1.x); + if(playMode==PlayMode::TWO_LOCAL)managePlayerMoves(conf.p2Def, p2.x); +} + /** Makes the invaders play once, and check lower bounds * * @return true if the invaders went down from one line (and we should check lower boundary), else false @@ -30,7 +37,7 @@ bool Game::manageInvaders(){ end+= grid.size()*conf.alien_size; // add the aliens end+= (grid.size()-1)*conf.distance; // add the distance between aliens - // you got the end ! + // you got the end position of the alien crowd ! if(end+conf.alien_speed