Sauvegarde des objets dans un fichier

This commit is contained in:
Mattéo Delabre 2016-04-10 06:53:45 +02:00
parent b175b31643
commit ed0f2f5ace
11 changed files with 234 additions and 55 deletions

View File

@ -64,6 +64,11 @@ public:
* Chargement du bloc depuis le fichier donné * Chargement du bloc depuis le fichier donné
*/ */
static ObjectPtr load(std::ifstream& file); static ObjectPtr load(std::ifstream& file);
/**
* Sauvegarde le bloc dans le fichier donné
*/
virtual void save(std::ofstream& file) const;
}; };
#endif #endif

View File

@ -42,6 +42,11 @@ public:
*/ */
static ObjectPtr load(std::ifstream& file); static ObjectPtr load(std::ifstream& file);
/**
* Sauvegarde le bloc de gravité dans le fichier donné
*/
virtual void save(std::ofstream& file) const;
/** /**
* Récupère la direction de gravité du bloc changeur de gravité * Récupère la direction de gravité du bloc changeur de gravité
*/ */

View File

@ -24,8 +24,10 @@ private:
sf::String name; sf::String name;
int total_time; int total_time;
sf::Sprite background;
std::string music_name; sf::Sprite background_sprite;
std::string background;
std::string music;
std::vector<ObjectPtr> objects; std::vector<ObjectPtr> objects;
std::vector<std::pair<float, float>> zone; std::vector<std::pair<float, float>> zone;
@ -56,12 +58,12 @@ public:
/** /**
* Charge un niveau de jeu avec le nom donné * Charge un niveau de jeu avec le nom donné
*/ */
virtual void load(std::string name); virtual void load(std::string filename);
/** /**
* Sauvegarde la configuration actuelle dans le niveau donné * Sauvegarde la configuration actuelle dans le niveau donné
*/ */
virtual void save(std::string name); virtual void save(std::string filename);
/** /**
* Appelé par le manager lorsque l'état est utilisé * Appelé par le manager lorsque l'état est utilisé
@ -93,15 +95,25 @@ public:
*/ */
void setTotalTime(int set_total_time); void setTotalTime(int set_total_time);
/**
* Récupère la musique du niveau
*/
std::string getMusic() const;
/**
* Modifie la musique du niveau
*/
void setMusic(std::string set_music);
/** /**
* Récupère le fond du niveau * Récupère le fond du niveau
*/ */
sf::Sprite getBackground() const; std::string getBackground() const;
/** /**
* Modifie le fond du niveau * Modifie le fond du niveau
*/ */
void setBackground(sf::Sprite set_background); void setBackground(std::string set_background);
/** /**
* Calcule le vecteur gravité en fonction de la direction de la gravité * Calcule le vecteur gravité en fonction de la direction de la gravité

View File

@ -89,6 +89,11 @@ public:
*/ */
static void load(std::ifstream& file, ObjectPtr object); static void load(std::ifstream& file, ObjectPtr object);
/**
* Sauvegarde cet objet dans le fichier donné
*/
virtual void save(std::ofstream& file) const = 0;
/** /**
* Met à jour la vitesse de l'objet selon les * Met à jour la vitesse de l'objet selon les
* forces qui lui sont appliquées * forces qui lui sont appliquées

View File

@ -64,6 +64,11 @@ public:
*/ */
static ObjectPtr load(std::ifstream& file); static ObjectPtr load(std::ifstream& file);
/**
* Sauvegarde le joueur dans le fichier donné
*/
virtual void save(std::ofstream& file) const;
/** /**
* Met à jour la position de l'objet selon sa * Met à jour la position de l'objet selon sa
* vitesse actuelle * vitesse actuelle

View File

@ -32,6 +32,11 @@ ObjectPtr Block::load(std::ifstream& file) {
return object; return object;
} }
void Block::save(std::ofstream& file) const {
// écriture des propriétés communes
Object::save(file);
}
void Block::beforeDraw(Level& level) { void Block::beforeDraw(Level& level) {
// texturage et coloration du bloc selon ses propriétés // texturage et coloration du bloc selon ses propriétés
sprite.setTexture( sprite.setTexture(

View File

@ -385,6 +385,7 @@ void Editor::test() {
game->setName(getName()); game->setName(getName());
game->setTotalTime(getTotalTime()); game->setTotalTime(getTotalTime());
game->setBackground(getBackground()); game->setBackground(getBackground());
game->setMusic(getMusic());
// copie des objets du niveau vers le jeu // copie des objets du niveau vers le jeu
std::vector<ObjectPtr>& objects = getObjects(); std::vector<ObjectPtr>& objects = getObjects();

View File

@ -52,21 +52,29 @@ unsigned int GravityBlock::getTypeId() const {
} }
ObjectPtr GravityBlock::load(std::ifstream& file) { ObjectPtr GravityBlock::load(std::ifstream& file) {
ObjectPtr object = ObjectPtr(new GravityBlock);
std::shared_ptr<GravityBlock> block = std::dynamic_pointer_cast<GravityBlock>(object);
// lecture de la direction de la gravité // lecture de la direction de la gravité
char gravity_direction; char gravity_direction;
file.read(&gravity_direction, 1); file.read(&gravity_direction, 1);
// lecture des propriétés d'un bloc
ObjectPtr object = Block::load(file);
std::shared_ptr<GravityBlock> block = std::dynamic_pointer_cast<GravityBlock>(object);
// attribution de la direction
block->setGravityDirection((GravityDirection) gravity_direction); block->setGravityDirection((GravityDirection) gravity_direction);
// lecture des propriétés communes des objets
Object::load(file, object);
file.seekg(1, file.cur);
return object; return object;
} }
void GravityBlock::save(std::ofstream& file) const {
// écriture de la direction de la gravité
char write_gravity_direction = (char) gravity_direction;
file.write(&write_gravity_direction, 1);
// écriture des propriétés d'un bloc
Block::save(file);
}
GravityDirection GravityBlock::getGravityDirection() const { GravityDirection GravityBlock::getGravityDirection() const {
return gravity_direction; return gravity_direction;
} }

View File

@ -19,6 +19,11 @@ const float GRAVITY = 235;
*/ */
const float MOVE = 200; const float MOVE = 200;
/**
* Numéro actuel de version du format de fichier
*/
const unsigned int VERSION_NUMBER = 0;
/** /**
* Dictionnaire associant les types d'objets * Dictionnaire associant les types d'objets
* à des instances qui seront utilisées pour la * à des instances qui seront utilisées pour la
@ -33,8 +38,8 @@ std::map<unsigned int, std::function<ObjectPtr(std::ifstream&)>> object_type_map
Level::Level(Manager& manager) : State(manager) {} Level::Level(Manager& manager) : State(manager) {}
Level::~Level() {} Level::~Level() {}
void Level::load(std::string name) { void Level::load(std::string filename) {
std::ifstream file = getResourceManager().getLevelReader(name); std::ifstream file = getResourceManager().getLevelReader(filename);
// vidage du niveau précédent et positionnement // vidage du niveau précédent et positionnement
// de la caméra au centre du niveau // de la caméra au centre du niveau
@ -43,9 +48,9 @@ void Level::load(std::string name) {
// lecture de la signture du fichier ("BAR") // lecture de la signture du fichier ("BAR")
char signature[3]; char signature[3];
file.read(signature, sizeof(signature)); file.read(signature, 3);
if (strncmp(signature, "BAR", sizeof(signature)) != 0) { if (strncmp(signature, "BAR", 3) != 0) {
throw std::runtime_error( throw std::runtime_error(
"Impossible de lire le fichier : en-tête invalide" "Impossible de lire le fichier : en-tête invalide"
); );
@ -55,7 +60,7 @@ void Level::load(std::string name) {
char file_version; char file_version;
file.read(&file_version, 1); file.read(&file_version, 1);
if (file_version != 0) { if (file_version != VERSION_NUMBER) {
throw std::runtime_error( throw std::runtime_error(
"Impossible de lire le fichier : version non prise en charge" "Impossible de lire le fichier : version non prise en charge"
); );
@ -67,7 +72,7 @@ void Level::load(std::string name) {
name = sf::String(std_name); name = sf::String(std_name);
// lecture du temps total du niveau // lecture du temps total du niveau
file.read(reinterpret_cast<char*>(&total_time), sizeof(total_time)); file.read(reinterpret_cast<char*>(&total_time), 4);
total_time = ntohl(total_time); total_time = ntohl(total_time);
// lecture de la zone de jeu // lecture de la zone de jeu
@ -78,8 +83,8 @@ void Level::load(std::string name) {
for (int i = 0; i < control_points; i++) { for (int i = 0; i < control_points; i++) {
float pos_x, pos_y; float pos_x, pos_y;
file.read(reinterpret_cast<char*>(&pos_x), sizeof(pos_x)); file.read(reinterpret_cast<char*>(&pos_x), 4);
file.read(reinterpret_cast<char*>(&pos_y), sizeof(pos_y)); file.read(reinterpret_cast<char*>(&pos_y), 4);
pos_x *= Constants::GRID; pos_x *= Constants::GRID;
pos_y *= Constants::GRID; pos_y *= Constants::GRID;
@ -88,50 +93,95 @@ void Level::load(std::string name) {
} }
// lecture des chemins de la musique et du fond // lecture des chemins de la musique et du fond
std::string background_name; std::getline(file, music, '\0');
std::getline(file, background, '\0');
std::getline(file, music_name, '\0'); // lecture des objets
std::getline(file, background_name, '\0'); int object_count;
background.setTexture(getResourceManager().getTexture(background_name));
// lecture du nombre de blocs file.read(reinterpret_cast<char*>(&object_count), 4);
int block_count; object_count = ntohl(object_count);
file.read(reinterpret_cast<char*>(&block_count), sizeof(block_count)); for (int i = 0; i < object_count; i++) {
block_count = ntohl(block_count); char object_type;
file.read(&object_type, 1);
for (int i = 0; i < block_count; i++) {
char block_type;
file.read(&block_type, 1);
// vérifie que le type est pris en charge // vérifie que le type est pris en charge
// pour éviter une erreur de segmentation // pour éviter une erreur de segmentation
if (object_type_map.count(block_type) == 0) { if (object_type_map.count(object_type) == 0) {
throw std::runtime_error( throw std::runtime_error(
"Impossible de lire le fichier : type d'objet inconnu" "Impossible de lire le fichier : type d'objet inconnu"
); );
} }
objects.push_back(object_type_map[block_type](file)); // lecture de l'objet
objects.push_back(object_type_map[object_type](file));
} }
} }
void Level::save(std::string name) { void Level::save(std::string filename) {
std::ofstream file = getResourceManager().getLevelWriter(name); std::ofstream file = getResourceManager().getLevelWriter(filename);
// TODO: faire une fonction d'enregistrement // écriture de la signture du fichier ("BAR")
char signature[3] = {'B', 'A', 'R'};
file.write(signature, 3);
// écriture de la version du fichier
char file_version = VERSION_NUMBER;
file.write(&file_version, 1);
// écriture du nom du niveau
char *write_name = (char*) name.toAnsiString().data();
file.write(write_name, name.getSize() + 1);
// écriture du temps total du niveau
int conv_total_time = htonl(total_time);
file.write(reinterpret_cast<char*>(&conv_total_time), 4);
// écriture de la zone de jeu
char control_points = (char) zone.size();
file.write(&control_points, 1);
for (int i = 0; i < control_points; i++) {
float pos_x = std::get<0>(zone[i]) / Constants::GRID;
float pos_y = std::get<1>(zone[i]) / Constants::GRID;
file.write(reinterpret_cast<char*>(&pos_x), 4);
file.write(reinterpret_cast<char*>(&pos_y), 4);
}
// écriture des noms de la musique et du fond
char *write_music = (char*) music.data();
file.write(write_music, music.size() + 1);
char *write_background = (char*) background.data();
file.write(write_background, background.size() + 1);
// écriture des objets
int object_count = htonl(objects.size());
file.write(reinterpret_cast<char*>(&object_count), 4);
for (unsigned int i = 0; i < objects.size(); i++) {
char object_type = objects[i]->getTypeId();
file.write(&object_type, 1);
// écriture de l'objet
objects[i]->save(file);
}
} }
void Level::begin() { void Level::begin() {
// TODO: ceci ne devrait pas être là // TODO: ceci ne devrait pas être là
// (imaginons que l'on quitte et revienne à un niveau) // (imaginons que l'on quitte et revienne à un niveau)
// (il faudra réfléchir à abandonner le concept de ::begin())
camera = getWindow().getDefaultView(); camera = getWindow().getDefaultView();
camera.setCenter(0, 0); camera.setCenter(0, 0);
camera_angle = 180.f; camera_angle = 180.f;
gravity_direction = GravityDirection::SOUTH; gravity_direction = GravityDirection::SOUTH;
if (music_name != "") { if (music != "") {
getResourceManager().playMusic(music_name); getResourceManager().playMusic(music);
} else { } else {
getResourceManager().stopMusic(); getResourceManager().stopMusic();
} }
@ -164,7 +214,12 @@ void Level::draw() {
// efface la scène précédente et dessine la couche de fond // efface la scène précédente et dessine la couche de fond
window.clear(sf::Color(66, 165, 245)); window.clear(sf::Color(66, 165, 245));
window.draw(background);
if (background != "") {
background_sprite.setTexture(getResourceManager().getTexture(background));
}
window.draw(background_sprite);
// chargement de la file d'affichage des objets // chargement de la file d'affichage des objets
std::priority_queue<ObjectPtr, std::vector<ObjectPtr>, ObjectCompare> display_queue; std::priority_queue<ObjectPtr, std::vector<ObjectPtr>, ObjectCompare> display_queue;
@ -203,11 +258,19 @@ void Level::setTotalTime(int set_total_time) {
total_time = set_total_time; total_time = set_total_time;
} }
sf::Sprite Level::getBackground() const { std::string Level::getMusic() const {
return music;
}
void Level::setMusic(std::string set_music) {
music = set_music;
}
std::string Level::getBackground() const {
return background; return background;
} }
void Level::setBackground(sf::Sprite set_background) { void Level::setBackground(std::string set_background) {
background = set_background; background = set_background;
} }

View File

@ -5,11 +5,17 @@
#include <cmath> #include <cmath>
const unsigned int Object::PROP_MASS = 1; const unsigned int Object::PROP_MASS = 1;
const float DEFAULT_MASS = 1.f;
const unsigned int Object::PROP_CHARGE = 2; const unsigned int Object::PROP_CHARGE = 2;
const float DEFAULT_CHARGE = 0.f;
const unsigned int Object::PROP_RESTITUTION = 3; const unsigned int Object::PROP_RESTITUTION = 3;
const float DEFAULT_RESTITUTION = 0.4f;
const unsigned int Object::PROP_STATIC_FRICTION = 4; const unsigned int Object::PROP_STATIC_FRICTION = 4;
const float DEFAULT_STATIC_FRICTION = 0.4f;
const unsigned int Object::PROP_DYNAMIC_FRICTION = 5; const unsigned int Object::PROP_DYNAMIC_FRICTION = 5;
const float DEFAULT_DYNAMIC_FRICTION = 0.2f;
const unsigned int Object::PROP_LAYER = 6; const unsigned int Object::PROP_LAYER = 6;
const int DEFAULT_LAYER = 0;
Object::Object() : Object::Object() :
acceleration(0, 0), velocity(0, 0), position(0, 0), acceleration(0, 0), velocity(0, 0), position(0, 0),
@ -17,11 +23,12 @@ Object::Object() :
// valeurs par défaut pour les propriétés // valeurs par défaut pour les propriétés
// de tous les objets du jeu // de tous les objets du jeu
mass(1.f), charge(0.f), mass(DEFAULT_MASS),
restitution(0.4f), charge(DEFAULT_CHARGE),
static_friction(0.4f), restitution(DEFAULT_RESTITUTION),
dynamic_friction(0.2f), static_friction(DEFAULT_STATIC_FRICTION),
layer(0) {} dynamic_friction(DEFAULT_DYNAMIC_FRICTION),
layer(DEFAULT_LAYER) {}
Object::~Object() {} Object::~Object() {}
@ -29,8 +36,8 @@ void Object::load(std::ifstream& file, ObjectPtr object) {
// lecture de la position de l'objet // lecture de la position de l'objet
float pos_x, pos_y; float pos_x, pos_y;
file.read(reinterpret_cast<char*>(&pos_x), sizeof(pos_x)); file.read(reinterpret_cast<char*>(&pos_x), 4);
file.read(reinterpret_cast<char*>(&pos_y), sizeof(pos_y)); file.read(reinterpret_cast<char*>(&pos_y), 4);
object->setPosition(sf::Vector2f( object->setPosition(sf::Vector2f(
pos_x * Constants::GRID, pos_y * Constants::GRID pos_x * Constants::GRID, pos_y * Constants::GRID
@ -43,31 +50,31 @@ void Object::load(std::ifstream& file, ObjectPtr object) {
switch (prop_type) { switch (prop_type) {
case Object::PROP_MASS: case Object::PROP_MASS:
float mass; float mass;
file.read(reinterpret_cast<char*>(&mass), sizeof(mass)); file.read(reinterpret_cast<char*>(&mass), 4);
object->setMass(mass); object->setMass(mass);
break; break;
case Object::PROP_CHARGE: case Object::PROP_CHARGE:
float charge; float charge;
file.read(reinterpret_cast<char*>(&charge), sizeof(charge)); file.read(reinterpret_cast<char*>(&charge), 4);
object->setCharge(charge); object->setCharge(charge);
break; break;
case Object::PROP_RESTITUTION: case Object::PROP_RESTITUTION:
float restitution; float restitution;
file.read(reinterpret_cast<char*>(&restitution), sizeof(restitution)); file.read(reinterpret_cast<char*>(&restitution), 4);
object->setRestitution(restitution); object->setRestitution(restitution);
break; break;
case Object::PROP_STATIC_FRICTION: case Object::PROP_STATIC_FRICTION:
float static_friction; float static_friction;
file.read(reinterpret_cast<char*>(&static_friction), sizeof(static_friction)); file.read(reinterpret_cast<char*>(&static_friction), 4);
object->setStaticFriction(static_friction); object->setStaticFriction(static_friction);
break; break;
case Object::PROP_DYNAMIC_FRICTION: case Object::PROP_DYNAMIC_FRICTION:
float dynamic_friction; float dynamic_friction;
file.read(reinterpret_cast<char*>(&dynamic_friction), sizeof(dynamic_friction)); file.read(reinterpret_cast<char*>(&dynamic_friction), 4);
object->setDynamicFriction(dynamic_friction); object->setDynamicFriction(dynamic_friction);
break; break;
@ -86,6 +93,60 @@ void Object::load(std::ifstream& file, ObjectPtr object) {
} }
} }
void Object::save(std::ofstream& file) const {
// écriture de la position de l'objet
float pos_x = getPosition().x / Constants::GRID;
float pos_y = getPosition().y / Constants::GRID;
file.write(reinterpret_cast<const char*>(&pos_x), 4);
file.write(reinterpret_cast<const char*>(&pos_y), 4);
// écriture des propriétés facultatives si nécessaire
char prop_type;
if (mass != DEFAULT_MASS) {
prop_type = Object::PROP_MASS;
file.write(&prop_type, 1);
file.write(reinterpret_cast<const char*>(&mass), 4);
}
if (charge != DEFAULT_CHARGE) {
prop_type = Object::PROP_CHARGE;
file.write(&prop_type, 1);
file.write(reinterpret_cast<const char*>(&charge), 4);
}
if (restitution != DEFAULT_RESTITUTION) {
prop_type = Object::PROP_RESTITUTION;
file.write(&prop_type, 1);
file.write(reinterpret_cast<const char*>(&restitution), 4);
}
if (static_friction != DEFAULT_STATIC_FRICTION) {
prop_type = Object::PROP_STATIC_FRICTION;
file.write(&prop_type, 1);
file.write(reinterpret_cast<const char*>(&static_friction), 4);
}
if (dynamic_friction != DEFAULT_DYNAMIC_FRICTION) {
prop_type = Object::PROP_DYNAMIC_FRICTION;
file.write(&prop_type, 1);
file.write(reinterpret_cast<const char*>(&dynamic_friction), 4);
}
if (layer != DEFAULT_LAYER) {
prop_type = Object::PROP_LAYER;
file.write(&prop_type, 1);
char write_layer = layer + 127;
file.write(&write_layer, 1);
}
// on termine par un octet nul pour signaler la fin
char null_byte = 0;
file.write(&null_byte, 1);
}
sf::Vector2f Object::getForces(const Level& level) const { sf::Vector2f Object::getForces(const Level& level) const {
sf::Vector2f forces(0, 0); sf::Vector2f forces(0, 0);
const std::vector<ObjectPtr>& objects = level.getObjects(); const std::vector<ObjectPtr>& objects = level.getObjects();

View File

@ -34,6 +34,15 @@ ObjectPtr Player::load(std::ifstream& file) {
return object; return object;
} }
void Player::save(std::ofstream& file) const {
// écriture du numéro de joueur
char write_player_number = player_number;
file.write(&write_player_number, 1);
// écriture des propriétés communes
Object::save(file);
}
sf::Vector2f Player::getForces(const Level& level) const { sf::Vector2f Player::getForces(const Level& level) const {
sf::Vector2f forces = Object::getForces(level); sf::Vector2f forces = Object::getForces(level);