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é
*/
static ObjectPtr load(std::ifstream& file);
/**
* Sauvegarde le bloc dans le fichier donné
*/
virtual void save(std::ofstream& file) const;
};
#endif

View File

@ -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é
*/

View File

@ -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<ObjectPtr> objects;
std::vector<std::pair<float, float>> 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é

View File

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

View File

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

View File

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

View File

@ -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<ObjectPtr>& objects = getObjects();

View File

@ -52,21 +52,29 @@ unsigned int GravityBlock::getTypeId() const {
}
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é
char gravity_direction;
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);
// 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;
}

View File

@ -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<unsigned int, std::function<ObjectPtr(std::ifstream&)>> 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<char*>(&total_time), sizeof(total_time));
file.read(reinterpret_cast<char*>(&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<char*>(&pos_x), sizeof(pos_x));
file.read(reinterpret_cast<char*>(&pos_y), sizeof(pos_y));
file.read(reinterpret_cast<char*>(&pos_x), 4);
file.read(reinterpret_cast<char*>(&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<char*>(&object_count), 4);
object_count = ntohl(object_count);
file.read(reinterpret_cast<char*>(&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<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() {
// 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<ObjectPtr, std::vector<ObjectPtr>, 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;
}

View File

@ -5,11 +5,17 @@
#include <cmath>
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<char*>(&pos_x), sizeof(pos_x));
file.read(reinterpret_cast<char*>(&pos_y), sizeof(pos_y));
file.read(reinterpret_cast<char*>(&pos_x), 4);
file.read(reinterpret_cast<char*>(&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<char*>(&mass), sizeof(mass));
file.read(reinterpret_cast<char*>(&mass), 4);
object->setMass(mass);
break;
case Object::PROP_CHARGE:
float charge;
file.read(reinterpret_cast<char*>(&charge), sizeof(charge));
file.read(reinterpret_cast<char*>(&charge), 4);
object->setCharge(charge);
break;
case Object::PROP_RESTITUTION:
float restitution;
file.read(reinterpret_cast<char*>(&restitution), sizeof(restitution));
file.read(reinterpret_cast<char*>(&restitution), 4);
object->setRestitution(restitution);
break;
case Object::PROP_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);
break;
case Object::PROP_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);
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 forces(0, 0);
const std::vector<ObjectPtr>& objects = level.getObjects();

View File

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