modified documentation

This commit is contained in:
Thomas 2022-01-11 10:17:54 +01:00
parent 7919f8f722
commit a01ea867cb
No known key found for this signature in database
GPG Key ID: E538821A6CDFDAD7
18 changed files with 137 additions and 122 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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<InvadersColumn>{
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;
};

View File

@ -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

View File

@ -2,14 +2,31 @@
#define GUARD_MYSPRITE_H
#include <future>
#include <optional>
#include "mingl/gui/sprite.h"
#include "pixelManager/pixelManager.h"
using namespace std;
class MySprite{
public:
unique_ptr<nsGui::Sprite> ptr;
future<void> 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<nsGui::Sprite> 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);
};

View File

@ -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<void> Task;
class PixelManager{
public:
MinGL& window;
mutable vector<Task> 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<ScoreLink>& 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<RGBAcolor> mirrorData(const vector<RGBAcolor>& 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<RGBAcolor> mirrorData(const vector<RGBAcolor>& 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<ScoreLink>& rankings, const WinValue& winner);
};

View File

@ -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();
};

View File

@ -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

View File

@ -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);

View File

@ -10,7 +10,6 @@
*/
#include <chrono>
#include <memory>
#include <thread>
#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<void>& 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() {

View File

@ -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{

View File

@ -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: {

View File

@ -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()");
}

View File

@ -1,16 +1,16 @@
#include "utils.h"
#include "mySprite.h"
future<void> 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<nsGui::Sprite>(fname);
sp = std::make_unique<nsGui::Sprite>(fname);
});
}
void MySprite::mirror(MySprite& msp) {
const vector<RGBAcolor>& inPixels = msp.ptr->getPixelData();
unsigned rowSize = msp.ptr->getRowSize();
const vector<RGBAcolor>& inPixels = msp.sp->getPixelData();
unsigned rowSize = msp.sp->getRowSize();
vector<RGBAcolor> 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<nsGui::Sprite>(outPixels, rowSize);
sp = std::make_unique<nsGui::Sprite>(outPixels, rowSize);
}

View File

@ -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 {

View File

@ -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<ScoreLink>& rankings, const WinValue& winner){
void PixelManager::drawMenu(const Position& pos, Menu& currentMenu, const vector<ScoreLink>& 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<string> 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<ScoreLink>& 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;
}

View File

@ -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<RGBAcolor>
PixelManager::mirrorData(const vector<nsGraphics::RGBAcolor>& inPixels, unsigned rowSize) {
vector<RGBAcolor> 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<rowSize;++j) {
// push back the pixel opposed to this one (still in the same line)
outPixels.push_back(inPixels[rowOffset + rowSize - j - 1]);
}
}
return std::move(outPixels);
}