push
This commit is contained in:
parent
15dc67c348
commit
a81ec496a6
@ -1,10 +1,5 @@
|
|||||||
Questions que je (Thomas Rubini) voudrais poser
|
Questions que je (Thomas Rubini) voudrais poser
|
||||||
|
|
||||||
- Est-ce que vous préférez l'implémentation orienté objet ou orienté macro pour lire la config ? Pourquoi ?
|
|
||||||
- Est-ce que traduire les chars A B et C (identifiants des types d'aliens) tirés de la config en valeurs d'enum est une bonne chose, pas important, ou contre-productif ?
|
|
||||||
- Est-ce que mon implémentation du réseau est bonne ?
|
|
||||||
- Est-ce mon implémentation du multithreading est bonne ?
|
|
||||||
|
|
||||||
- Est-on obligé d'utiliser size_t quand on sait que la taille du vecteur ne dépassera jamais concrètement la taille d'un int (cas précis : taille de 100 maximum, est-on obligé d'utiliser size_t de 8 bytes ?)
|
- Est-on obligé d'utiliser size_t quand on sait que la taille du vecteur ne dépassera jamais concrètement la taille d'un int (cas précis : taille de 100 maximum, est-on obligé d'utiliser size_t de 8 bytes ?)
|
||||||
* Non
|
* Non
|
||||||
- Que pensez-vous de la sémantique de déplacement, plutot que la référence constante ?
|
- Que pensez-vous de la sémantique de déplacement, plutot que la référence constante ?
|
||||||
|
1
README
1
README
@ -4,6 +4,7 @@ PascalCase pour les noms de classes/structures
|
|||||||
Nommage en anglais
|
Nommage en anglais
|
||||||
Pas de fonctions de +100 lignes
|
Pas de fonctions de +100 lignes
|
||||||
Les guards sont de cette forme : GUARD_<filename>_H
|
Les guards sont de cette forme : GUARD_<filename>_H
|
||||||
|
Lors d'un include, on utilise <> pour la STD, "" pour nos fichiers/MinGL
|
||||||
|
|
||||||
Concernant les const :
|
Concernant les const :
|
||||||
Afin de limiter l'utilisation du mot const (pour garder une certaine lisibilité du code), les cas suivants n'ont pas besoin d'etre déclarés comme const :
|
Afin de limiter l'utilisation du mot const (pour garder une certaine lisibilité du code), les cas suivants n'ont pas besoin d'etre déclarés comme const :
|
||||||
|
50
headers/configManagement.h
Normal file
50
headers/configManagement.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*!
|
||||||
|
*
|
||||||
|
* @file configManagement.h
|
||||||
|
* @author RUBINI Thomas
|
||||||
|
* @author SIMAILA Djalim
|
||||||
|
* @date January 2022
|
||||||
|
* @version 1.0
|
||||||
|
* @brief config parser
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SPACE_CONFIGMANAGEMENT_H
|
||||||
|
#define SPACE_CONFIGMANAGEMENT_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This header will only be imported once, but Djalim told me he would hurt me
|
||||||
|
* if I didn't move it into his own header file instead of the cpp file
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ConfigBuilder{
|
||||||
|
public:
|
||||||
|
ConfigData collectedData;
|
||||||
|
void parseFile(const string& fname);
|
||||||
|
void readConfig();
|
||||||
|
void dumpInternalValues() const;
|
||||||
|
private:
|
||||||
|
map<string, string> internalValues;
|
||||||
|
|
||||||
|
const string& getString(const configKey& key, const string& def) const;
|
||||||
|
const string& getString(const configKey& key) const;
|
||||||
|
char getChar(const configKey& key, char def) const;
|
||||||
|
char getChar(const configKey& key) const;
|
||||||
|
int getInt(const configKey& key) const;
|
||||||
|
int getInt(const configKey& key, int def) const;
|
||||||
|
void getColor(const configKey& key, nsGraphics::RGBAcolor& color, nsGraphics::RGBAcolor& def) const;
|
||||||
|
void getColor(const configKey& key, nsGraphics::RGBAcolor& color) const;
|
||||||
|
void getList(const configKey& key, vector<string>& vec) const;
|
||||||
|
|
||||||
|
void readGrid(const configKey& baseKey);
|
||||||
|
void readPlayer(const configKey& baseKey, PlayerDef&);
|
||||||
|
void readInvaderType(const configKey& baseKey, InvaderTypeDef&);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ConfigBuilder::dumpInternalValues() const {
|
||||||
|
for(const auto& ite : internalValues){
|
||||||
|
cerr << ite.first << " -> " << ite.second << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
25
headers/errors.h
Normal file
25
headers/errors.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*!
|
||||||
|
*
|
||||||
|
* @file configData.h
|
||||||
|
* @author RUBINI Thomas
|
||||||
|
* @date January 2022
|
||||||
|
* @version 1.0
|
||||||
|
* @brief Configuration file data storage
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GUARD_ERRORS_H
|
||||||
|
#define GUARD_ERRORS_H
|
||||||
|
|
||||||
|
#include<string>
|
||||||
|
#include<stdexcept>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// We keep the same case
|
||||||
|
class config_error : public runtime_error {
|
||||||
|
public:
|
||||||
|
explicit config_error(const string& msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -202,37 +202,37 @@ private:
|
|||||||
void moveTorpedos();
|
void moveTorpedos();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief checks if a missile collides with a player
|
||||||
* @return
|
* @fn checkMissilesAndPlayers();
|
||||||
* @fn
|
|
||||||
*/
|
*/
|
||||||
bool checkMissilesAndPlayers();
|
void checkMissilesAndPlayers();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief check if a torpedo collides with an invader
|
||||||
* @return
|
* @return true if there is a collision, false elsewise
|
||||||
* @fn
|
* @fn bool checkTorpedosAndInvaders();
|
||||||
*/
|
*/
|
||||||
bool checkTorpedosAndInvaders();
|
bool checkTorpedosAndInvaders();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief check if the invaders have reach the players
|
||||||
* @return
|
* @return true if they have reach the player, false elsewise
|
||||||
* @fn
|
* @fn bool invadersTouchPlayer() const;
|
||||||
*/
|
*/
|
||||||
bool invadersTouchPlayer() const;
|
bool invadersTouchPlayer() const;
|
||||||
|
|
||||||
// god things
|
// god things
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
* @brief change god's state to awake
|
||||||
|
* @fn void awakeGod();
|
||||||
*/
|
*/
|
||||||
void awakeGod();
|
void awakeGod();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief make god behave
|
||||||
* @return
|
* @return true if theres no invader left, false elsewise
|
||||||
* @fn
|
* @fn bool manageGod();
|
||||||
*/
|
*/
|
||||||
bool manageGod();
|
bool manageGod();
|
||||||
|
|
||||||
@ -240,28 +240,37 @@ 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 API, costs nothing to us
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
* @brief constructor for the game class
|
||||||
|
* @fn Game();
|
||||||
*/
|
*/
|
||||||
Game();
|
Game();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
* @brief manages and changes the states of the game
|
||||||
|
* @fn void managedGames();
|
||||||
*/
|
*/
|
||||||
void managedGames();
|
void managedGames();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief enter the main gameplay game loop
|
||||||
* @return
|
* @return the value of the winners can be the players, the invaders or god
|
||||||
* @fn
|
* @fn WinValue enterGameLoop();
|
||||||
*/
|
*/
|
||||||
WinValue enterGameLoop();
|
WinValue enterGameLoop();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief reload the configuration file for a new game
|
||||||
* @return
|
* @return false if an error occured, true elsewise
|
||||||
* @fn
|
* @fn bool reloadConfig();
|
||||||
*/
|
*/
|
||||||
bool reloadConfig();
|
bool reloadConfig();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief tells if all players are dead
|
||||||
|
* @return true if all player are dead, false otherwise
|
||||||
|
* @fn bool arePlayersDead();
|
||||||
|
*/
|
||||||
|
bool arePlayersDead();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -6,6 +6,9 @@
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @brief Special entity known as "God"
|
* @brief Special entity known as "God"
|
||||||
*
|
*
|
||||||
|
* Well, i (Djalim) discovered that Thomas put God in the game
|
||||||
|
* I didnt think it was a good idea but no man can stop Thomas
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GUARD_GOD_H
|
#ifndef GUARD_GOD_H
|
||||||
@ -15,7 +18,7 @@
|
|||||||
#include "invadersGrid.h"
|
#include "invadersGrid.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief list of all known god states
|
||||||
*/
|
*/
|
||||||
enum class GodState{
|
enum class GodState{
|
||||||
NONE,
|
NONE,
|
||||||
@ -40,18 +43,18 @@ enum class GodState{
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @class God
|
* @class God
|
||||||
* @brief
|
* @brief stores all God's data
|
||||||
*/
|
*/
|
||||||
class God{
|
class God{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief god's current state
|
||||||
*/
|
*/
|
||||||
GodState state;
|
GodState state;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief manage all sorts of things, gods secrets remains unknown
|
||||||
*/
|
*/
|
||||||
unsigned counter;
|
unsigned counter;
|
||||||
|
|
||||||
@ -59,34 +62,34 @@ public:
|
|||||||
// we do not use a Position because it is used for pixel X and Y
|
// we do not use a Position because it is used for pixel X and Y
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief x pixel coordinate of the invader thrown by the hand of god
|
||||||
*/
|
*/
|
||||||
unsigned thrownInvPosX;
|
unsigned thrownInvPosX;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief y pixel coordinate of the invader thrown by the hand of god
|
||||||
*/
|
*/
|
||||||
unsigned thrownInvPosY;
|
unsigned thrownInvPosY;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief type of the invader thrown by the hand of god
|
||||||
*/
|
*/
|
||||||
InvaderType thrownInvType;
|
InvaderType thrownInvType;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief direction of the thrown invader movement
|
||||||
*/
|
*/
|
||||||
Position thrownVector;
|
Position thrownVector;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief position of a point for bezier's curve
|
||||||
*/
|
*/
|
||||||
Position thrownTransition;
|
Position thrownTransition;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief
|
* @brief give initial the pixel coordinates of god's right hand
|
||||||
* @param[in] screenWidth :
|
* @param[in] screenWidth : width of the screen in pixel
|
||||||
* @return
|
* @return pixel coordinates of the hand
|
||||||
* @fn Position getRightHandPos(unsigned screenWidth) const;
|
* @fn Position getRightHandPos(unsigned screenWidth) const;
|
||||||
*/
|
*/
|
||||||
Position getRightHandPos(unsigned screenWidth) const;
|
Position getRightHandPos(unsigned screenWidth) const;
|
||||||
|
@ -53,7 +53,7 @@ public:
|
|||||||
* @return
|
* @return
|
||||||
* @fn
|
* @fn
|
||||||
*/
|
*/
|
||||||
unsigned randomValid() const;
|
unsigned randomValidInv() const;
|
||||||
}; // class InvadersColumn
|
}; // class InvadersColumn
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,17 +18,62 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @struct ScoreLink
|
||||||
|
* @brief Makes a link between a player username and their score
|
||||||
|
*/
|
||||||
struct ScoreLink{
|
struct ScoreLink{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief player username
|
||||||
|
*/
|
||||||
string name;
|
string name;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief player score
|
||||||
|
*/
|
||||||
unsigned score;
|
unsigned score;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief constructor of the struct
|
||||||
|
* @param[in] name : player username
|
||||||
|
* @param[in] score : player score
|
||||||
|
* @fn ScoreLink(string name, unsigned score);
|
||||||
|
*/
|
||||||
ScoreLink(string name, unsigned score);
|
ScoreLink(string name, unsigned score);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @class ScoresManager
|
||||||
|
* @brief manage the score in the game and inside the score file
|
||||||
|
*/
|
||||||
class ScoresManager {
|
class ScoresManager {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief list of pairs of player names and their score
|
||||||
|
*/
|
||||||
vector<ScoreLink> scores;
|
vector<ScoreLink> scores;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief add player name and their score in the list of scores
|
||||||
|
* @param[in] name : player name
|
||||||
|
* @param[in] score : player score
|
||||||
|
* @fn void inputScore(string name, unsigned score);
|
||||||
|
*/
|
||||||
void inputScore(string name, unsigned score);
|
void inputScore(string name, unsigned score);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief read the score file and put all of its data inside the list of score
|
||||||
|
* @fn void readFile();
|
||||||
|
*/
|
||||||
void readFile();
|
void readFile();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief write the score list into the score file
|
||||||
|
* @fn void writeFile() const;
|
||||||
|
*/
|
||||||
void writeFile() const;
|
void writeFile() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,3 +1,13 @@
|
|||||||
|
/*!
|
||||||
|
*
|
||||||
|
* @file utils.h
|
||||||
|
* @author RUBINI Thomas
|
||||||
|
* @date January 2022
|
||||||
|
* @version 1.0
|
||||||
|
* @brief utilies for the game
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef GUARD_UTILS_H
|
#ifndef GUARD_UTILS_H
|
||||||
#define GUARD_UTILS_H
|
#define GUARD_UTILS_H
|
||||||
|
|
||||||
@ -28,11 +38,14 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using nsGraphics::RGBAcolor;
|
using nsGraphics::RGBAcolor;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief list of win values
|
||||||
|
*/
|
||||||
enum class WinValue{
|
enum class WinValue{
|
||||||
NOBODY, // should never be used
|
NOBODY, // should never be used
|
||||||
PLAYERS,
|
PLAYERS,
|
||||||
INVADERS,
|
INVADERS,
|
||||||
|
GOD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -42,9 +55,25 @@ typedef unsigned playerID;
|
|||||||
#define PLAYER2 1
|
#define PLAYER2 1
|
||||||
|
|
||||||
// didn't want to use Position because of the semantic with x and y
|
// 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
|
||||||
|
* @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 */
|
||||||
bool areLinesColliding(unsigned start1, unsigned end1, unsigned start2, unsigned end2);
|
bool areLinesColliding(unsigned start1, unsigned end1, unsigned start2, unsigned end2);
|
||||||
|
|
||||||
// change draw position for a specified size (keeps the same center)
|
// change draw position for a specified size (keeps the same center)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief change the size of a Position object
|
||||||
|
* @param[in,out] pos : Position object
|
||||||
|
* @param[in] sizeFrom: current size of the objet
|
||||||
|
* @param[in] sizeTo : new size of the object
|
||||||
|
*/
|
||||||
void applyTransformation(Position& pos, unsigned sizeFrom, unsigned sizeTo);
|
void applyTransformation(Position& pos, unsigned sizeFrom, unsigned sizeTo);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -11,33 +11,9 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
#include "configManagement.h"
|
||||||
|
#include "errors.h"
|
||||||
|
|
||||||
// you will MOVE THIS OUT OF THIS FILE
|
|
||||||
|
|
||||||
class ConfigBuilder{
|
|
||||||
public:
|
|
||||||
ConfigData collectedData;
|
|
||||||
void parseFile(const string& fname);
|
|
||||||
void readConfig();
|
|
||||||
void dumpInternalValues() const;
|
|
||||||
private:
|
|
||||||
map<string, string> internalValues;
|
|
||||||
const string& getString(const configKey& key) const;
|
|
||||||
char getChar(const configKey& key) const;
|
|
||||||
int getInt(const configKey& key) const;
|
|
||||||
void getColor(const configKey& key, nsGraphics::RGBAcolor&) const;
|
|
||||||
void getList(const configKey& key, vector<string>&) const;
|
|
||||||
|
|
||||||
void readGrid(const configKey& baseKey);
|
|
||||||
void readPlayer(const configKey& baseKey, PlayerDef&);
|
|
||||||
void readInvaderType(const configKey& baseKey, InvaderTypeDef&);
|
|
||||||
};
|
|
||||||
|
|
||||||
void ConfigBuilder::dumpInternalValues() const {
|
|
||||||
for(const auto& ite : internalValues){
|
|
||||||
cerr << ite.first << " -> " << ite.second << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void trimSpaces(string& str){
|
void trimSpaces(string& str){
|
||||||
str.erase(0, str.find_first_not_of(' '));
|
str.erase(0, str.find_first_not_of(' '));
|
||||||
@ -56,12 +32,12 @@ void sanitizeValue(string& val) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* WARNING : This implementation of YAML is not meant to be complete, but to work with our specific needs
|
* WARNING : This implementation of YAML is not meant to be complete, but to work with our specific needs
|
||||||
* It also can't detect and report errors in a non YAML-compliant file
|
* It also can't detect and report errors in a non-YAML-compliant file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ConfigBuilder::parseFile(const string& fname) {
|
void ConfigBuilder::parseFile(const string& fname) {
|
||||||
ifstream file(fname);
|
ifstream file(fname);
|
||||||
if(!file.is_open())throw runtime_error("Error while opening config.yml. Check file location ?");
|
if(!file.is_open())throw config_error("Error while opening config.yml. Check file location ?");
|
||||||
|
|
||||||
vector<string> keyParts;
|
vector<string> keyParts;
|
||||||
unsigned listIndex;
|
unsigned listIndex;
|
||||||
@ -91,7 +67,7 @@ void ConfigBuilder::parseFile(const string& fname) {
|
|||||||
|
|
||||||
}else{
|
}else{
|
||||||
match = line.find(':');
|
match = line.find(':');
|
||||||
if (match == string::npos)throw runtime_error("Invalid line : " + line);
|
if (match == string::npos)throw config_error("Invalid line : " + line);
|
||||||
string key = line.substr(0, match);
|
string key = line.substr(0, match);
|
||||||
string value = line.substr(match + 1);
|
string value = line.substr(match + 1);
|
||||||
trimSpaces(key);
|
trimSpaces(key);
|
||||||
@ -148,7 +124,7 @@ void ConfigBuilder::readGrid(const configKey& baseKey) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:{
|
default:{
|
||||||
throw runtime_error("Invalid invader ID in grid definition : "+ to_string(s[i]));
|
throw config_error("Invalid invader ID in grid definition : "+ to_string(s[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,26 +188,60 @@ void ConfigBuilder::readConfig() {
|
|||||||
getColor("projectiles.torpedos.color", collectedData.torpedosColor);
|
getColor("projectiles.torpedos.color", collectedData.torpedosColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfigBuilder::getInt(const configKey& key) const {
|
const string& ConfigBuilder::getString(const configKey& key, const string& def) const {
|
||||||
return stoi(getString(key));
|
try{
|
||||||
|
return getString(key);
|
||||||
|
}catch(config_error& e){
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ConfigBuilder::getChar(const configKey& key) const {
|
|
||||||
return getString(key)[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const string& ConfigBuilder::getString(const configKey& key) const {
|
const string& ConfigBuilder::getString(const configKey& key) const {
|
||||||
if(internalValues.contains(key)){
|
if(internalValues.contains(key)){
|
||||||
return internalValues.at(key);
|
return internalValues.at(key);
|
||||||
}else{
|
}else{
|
||||||
throw runtime_error("Non-existent key requested : "+key);
|
throw config_error("Non-existent key requested : "+key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConfigBuilder::getInt(const configKey& key) const {
|
||||||
|
try{
|
||||||
|
return stoi(getString(key));
|
||||||
|
}catch(invalid_argument& e){
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
throw config_error("Invalid int data for key "+key+" : |"+getString(key)+"|");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConfigBuilder::getInt(const configKey& key, int def) const {
|
||||||
|
try{
|
||||||
|
return getInt(key);
|
||||||
|
}catch(config_error& e){
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char ConfigBuilder::getChar(const configKey& key) const {
|
||||||
|
string s = getString(key);
|
||||||
|
if(s.size()!=1)throw config_error("Invalid char data for key "+key+" : |"+s+"|");
|
||||||
|
return s[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
char ConfigBuilder::getChar(const configKey& key, char def) const {
|
||||||
|
try{
|
||||||
|
return getChar(key);
|
||||||
|
}catch(config_error& e){
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigBuilder::getList(const configKey& key, vector<string>& toPopulate) const {
|
void ConfigBuilder::getList(const configKey& key, vector<string>& toPopulate) const {
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
string fullKey = key+".0";
|
string fullKey = key+".0";
|
||||||
if(!internalValues.contains(fullKey))throw runtime_error("Non-existent list key requested : "+key);
|
if(!internalValues.contains(fullKey))throw config_error("Non-existent list key requested : "+key);
|
||||||
|
|
||||||
do{
|
do{
|
||||||
toPopulate.push_back(internalValues.at(fullKey));
|
toPopulate.push_back(internalValues.at(fullKey));
|
||||||
@ -259,14 +269,10 @@ void ConfigBuilder::getColor(const configKey& key, nsGraphics::RGBAcolor& color)
|
|||||||
else if (colorStr == "purple")color = nsGraphics::KPurple;
|
else if (colorStr == "purple")color = nsGraphics::KPurple;
|
||||||
else if (colorStr == "teal")color = nsGraphics::KTeal;
|
else if (colorStr == "teal")color = nsGraphics::KTeal;
|
||||||
else if (colorStr == "navy")color = nsGraphics::KNavy;
|
else if (colorStr == "navy")color = nsGraphics::KNavy;
|
||||||
else throw runtime_error("Invalid color string : "+colorStr);
|
else throw config_error("Invalid color string : "+colorStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return false if there was an error
|
|
||||||
*/
|
|
||||||
bool Game::reloadConfig() {
|
bool Game::reloadConfig() {
|
||||||
map<string, string> strValues;
|
map<string, string> strValues;
|
||||||
ConfigBuilder builder;
|
ConfigBuilder builder;
|
||||||
@ -275,7 +281,7 @@ bool Game::reloadConfig() {
|
|||||||
builder.parseFile("config.yml");
|
builder.parseFile("config.yml");
|
||||||
parsed = true;
|
parsed = true;
|
||||||
builder.readConfig();
|
builder.readConfig();
|
||||||
}catch(runtime_error& e){
|
}catch(config_error& e){
|
||||||
if(parsed)cerr << "An error occured while reading the configuration :" << endl;
|
if(parsed)cerr << "An error occured while reading the configuration :" << endl;
|
||||||
else cerr << "An error occured while parsing the configuration :" << endl;
|
else cerr << "An error occured while parsing the configuration :" << endl;
|
||||||
cerr << e.what() << endl;
|
cerr << e.what() << endl;
|
||||||
|
5
src/errors.cpp
Normal file
5
src/errors.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "errors.h"
|
||||||
|
|
||||||
|
config_error::config_error(const string& msg) : runtime_error(msg) {
|
||||||
|
|
||||||
|
}
|
@ -60,7 +60,6 @@ void Game::managedGames() {
|
|||||||
// we assume the game has been played before, and so we need to clean used members
|
// we assume the game has been played before, and so we need to clean used members
|
||||||
void Game::initGame(){
|
void Game::initGame(){
|
||||||
grid = confData.grid; // will copy the grid
|
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)
|
// 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();
|
players.clear();
|
||||||
@ -114,16 +113,19 @@ WinValue Game::enterGameLoop(){ // returns when game is finished
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
manageGod();
|
if(manageGod())return WinValue::PLAYERS;
|
||||||
|
if(arePlayersDead())return WinValue::GOD;
|
||||||
|
|
||||||
moveMissiles();
|
moveMissiles();
|
||||||
remCollidingProjectiles();
|
remCollidingProjectiles();
|
||||||
moveTorpedos();
|
moveTorpedos();
|
||||||
remCollidingProjectiles();
|
remCollidingProjectiles();
|
||||||
|
|
||||||
if(checkMissilesAndPlayers())return WinValue::INVADERS;
|
checkMissilesAndPlayers();
|
||||||
if(checkTorpedosAndInvaders())return WinValue::PLAYERS;
|
if(checkTorpedosAndInvaders())return WinValue::PLAYERS;
|
||||||
|
|
||||||
|
if(arePlayersDead())return WinValue::INVADERS;
|
||||||
|
|
||||||
displayAll(fps);
|
displayAll(fps);
|
||||||
|
|
||||||
pm.endFrame();
|
pm.endFrame();
|
||||||
@ -146,3 +148,10 @@ WinValue Game::enterGameLoop(){ // returns when game is finished
|
|||||||
Position Game::invIndexToPos(unsigned x, unsigned y) const {
|
Position Game::invIndexToPos(unsigned x, unsigned y) const {
|
||||||
return basePos+Position(INV_GET_POS(x), INV_GET_POS(y));
|
return basePos+Position(INV_GET_POS(x), INV_GET_POS(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Game::arePlayersDead() {
|
||||||
|
for(Player& p : players){
|
||||||
|
if(!p.isEliminated())return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -48,10 +48,6 @@ void Game::managePlayers(){
|
|||||||
for(unsigned i=0;i<players.size();++i)manageOnePlayer(i);
|
for(unsigned i=0;i<players.size();++i)manageOnePlayer(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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
|
|
||||||
*/
|
|
||||||
bool Game::manageInvaders(){
|
bool Game::manageInvaders(){
|
||||||
if(grid.empty())return false; // If there are no more invaders we don't need to manage them
|
if(grid.empty())return false; // If there are no more invaders we don't need to manage them
|
||||||
// shoot
|
// shoot
|
||||||
@ -94,10 +90,6 @@ bool Game::manageInvaders(){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** makes projectiles move, and manage collisions between them and everything
|
|
||||||
*
|
|
||||||
* @return 1 if the invaders are all dead, 2 if the player is dead, else 0
|
|
||||||
*/
|
|
||||||
void Game::remCollidingProjectiles(){
|
void Game::remCollidingProjectiles(){
|
||||||
|
|
||||||
auto miss = missiles.begin();
|
auto miss = missiles.begin();
|
||||||
@ -150,7 +142,7 @@ void Game::moveTorpedos() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Game::checkMissilesAndPlayers() {
|
void Game::checkMissilesAndPlayers() {
|
||||||
auto miss_ite = missiles.begin();
|
auto miss_ite = missiles.begin();
|
||||||
while(miss_ite!=missiles.end()){
|
while(miss_ite!=missiles.end()){
|
||||||
bool wasColliding = false;
|
bool wasColliding = false;
|
||||||
@ -171,7 +163,6 @@ bool Game::checkMissilesAndPlayers() {
|
|||||||
if(wasColliding)missiles.erase(miss_ite);
|
if(wasColliding)missiles.erase(miss_ite);
|
||||||
else ++miss_ite;
|
else ++miss_ite;
|
||||||
}
|
}
|
||||||
return false; // TODO manage death animation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Game::checkTorpedosAndInvaders() {
|
bool Game::checkTorpedosAndInvaders() {
|
||||||
@ -202,7 +193,7 @@ bool Game::checkTorpedosAndInvaders() {
|
|||||||
|
|
||||||
grid[i][alienIndex] = InvaderType::NONE;
|
grid[i][alienIndex] = InvaderType::NONE;
|
||||||
|
|
||||||
if(updateColumns()) return true;
|
if(!areThereInvadersLeft()) return true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ void Game::awakeGod() {
|
|||||||
/**
|
/**
|
||||||
* @returns true if we can finish the game
|
* @returns true if we can finish the game
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
bool Game::manageGod() {
|
bool Game::manageGod() {
|
||||||
switch (god.state) {
|
switch (god.state) {
|
||||||
case GodState::NONE: {
|
case GodState::NONE: {
|
||||||
@ -35,19 +40,18 @@ bool Game::manageGod() {
|
|||||||
++god.counter;
|
++god.counter;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (areThereInvadersLeft()) {
|
|
||||||
// init throw
|
// init throw
|
||||||
god.counter = 0;
|
god.counter = 0;
|
||||||
god.state = GodState::RETRIEVE1;
|
god.state = GodState::RETRIEVE1;
|
||||||
god.thrownInvPosX = grid.randomValidCol();
|
god.thrownInvPosX = grid.randomValidCol();
|
||||||
god.thrownInvPosY = grid[god.thrownInvPosX].randomValid();
|
god.thrownInvPosY = grid[god.thrownInvPosX].randomValidInv();
|
||||||
god.thrownInvType = InvaderType::NONE;
|
god.thrownInvType = InvaderType::NONE;
|
||||||
|
|
||||||
god.thrownTransition.setX(pm.getScreenWidth() - GOD_HAND_DISTANCE - GOD_HAND_SIZE);
|
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_POS(god.thrownInvPosY));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case GodState::RETRIEVE1: {
|
case GodState::RETRIEVE1: {
|
||||||
if (god.counter < 100) {
|
if (god.counter < 100) {
|
||||||
god.counter += 2;
|
god.counter += 2;
|
||||||
@ -132,14 +136,19 @@ bool Game::manageGod() {
|
|||||||
* we do not need to reset other members, they'll be treated as non-initialized
|
* we do not need to reset other members, they'll be treated as non-initialized
|
||||||
* When we cycle back between states
|
* When we cycle back between states
|
||||||
*/
|
*/
|
||||||
return false;
|
|
||||||
|
|
||||||
|
// We could have optimized that, but it's more readable like this and hopefully the compiler will optimize it itself
|
||||||
|
if(areThereInvadersLeft())return false;
|
||||||
|
else return true;
|
||||||
}
|
}
|
||||||
case GodState::YOLO: {
|
case GodState::YOLO: {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
throw runtime_error("SHOULD NOT HAPPEN : invalid action for god : ID="+ to_string(static_cast<int>(god.state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Position God::getRightHandPos(unsigned screenWidth) const {
|
Position God::getRightHandPos(unsigned screenWidth) const {
|
||||||
return Position(screenWidth - GOD_HAND_DISTANCE - GOD_HAND_SIZE, 0);
|
return {screenWidth - GOD_HAND_DISTANCE - GOD_HAND_SIZE, 0};
|
||||||
}
|
}
|
@ -27,7 +27,7 @@ unsigned InvadersColumn::getOutterInvader() const {
|
|||||||
|
|
||||||
// these are used to invoke rand() as less as possible
|
// these are used to invoke rand() as less as possible
|
||||||
|
|
||||||
unsigned InvadersColumn::randomValid() const {
|
unsigned InvadersColumn::randomValidInv() const {
|
||||||
|
|
||||||
|
|
||||||
unsigned validTotal = 0;
|
unsigned validTotal = 0;
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
#include <utils.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
bool areLinesColliding(unsigned start1, unsigned end1, unsigned start2, unsigned end2){
|
bool areLinesColliding(unsigned start1, unsigned end1, unsigned start2, unsigned end2){
|
||||||
|
Loading…
Reference in New Issue
Block a user