diff --git a/config.yml b/config.yml index 4079253..90d2329 100644 --- a/config.yml +++ b/config.yml @@ -58,6 +58,8 @@ general: # # The keys settings will define the key configuration of the player # the keys must be non function keys (F1 -> F12) +# The keys used for menu navigation are hardcoded to be "zqsd" +# we weren't sure if the best choice was to do that, or to add yet again another config section # keys: # left: q # right: d diff --git a/headers/game.h b/headers/game.h index 3714560..b6707c2 100644 --- a/headers/game.h +++ b/headers/game.h @@ -103,12 +103,6 @@ private: unsigned fireCooldown=0; // basic methods - - /*! - * @brief Set or reset all the setting for a new game - * @fn void initGame(); - */ - void initGame(); /*! * @brief @@ -125,12 +119,12 @@ private: /*! * @brief convert invader's matrix position to pixel coodinates - * @return pixel position object + * @param[in] x : column index of the invader in the grid + * @param[in] y : invader index of the invader in the column + * @return the pixel position of the invader * @fn Position invIndexToPos(unsigned x, unsigned y) const; */ Position invIndexToPos(unsigned x, unsigned y) const; - - // drawing methods /*! * @brief display players score on the screen @@ -242,7 +236,7 @@ private: bool manageGod(); public: - // in case someone wants to mess with the code, here's a minimal API, costs nothing to us + // in case someone wants to mess with the code, here's a minimal public API, costs nothing to us /*! * @brief constructor for the game class @@ -251,11 +245,17 @@ public: Game(); /*! - * @brief manages and changes the states of the game + * @brief start games managed by our class * @fn void managedGames(); */ void managedGames(); - + + /*! + * @brief Set or reset all the setting for a new game + * @fn void initGame(); + */ + void initGame(); + /*! * @brief enter the main gameplay game loop * @return the value of the winners can be the players, the invaders or god diff --git a/headers/god.h b/headers/god.h index 34361d9..57ff782 100644 --- a/headers/god.h +++ b/headers/god.h @@ -58,15 +58,14 @@ public: unsigned counter; - // we do not use a Position because it is used for pixel X and Y - + // we do not use a Position because it is not used for pixel coordinate, but vector indexes /*! - * @brief x pixel coordinate of the invader thrown by the hand of god + * @brief x index (column in the grid) of the invader thrown by the hand of god */ unsigned thrownInvPosX; /*! - * @brief y pixel coordinate of the invader thrown by the hand of god + * @brief y index (invader in the column) of the invader thrown by the hand of god */ unsigned thrownInvPosY; @@ -81,7 +80,7 @@ public: Position thrownVector; /*! - * @brief position of a point for bezier's curve + * @brief position of a point for bezier's curve (used in RETRIEVE1 and RETRIEVE2 states, for the hand animation) */ Position thrownTransition; diff --git a/headers/invadersGrid.h b/headers/invadersGrid.h index 78f1ac3..f6d23ed 100644 --- a/headers/invadersGrid.h +++ b/headers/invadersGrid.h @@ -49,12 +49,12 @@ public: unsigned getOutterInvader() const; /*! - * @brief - * @return - * @fn + * @brief Returns a random valid invader in the column (reminder, the column can contains NONE invaders) + * @return an index pointing to an invader in this column + * @fn unsigned randomValidInv() const; */ unsigned randomValidInv() const; -}; // class InvadersColumn +}; /*! @@ -65,12 +65,20 @@ class InvadersGrid : public vector{ public: /*! - * @brief List of all invader type - * @return - * @fn + * @brief Helper function for randomValidCol() that returns the number of valid column + * (at least one invader in them) in the grid + * This is a separate function because we need to use it elsewhere + * @return The number of valid columns in the grid + * @fn unsigned validColsNumber() const; */ unsigned validColsNumber() const; + + /*! + * @brief Returns a random valid column in the grid + * @return an index pointing to a column in the grid + * @fn unsigned randomValidCol() const; + */ unsigned randomValidCol() const; }; diff --git a/headers/menu.h b/headers/menu.h index 18de8d0..6cc0e25 100644 --- a/headers/menu.h +++ b/headers/menu.h @@ -28,7 +28,7 @@ struct Menu{ /*! * @brief index of currently selected menu option */ - unsigned currentValue = 0; + unsigned selectedEntry = 0; /*! * @brief color of currently selected menu option diff --git a/headers/mySprite.h b/headers/mySprite.h index 028c16c..3f83c04 100644 --- a/headers/mySprite.h +++ b/headers/mySprite.h @@ -2,14 +2,31 @@ #define GUARD_MYSPRITE_H #include +#include #include "mingl/gui/sprite.h" +#include "pixelManager/pixelManager.h" using namespace std; class MySprite{ public: - unique_ptr ptr; - future asyncLoad(const string& fname); + /*! + * @brief optional actual Sprite + * We need to use an optional to init the object through a function, that can be used with std::async + */ + optional sp; + + /*! + * @brief load a sprite asynchronously + * @fn Task asyncLoad(const string& fname); + * @returns An async task of the loading action + */ + Task asyncLoad(const string& fname); + + /*! + * @brief Mirror a sprite pixel data into this one + * @fn void mirror(MySprite& msp); + */ void mirror(MySprite& msp); }; diff --git a/headers/pixelManager/pixelManager.h b/headers/pixelManager/pixelManager.h index 1e469d1..3baa9ae 100644 --- a/headers/pixelManager/pixelManager.h +++ b/headers/pixelManager/pixelManager.h @@ -40,7 +40,7 @@ typedef nsGui::GlutFont::GlutFonts Font; * It's MinGL's fault. This is all I have to say */ -// The convention seems to just add a number to the macro name +// The convention to add another argument seems to just add a number to the macro name #define ADD_SPRITE_TASK(X) ADD_SPRITE_TASK2(X, X) #define ADD_SPRITE_TASK2(X, Y) tasks.push_back((X).asyncLoad("assets/"#Y".si2")); @@ -50,7 +50,6 @@ typedef future Task; class PixelManager{ public: MinGL& window; - mutable vector drawTasks; /*! @@ -172,24 +171,7 @@ public: * @fn void displayButton(const Position& baseVector,const string& text,nsGraphics::RGBAcolor& color); */ void displayButton(const Position& baseVector,const string& text,nsGraphics::RGBAcolor& color); - - /*! - * @brief display a menu on screen - * @param[in] pos : pixel coordinates of the menu - * @param[in,out] currentMenu : menu struct conteining the menu option - * @fn void displayMenu(const Position& pos, Menu& currentMenu); - */ - void displayMenu(const Position& pos, Menu& currentMenu); - - /*! - * @brief display a menu on screen - * @param[in] pos : pixel coordinates of the menu - * @param[in,out] currentMenu : menu struct conteining the menu option - * @param[in] rankings : the current top 10 players - * @param[in] winner : the winner of the game - * @fn void displayMenu(const Position& pos, Menu& currentMenu); - */ - void displayMenu(const Position& pos, Menu& currentMenu, const vector& rankings,const WinValue& winner); + /*! * @brief display text on screen * @param[in] pos : pixel coordinates of the text @@ -268,16 +250,24 @@ public: void drawGodFace(int y, bool angry=false) const; private: - // Explanation for choices : - // non reference output : I don't think we have another choice than a std::move() here - + /*! - * @brief - * @param[in] inPixel : vector of pixel from a sprite - * @param[in] rowSize : size of a line of pixel - * @fn vector mirrorData(const vector& inPixels, unsigned rowSize); + * @brief display a menu on screen + * @param[in] pos : pixel coordinates of the menu + * @param[in,out] currentMenu : menu struct conteining the menu option + * @fn void drawMenu(const Position& pos, Menu& currentMenu); */ - static vector mirrorData(const vector& inPixels, unsigned rowSize); + void drawMenu(const Position& pos, Menu& currentMenu); + + /*! + * @brief display a menu on screen + * @param[in] pos : pixel coordinates of the menu + * @param[in,out] currentMenu : menu struct conteining the menu option + * @param[in] rankings : the current top 10 players + * @param[in] winner : the winner of the game + * @fn void drawMenu(const Position& pos, Menu& currentMenu); + */ + void drawMenu(const Position& pos, Menu& currentMenu, const vector& rankings, const WinValue& winner); }; diff --git a/headers/player.h b/headers/player.h index 55ee42d..9a3d172 100644 --- a/headers/player.h +++ b/headers/player.h @@ -49,9 +49,32 @@ struct Player{ */ unsigned fireCooldown=0; + + /*! + * @brief Tells if the player has a death animation ongoing + * @fn bool hasDeathAnimation() const; + * @returns true is the player has a death animation ongoing + */ bool hasDeathAnimation() const; + + /*! + * @brief Tells if the player is eliminated (no more lives) + * @fn bool isEliminated() const; + * @returns true is the player is eliminated (no more lives) + */ bool isEliminated() const; + + /*! + * @brief Tells if the player is playing, or has a death animation/is eliminated + * @fn bool isPlaying() const + * @returns true is the player is playing + */ bool isPlaying() const; + + /*! + * @brief Damage the player (no precondition on existing state) + * @fn void damage; + */ void damage(); }; diff --git a/headers/utils.h b/headers/utils.h index d194ff0..2ee6a01 100644 --- a/headers/utils.h +++ b/headers/utils.h @@ -18,10 +18,7 @@ #define PLAYER_HEIGHT 100 #define PROJ_LENGTH_FACTOR 2 -/* Copy constructuor and assignement are disabled in most of - * our classes so we're sure we can't accidentally copy players - * (We need to explicitly specify the default constructor)*/ -#define INV_GET_POS(i) confData.invadersSize*(i)+confData.invadersDistance*(i) +#define INV_GET_SINGLE_POS(i) confData.invadersSize*(i)+confData.invadersDistance*(i) // Syntax : DEBUG(cout << "hey" << endl) // The debug flag defintion has been set here, but normally we would add it to the MakeFile @@ -55,22 +52,21 @@ typedef unsigned playerID; #define PLAYER1 0 #define PLAYER2 1 -// didn't want to use Position because of the semantic with x and y +// /*! - * @brief tells if 2 lines are colliding in a 1 dimentionnal space + * @brief tells if 2 lines are colliding in a 1 dimensional space. Didn't want to use Position because of the semantic with x and y * @param[in] start1 : position of the first point of the first line * @param[in] end1: posision of the last point of the first line * @param[in] start2 : position of the first point of the seconde line * @param[in] end2: posision of the last point of the second line - * @return true if they are -olliding, false elsewise */ + * @return true if they are colliding, false otherwise */ bool areLinesColliding(unsigned start1, unsigned end1, unsigned start2, unsigned end2); // change draw position for a specified size (keeps the same center) /*! - * @brief change the size of a Position object + * @brief change the position object to reflect the top-right position of a "sizeTo"-sized entity, from a "sizeFrom"-sized entity, keeping the same center * @param[in,out] pos : Position object * @param[in] sizeFrom: current size of the objet * @param[in] sizeTo : new size of the object diff --git a/src/game/display.cpp b/src/game/display.cpp index df5be6f..cf851a8 100644 --- a/src/game/display.cpp +++ b/src/game/display.cpp @@ -100,7 +100,7 @@ void Game::displayInvader(const Position& pos, InvaderType type) const { } } -void applyBezier(Position& pos, const Position& point, const double percent) { +void applyBezierCurbe(Position& pos, const Position& point, const double percent) { pos += (point-pos)*percent; } @@ -138,8 +138,8 @@ void Game::displayGod() const { Position pos(god.getRightHandPos(pm->getScreenWidth())); Position endPos = invIndexToPos(god.thrownInvPosX, god.thrownInvPosY); - applyBezier(pos, god.thrownTransition, god.counter / 100.0); - applyBezier(pos, endPos, god.counter / 100.0); + applyBezierCurbe(pos, god.thrownTransition, god.counter / 100.0); + applyBezierCurbe(pos, endPos, god.counter / 100.0); // pos is now the position we need to draw our hand to pm->drawSprite(pm->rightHand, pos); diff --git a/src/game/gameBasics.cpp b/src/game/gameBasics.cpp index b3288bc..59ea6df 100644 --- a/src/game/gameBasics.cpp +++ b/src/game/gameBasics.cpp @@ -10,7 +10,6 @@ */ #include -#include #include #include "game.h" #include "playMode.h" @@ -37,7 +36,7 @@ Game::Game() : WININIT { chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now(); pm->loadSprites(tasks); - for(future& f : tasks)f.wait(); + for(Task& 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); @@ -75,7 +74,7 @@ void Game::managedGames() { whoWon = enterGameLoop(); // will read the playMode DEBUG_MSG("END End of game") handleScoreSaving(); - if(!pm->showDeathMenu(sm.scores,whoWon))playMode = PlayMode::NONE; + if(!pm->showDeathMenu(sm.scores, whoWon))playMode = PlayMode::NONE; } } } @@ -170,7 +169,7 @@ WinValue Game::enterGameLoop(){ // returns when game is finished } Position Game::invIndexToPos(unsigned x, unsigned y) const { - return basePos+Position(INV_GET_POS(x), INV_GET_POS(y)); + return basePos+Position(INV_GET_SINGLE_POS(x), INV_GET_SINGLE_POS(y)); } bool Game::arePlayersDead() { diff --git a/src/game/gameManagers.cpp b/src/game/gameManagers.cpp index 3eae4f7..cd60b8d 100644 --- a/src/game/gameManagers.cpp +++ b/src/game/gameManagers.cpp @@ -61,23 +61,20 @@ bool Game::manageInvaders(){ )); }else --fireCooldown; - // moving - // TODO fix this lol if(direction){ // go to the right int end = basePos.getX(); // start Position end+= grid.size() * confData.invadersSize; // add the invaders end+= (grid.size()-1) * confData.invadersDistance; // add the invadersDistance between invaders - // you got the end position of the invader crowd ! - unsigned relativeScreenWidth = pm->getScreenWidth(); + size_t i = grid.size()-1; while (grid[i].hasNoValid()){ - relativeScreenWidth += confData.invadersSize + confData.invadersDistance; + end -= (confData.invadersSize + confData.invadersDistance); --i; } - if(end + confData.invadersSpeed < relativeScreenWidth){ + if(end + confData.invadersSpeed < pm->getScreenWidth()){ basePos.setX(basePos.getX() + confData.invadersSpeed); } else{ diff --git a/src/game/godManager.cpp b/src/game/godManager.cpp index edfdb39..bcdce3c 100644 --- a/src/game/godManager.cpp +++ b/src/game/godManager.cpp @@ -22,7 +22,8 @@ void Game::tryAwakeGod() { */ /* This is a really long function, but I feel like it's still readable because of the switch, and... - * Honestly I think splitting it into multiple small functions would be ugly*/ + * Honestly I think splitting it into multiple small functions would be uglier + * Each state is responsible for managing the counter*/ bool Game::manageGod() { switch (god.state) { case GodState::NONE: { @@ -49,7 +50,7 @@ bool Game::manageGod() { god.thrownInvType = InvaderType::NONE; god.thrownTransition.setX(pm->getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE); - god.thrownTransition.setY(basePos.getY() + INV_GET_POS(god.thrownInvPosY)); + god.thrownTransition.setY(basePos.getY() + INV_GET_SINGLE_POS(god.thrownInvPosY)); return false; } case GodState::RETRIEVE1: { diff --git a/src/invaderGrids.cpp b/src/invaderGrids.cpp index e71791b..d99275b 100644 --- a/src/invaderGrids.cpp +++ b/src/invaderGrids.cpp @@ -44,7 +44,7 @@ unsigned InvadersColumn::randomValidInv() const { ++validIndex; } } - throw runtime_error("SHOULD NOT HAPPEN"); + throw runtime_error("SHOULD NOT HAPPEN : see randomValidInv()"); } unsigned InvadersGrid::validColsNumber() const { @@ -68,5 +68,5 @@ unsigned InvadersGrid::randomValidCol() const { ++validIndex; } } - throw runtime_error("SHOULD NOT HAPPEN"); + throw runtime_error("SHOULD NOT HAPPEN : see randomValidCol()"); } \ No newline at end of file diff --git a/src/mySprite.cpp b/src/mySprite.cpp index bc548ca..c15c1c2 100644 --- a/src/mySprite.cpp +++ b/src/mySprite.cpp @@ -1,16 +1,16 @@ #include "utils.h" #include "mySprite.h" -future MySprite::asyncLoad(const string& fname){ +Task MySprite::asyncLoad(const string& fname){ DEBUG_MSG("Load file " << fname) return std::async(std::launch::async, [fname, this]() -> void { - ptr = std::make_unique(fname); + sp = std::make_unique(fname); }); } void MySprite::mirror(MySprite& msp) { - const vector& inPixels = msp.ptr->getPixelData(); - unsigned rowSize = msp.ptr->getRowSize(); + const vector& inPixels = msp.sp->getPixelData(); + unsigned rowSize = msp.sp->getRowSize(); vector outPixels; // we reserve size so the vector doesn't dynamically grows @@ -23,5 +23,5 @@ void MySprite::mirror(MySprite& msp) { outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]); } } - ptr = std::make_unique(outPixels, rowSize); + sp = std::make_unique(outPixels, rowSize); } diff --git a/src/pixelManager/drawEntities.cpp b/src/pixelManager/drawEntities.cpp index 5facd3c..f4ce3b2 100644 --- a/src/pixelManager/drawEntities.cpp +++ b/src/pixelManager/drawEntities.cpp @@ -79,8 +79,8 @@ void PixelManager::drawTorpedo(const Position& baseVector, unsigned width, const void PixelManager::drawSprite(const MySprite& msp, const Position& pos) const { // The sprite is associated with a Vec2D for whatever reason, so yeah, we modify it each time we draw it - msp.ptr->setPosition(pos); - msp.ptr->draw(window); + msp.sp->setPosition(pos); + msp.sp->draw(window); } void PixelManager::drawGodBench(int y) const { diff --git a/src/pixelManager/drawMenus.cpp b/src/pixelManager/drawMenus.cpp index 9edbe46..5c142c0 100644 --- a/src/pixelManager/drawMenus.cpp +++ b/src/pixelManager/drawMenus.cpp @@ -25,7 +25,7 @@ void PixelManager::displayButton(const Position& baseVector, const string& text, window << nsGui::Text(baseVector+Position(10,22), text, color); } -void PixelManager::displayMenu(const Position& pos, Menu& currentMenu){ +void PixelManager::drawMenu(const Position& pos, Menu& currentMenu){ startFrame(); drawSprite(menuBackground, Position(0, 0)); drawSprite(logo,Position(100,50)); @@ -36,7 +36,7 @@ void PixelManager::displayMenu(const Position& pos, Menu& currentMenu){ unsigned margin = 0; unsigned cpt = 0; for(string& value : currentMenu.entries ){ - displayButton(Position(0,0+margin)+ pos, value, (currentMenu.currentValue == cpt) ? currentMenu.selectedColor : currentMenu.unSelectedColor ); + displayButton(Position(0,0+margin)+ pos, value, (currentMenu.selectedEntry == cpt) ? currentMenu.selectedColor : currentMenu.unSelectedColor ); ++cpt; margin += 50; } @@ -44,7 +44,7 @@ void PixelManager::displayMenu(const Position& pos, Menu& currentMenu){ } -void PixelManager::displayMenu(const Position& pos, Menu& currentMenu, const vector& rankings, const WinValue& winner){ +void PixelManager::drawMenu(const Position& pos, Menu& currentMenu, const vector& rankings, const WinValue& winner){ startFrame(); drawSprite(menuBackground, Position(0, 0)); drawSprite(logo,Position(100,50)); @@ -55,7 +55,7 @@ void PixelManager::displayMenu(const Position& pos, Menu& currentMenu, const vec else if (winner == WinValue::INVADERS) drawText(Position(0-55,0-20)+ pos,"The invaders have reached earth",nsGraphics::KWhite); else drawText(Position(0-55,0-20)+ pos,"God won, as His power are infinite",nsGraphics::KWhite); for(string& value : currentMenu.entries ){ - displayButton(Position(0,0+margin)+ pos, value, (currentMenu.currentValue == cpt) ? currentMenu.selectedColor : currentMenu.unSelectedColor ); + displayButton(Position(0,0+margin)+ pos, value, (currentMenu.selectedEntry == cpt) ? currentMenu.selectedColor : currentMenu.unSelectedColor ); ++cpt; margin += 50; } @@ -71,26 +71,26 @@ void PixelManager::displayMenu(const Position& pos, Menu& currentMenu, const vec PlayMode PixelManager::showInitialMenu(){ vector entries {"single player","multi player (local)","exit"}; - Menu initial {entries,0,nsGraphics::KRed,nsGraphics::KWhite}; + Menu initialMenu {entries, 0, nsGraphics::KRed, nsGraphics::KWhite}; unsigned xOffset = getScreenHeight() / 2 ; unsigned yOffset = getScreenWidth() / 2 - 90; chrono::milliseconds waitTime = chrono::milliseconds(100); while(window.isOpen()){ - displayMenu(Position(yOffset,xOffset),initial); + drawMenu(Position(yOffset, xOffset), initialMenu); // go down if (window.isPressed({'s', false})){ - ++initial.currentValue; - if (initial.currentValue > initial.entries.size()-1) initial.currentValue = 0; + ++initialMenu.selectedEntry; + if (initialMenu.selectedEntry > initialMenu.entries.size() - 1) initialMenu.selectedEntry = 0; this_thread::sleep_for(waitTime); } // go up if (window.isPressed({'z', false})){ - if (initial.currentValue == 0) initial.currentValue = initial.entries.size()-1; - else --initial.currentValue; + if (initialMenu.selectedEntry == 0) initialMenu.selectedEntry = initialMenu.entries.size() - 1; + else --initialMenu.selectedEntry; this_thread::sleep_for(waitTime); }// select option else if (window.isPressed({13, false})){ - switch(initial.currentValue){ + switch(initialMenu.selectedEntry){ case 0: return PlayMode::SINGLE; case 1: @@ -160,21 +160,21 @@ bool PixelManager::showDeathMenu(const vector& rankings,const WinValu unsigned yOffset = getScreenWidth() / 2 - 90; chrono::milliseconds waitTime = chrono::milliseconds(100); while(window.isOpen()){ - displayMenu(Position(yOffset,xOffset),death,rankings,winner); + drawMenu(Position(yOffset, xOffset), death, rankings, winner); // go down if (window.isPressed({'s', false})){ - ++death.currentValue; - if (death.currentValue > death.entries.size()-1) death.currentValue = 0; + ++death.selectedEntry; + if (death.selectedEntry > death.entries.size() - 1) death.selectedEntry = 0; this_thread::sleep_for(waitTime); } // go up if (window.isPressed({'z', false})){ - if (death.currentValue == 0) death.currentValue = death.entries.size()-1; - else --death.currentValue; + if (death.selectedEntry == 0) death.selectedEntry = death.entries.size() - 1; + else --death.selectedEntry; this_thread::sleep_for(waitTime); }// select option else if (window.isPressed({13, false})){ - switch(death.currentValue){ + switch(death.selectedEntry){ case 0:{ return true; } diff --git a/src/pixelManager/pixelManager.cpp b/src/pixelManager/pixelManager.cpp index fe7addf..e005f5d 100644 --- a/src/pixelManager/pixelManager.cpp +++ b/src/pixelManager/pixelManager.cpp @@ -13,7 +13,6 @@ void PixelManager::startFrame() const { } void PixelManager::endFrame() const { - for(Task& t : drawTasks)t.wait(); window.finishFrame(); } @@ -23,20 +22,4 @@ unsigned PixelManager::getScreenHeight() const { unsigned PixelManager::getScreenWidth() const { return window.getWindowSize().getX(); -} - -vector -PixelManager::mirrorData(const vector& inPixels, unsigned rowSize) { - vector outPixels; - // we reserve size so the vector doesn't dynamically grows - outPixels.reserve(inPixels.size()); - //for each line of pixel - for(unsigned rowOffset=0; rowOffset < inPixels.size(); rowOffset+=rowSize){ - // for each pixel of that line - for(unsigned j=0;j