From ed0f2f5ace7d6c6f3a46252186032d467331413e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Sun, 10 Apr 2016 06:53:45 +0200 Subject: [PATCH] Sauvegarde des objets dans un fichier --- include/block.hpp | 5 ++ include/gravity_block.hpp | 5 ++ include/level.hpp | 24 ++++++-- include/object.hpp | 5 ++ include/player.hpp | 5 ++ src/block.cpp | 5 ++ src/editor.cpp | 1 + src/gravity_block.cpp | 22 ++++--- src/level.cpp | 123 ++++++++++++++++++++++++++++---------- src/object.cpp | 85 ++++++++++++++++++++++---- src/player.cpp | 9 +++ 11 files changed, 234 insertions(+), 55 deletions(-) diff --git a/include/block.hpp b/include/block.hpp index d12f63f..eff6891 100644 --- a/include/block.hpp +++ b/include/block.hpp @@ -64,6 +64,11 @@ public: * Chargement du bloc depuis le fichier donné */ static ObjectPtr load(std::ifstream& file); + + /** + * Sauvegarde le bloc dans le fichier donné + */ + virtual void save(std::ofstream& file) const; }; #endif diff --git a/include/gravity_block.hpp b/include/gravity_block.hpp index fdbed7a..dd1baa7 100644 --- a/include/gravity_block.hpp +++ b/include/gravity_block.hpp @@ -42,6 +42,11 @@ public: */ 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é */ diff --git a/include/level.hpp b/include/level.hpp index cb9ef16..07c4bc2 100644 --- a/include/level.hpp +++ b/include/level.hpp @@ -24,8 +24,10 @@ private: sf::String name; int total_time; - sf::Sprite background; - std::string music_name; + + sf::Sprite background_sprite; + std::string background; + std::string music; std::vector objects; std::vector> zone; @@ -56,12 +58,12 @@ public: /** * 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é */ - virtual void save(std::string name); + virtual void save(std::string filename); /** * Appelé par le manager lorsque l'état est utilisé @@ -93,15 +95,25 @@ public: */ 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 */ - sf::Sprite getBackground() const; + std::string getBackground() const; /** * 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é diff --git a/include/object.hpp b/include/object.hpp index ff472cf..86c8518 100644 --- a/include/object.hpp +++ b/include/object.hpp @@ -89,6 +89,11 @@ public: */ 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 * forces qui lui sont appliquées diff --git a/include/player.hpp b/include/player.hpp index 1ea300b..4095b73 100644 --- a/include/player.hpp +++ b/include/player.hpp @@ -64,6 +64,11 @@ public: */ 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 * vitesse actuelle diff --git a/src/block.cpp b/src/block.cpp index 3d8b075..71d7618 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -32,6 +32,11 @@ ObjectPtr Block::load(std::ifstream& file) { return object; } +void Block::save(std::ofstream& file) const { + // écriture des propriétés communes + Object::save(file); +} + void Block::beforeDraw(Level& level) { // texturage et coloration du bloc selon ses propriétés sprite.setTexture( diff --git a/src/editor.cpp b/src/editor.cpp index bdd5973..c9fa930 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -385,6 +385,7 @@ void Editor::test() { game->setName(getName()); game->setTotalTime(getTotalTime()); game->setBackground(getBackground()); + game->setMusic(getMusic()); // copie des objets du niveau vers le jeu std::vector& objects = getObjects(); diff --git a/src/gravity_block.cpp b/src/gravity_block.cpp index e29b020..1d943bb 100644 --- a/src/gravity_block.cpp +++ b/src/gravity_block.cpp @@ -52,21 +52,29 @@ unsigned int GravityBlock::getTypeId() const { } ObjectPtr GravityBlock::load(std::ifstream& file) { - ObjectPtr object = ObjectPtr(new GravityBlock); - std::shared_ptr block = std::dynamic_pointer_cast(object); - // lecture de la direction de la gravité char gravity_direction; file.read(&gravity_direction, 1); + + // lecture des propriétés d'un bloc + ObjectPtr object = Block::load(file); + std::shared_ptr block = std::dynamic_pointer_cast(object); + + // attribution de la 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; } +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 { return gravity_direction; } diff --git a/src/level.cpp b/src/level.cpp index 21da421..26b2709 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -19,6 +19,11 @@ const float GRAVITY = 235; */ 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 * à des instances qui seront utilisées pour la @@ -33,8 +38,8 @@ std::map> object_type_map Level::Level(Manager& manager) : State(manager) {} Level::~Level() {} -void Level::load(std::string name) { - std::ifstream file = getResourceManager().getLevelReader(name); +void Level::load(std::string filename) { + std::ifstream file = getResourceManager().getLevelReader(filename); // vidage du niveau précédent et positionnement // 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") 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( "Impossible de lire le fichier : en-tête invalide" ); @@ -55,7 +60,7 @@ void Level::load(std::string name) { char file_version; file.read(&file_version, 1); - if (file_version != 0) { + if (file_version != VERSION_NUMBER) { throw std::runtime_error( "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); // lecture du temps total du niveau - file.read(reinterpret_cast(&total_time), sizeof(total_time)); + file.read(reinterpret_cast(&total_time), 4); total_time = ntohl(total_time); // lecture de la zone de jeu @@ -78,8 +83,8 @@ void Level::load(std::string name) { for (int i = 0; i < control_points; i++) { float pos_x, pos_y; - file.read(reinterpret_cast(&pos_x), sizeof(pos_x)); - file.read(reinterpret_cast(&pos_y), sizeof(pos_y)); + file.read(reinterpret_cast(&pos_x), 4); + file.read(reinterpret_cast(&pos_y), 4); pos_x *= 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 - std::string background_name; + std::getline(file, music, '\0'); + std::getline(file, background, '\0'); - std::getline(file, music_name, '\0'); - std::getline(file, background_name, '\0'); - background.setTexture(getResourceManager().getTexture(background_name)); + // lecture des objets + int object_count; - // lecture du nombre de blocs - int block_count; + file.read(reinterpret_cast(&object_count), 4); + object_count = ntohl(object_count); - file.read(reinterpret_cast(&block_count), sizeof(block_count)); - block_count = ntohl(block_count); - - for (int i = 0; i < block_count; i++) { - char block_type; - file.read(&block_type, 1); + for (int i = 0; i < object_count; i++) { + char object_type; + file.read(&object_type, 1); // vérifie que le type est pris en charge // 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( "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) { - std::ofstream file = getResourceManager().getLevelWriter(name); +void Level::save(std::string filename) { + 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(&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(&pos_x), 4); + file.write(reinterpret_cast(&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(&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() { // TODO: ceci ne devrait pas être là // (imaginons que l'on quitte et revienne à un niveau) + // (il faudra réfléchir à abandonner le concept de ::begin()) + camera = getWindow().getDefaultView(); camera.setCenter(0, 0); camera_angle = 180.f; gravity_direction = GravityDirection::SOUTH; - if (music_name != "") { - getResourceManager().playMusic(music_name); + if (music != "") { + getResourceManager().playMusic(music); } else { getResourceManager().stopMusic(); } @@ -164,7 +214,12 @@ void Level::draw() { // efface la scène précédente et dessine la couche de fond 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 std::priority_queue, ObjectCompare> display_queue; @@ -203,11 +258,19 @@ void Level::setTotalTime(int 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; } -void Level::setBackground(sf::Sprite set_background) { +void Level::setBackground(std::string set_background) { background = set_background; } diff --git a/src/object.cpp b/src/object.cpp index db09afa..b6de8fa 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -5,11 +5,17 @@ #include const unsigned int Object::PROP_MASS = 1; +const float DEFAULT_MASS = 1.f; const unsigned int Object::PROP_CHARGE = 2; +const float DEFAULT_CHARGE = 0.f; const unsigned int Object::PROP_RESTITUTION = 3; +const float DEFAULT_RESTITUTION = 0.4f; const unsigned int Object::PROP_STATIC_FRICTION = 4; +const float DEFAULT_STATIC_FRICTION = 0.4f; const unsigned int Object::PROP_DYNAMIC_FRICTION = 5; +const float DEFAULT_DYNAMIC_FRICTION = 0.2f; const unsigned int Object::PROP_LAYER = 6; +const int DEFAULT_LAYER = 0; Object::Object() : acceleration(0, 0), velocity(0, 0), position(0, 0), @@ -17,11 +23,12 @@ Object::Object() : // valeurs par défaut pour les propriétés // de tous les objets du jeu - mass(1.f), charge(0.f), - restitution(0.4f), - static_friction(0.4f), - dynamic_friction(0.2f), - layer(0) {} + mass(DEFAULT_MASS), + charge(DEFAULT_CHARGE), + restitution(DEFAULT_RESTITUTION), + static_friction(DEFAULT_STATIC_FRICTION), + dynamic_friction(DEFAULT_DYNAMIC_FRICTION), + layer(DEFAULT_LAYER) {} Object::~Object() {} @@ -29,8 +36,8 @@ void Object::load(std::ifstream& file, ObjectPtr object) { // lecture de la position de l'objet float pos_x, pos_y; - file.read(reinterpret_cast(&pos_x), sizeof(pos_x)); - file.read(reinterpret_cast(&pos_y), sizeof(pos_y)); + file.read(reinterpret_cast(&pos_x), 4); + file.read(reinterpret_cast(&pos_y), 4); object->setPosition(sf::Vector2f( pos_x * Constants::GRID, pos_y * Constants::GRID @@ -43,31 +50,31 @@ void Object::load(std::ifstream& file, ObjectPtr object) { switch (prop_type) { case Object::PROP_MASS: float mass; - file.read(reinterpret_cast(&mass), sizeof(mass)); + file.read(reinterpret_cast(&mass), 4); object->setMass(mass); break; case Object::PROP_CHARGE: float charge; - file.read(reinterpret_cast(&charge), sizeof(charge)); + file.read(reinterpret_cast(&charge), 4); object->setCharge(charge); break; case Object::PROP_RESTITUTION: float restitution; - file.read(reinterpret_cast(&restitution), sizeof(restitution)); + file.read(reinterpret_cast(&restitution), 4); object->setRestitution(restitution); break; case Object::PROP_STATIC_FRICTION: float static_friction; - file.read(reinterpret_cast(&static_friction), sizeof(static_friction)); + file.read(reinterpret_cast(&static_friction), 4); object->setStaticFriction(static_friction); break; case Object::PROP_DYNAMIC_FRICTION: float dynamic_friction; - file.read(reinterpret_cast(&dynamic_friction), sizeof(dynamic_friction)); + file.read(reinterpret_cast(&dynamic_friction), 4); object->setDynamicFriction(dynamic_friction); 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(&pos_x), 4); + file.write(reinterpret_cast(&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(&mass), 4); + } + + if (charge != DEFAULT_CHARGE) { + prop_type = Object::PROP_CHARGE; + file.write(&prop_type, 1); + file.write(reinterpret_cast(&charge), 4); + } + + if (restitution != DEFAULT_RESTITUTION) { + prop_type = Object::PROP_RESTITUTION; + file.write(&prop_type, 1); + file.write(reinterpret_cast(&restitution), 4); + } + + if (static_friction != DEFAULT_STATIC_FRICTION) { + prop_type = Object::PROP_STATIC_FRICTION; + file.write(&prop_type, 1); + file.write(reinterpret_cast(&static_friction), 4); + } + + if (dynamic_friction != DEFAULT_DYNAMIC_FRICTION) { + prop_type = Object::PROP_DYNAMIC_FRICTION; + file.write(&prop_type, 1); + file.write(reinterpret_cast(&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 forces(0, 0); const std::vector& objects = level.getObjects(); diff --git a/src/player.cpp b/src/player.cpp index 6ea566e..70f5bad 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -34,6 +34,15 @@ ObjectPtr Player::load(std::ifstream& file) { 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 forces = Object::getForces(level);