diff --git a/include/constants.hpp b/include/constants.hpp index f50451c..23bedea 100644 --- a/include/constants.hpp +++ b/include/constants.hpp @@ -1,6 +1,8 @@ #ifndef __PTF_CONSTANTS_HPP__ #define __PTF_CONSTANTS_HPP__ +#include + namespace Constants { /** * Constante d'attraction. Utilisée dans la formule diff --git a/include/game.hpp b/include/game.hpp index f8d2f24..97a446a 100644 --- a/include/game.hpp +++ b/include/game.hpp @@ -1,53 +1,26 @@ #ifndef __PTF_GAME_HPP__ #define __PTF_GAME_HPP__ -#include -#include -#include -#include "view.hpp" -#include "object.hpp" -#include "manager.hpp" -#include "resource_manager.hpp" +#include "level.hpp" /** * La classe Game gère l'affichage et les objets * d'une partie de jeu */ -class Game : public View { +class Game : public Level { private: - std::string level_name; - sf::Sprite background; - sf::Time next_frame_time; - std::vector objects; - std::vector> level_zone; - /** * Met à jour les objets du jeu pour * qu'ils s'adaptent au nouvel état */ void update(); - /** - * Dessine la scène du jeu couche par couche - */ - void draw(); - public: Game(Manager& manager); virtual ~Game(); - /** - * Charge un niveau de jeu depuis le fichier donné - */ - void load(std::ifstream& file); - - /** - * Sauvegarde la configuration actuelle comme un niveau - */ - void save(); - /** * Demande le passage à la frame suivante sur * cette vue diff --git a/include/level.hpp b/include/level.hpp new file mode 100644 index 0000000..385f2f3 --- /dev/null +++ b/include/level.hpp @@ -0,0 +1,60 @@ +#ifndef __PTF_OBJECT_VIEW_HPP__ +#define __PTF_OBJECT_VIEW_HPP__ + +#include +#include +#include "view.hpp" +#include "object.hpp" +#include "manager.hpp" +#include "resource_manager.hpp" + +/** + * La classe Level est une abstraction des + * classes affichant une collection d'objets, comme + * les classe de l'éditeur et du jeu + */ +class Level : public View { +private: + std::string name; + sf::Sprite background; + + std::vector objects; + std::vector> zone; + +protected: + /** + * Dessine tous les objets et le fond à l'écran + */ + void draw(); + +public: + Level(Manager& manager); + virtual ~Level(); + + /** + * Charge un niveau de jeu depuis le fichier donné + */ + void load(std::ifstream& file); + + /** + * Sauvegarde la configuration actuelle comme un niveau + */ + void save(); + + /** + * Récupère le nom du niveau + */ + std::string getName(); + + /** + * Récupère la liste des objets + */ + std::vector getObjects(); + + /** + * Récupère la zone du niveau + */ + std::vector> getZone(); +}; + +#endif diff --git a/src/game.cpp b/src/game.cpp index bab65f7..19ae7dd 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,114 +1,9 @@ #include "game.hpp" #include "constants.hpp" -#include "object.hpp" -#include "block.hpp" -#include "player.hpp" -#include -#include -#include -#include -#include -/** - * Dictionnaire associant les types d'objets - * à des instances qui seront utilisées pour la - * construction d'autres objets de ces types - */ -std::map(std::ifstream&)>> object_type_map = { - {Player::TYPE_ID, Player::load}, - {Block::TYPE_ID, Block::load} -}; - -Game::Game(Manager& manager) : View(manager), +Game::Game(Manager& manager) : Level(manager), next_frame_time(manager.getCurrentTime()) {} - -Game::~Game() { - objects.clear(); -} - -void Game::load(std::ifstream& file) { - // vide le niveau précédent s'il y a lieu - if (objects.size() != 0) { - objects.clear(); - } - - // lecture de la signture du fichier ("BAR") - char signature[3]; - file.read(signature, sizeof(signature)); - - if (strncmp(signature, "BAR", sizeof(signature)) != 0) { - throw std::runtime_error( - "Impossible de lire le fichier : en-tête invalide" - ); - } - - // lecture de la version du fichier - char file_version; - file.read(&file_version, 1); - - if (file_version != 0) { - throw std::runtime_error( - "Impossible de lire le fichier : version non prise en charge" - ); - } - - // lecture du nom du niveau - std::getline(file, level_name, '\0'); - - // lecture de la zone de jeu - char control_points; - file.read(&control_points, 1); - level_zone.clear(); - - 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)); - - pos_x *= Constants::GRID; - pos_y *= Constants::GRID; - - level_zone.push_back(std::make_pair(pos_x, pos_y)); - } - - // lecture des chemins de la musique et du fond - std::string music_name, background_name; - ResourceManager& resource_manager = manager.getResourceManager(); - - std::getline(file, music_name, '\0'); - resource_manager.setMusic(music_name); - resource_manager.playMusic(); - - std::getline(file, background_name, '\0'); - background.setTexture(resource_manager.getTexture(background_name)); - - // lecture du nombre de blocs - int block_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); - - // vérifie que le type est pris en charge - // pour éviter une erreur de segmentation - if (object_type_map.count(block_type) == 0) { - throw std::runtime_error( - "Impossible de lire le fichier : type d'objet inconnu" - ); - } - - objects.push_back(object_type_map[block_type](file)); - } -} - -void Game::save() { - // TODO: faire une fonction d'enregistrement - // TODO: migrer sur une classe commune Game <-> Editor -} +Game::~Game() {} void Game::frame() { sf::Time current_time = manager.getCurrentTime(); @@ -136,11 +31,11 @@ void Game::update() { std::vector colliding; // détection des objets en collision - for (unsigned int i = 0; i < objects.size(); i++) { - ObjectPtr objA = objects[i]; + for (unsigned int i = 0; i < getObjects().size(); i++) { + ObjectPtr objA = getObjects()[i]; - for (unsigned int j = i + 1; j < objects.size(); j++) { - ObjectPtr objB = objects[j]; + for (unsigned int j = i + 1; j < getObjects().size(); j++) { + ObjectPtr objB = getObjects()[j]; CollisionData data(*objA, *objB); if (objA->detectCollision(*objB, data)) { @@ -150,8 +45,8 @@ void Game::update() { } // intégration des forces dans la vitesse (première moitié) - for (unsigned int i = 0; i < objects.size(); i++) { - objects[i]->updateVelocity(manager, objects, Constants::PHYSICS_TIME.asSeconds() / 2); + for (unsigned int i = 0; i < getObjects().size(); i++) { + getObjects()[i]->updateVelocity(manager, getObjects(), Constants::PHYSICS_TIME.asSeconds() / 2); } // résolution des collisions détectées @@ -161,8 +56,8 @@ void Game::update() { } // intégration de la vitesse dans la position - for (unsigned int i = 0; i < objects.size(); i++) { - objects[i]->updatePosition(Constants::PHYSICS_TIME.asSeconds()); + for (unsigned int i = 0; i < getObjects().size(); i++) { + getObjects()[i]->updatePosition(Constants::PHYSICS_TIME.asSeconds()); } // application de la correction positionnelle @@ -174,29 +69,7 @@ void Game::update() { } // intégration des forces dans la vitesse (seconde moitié) - for (unsigned int i = 0; i < objects.size(); i++) { - objects[i]->updateVelocity(manager, objects, Constants::PHYSICS_TIME.asSeconds() / 2); + for (unsigned int i = 0; i < getObjects().size(); i++) { + getObjects()[i]->updateVelocity(manager, getObjects(), Constants::PHYSICS_TIME.asSeconds() / 2); } } - -void Game::draw() { - // efface la scène précédente et dessine la couche de fond - sf::RenderWindow& window = manager.getWindow(); - window.clear(sf::Color(66, 165, 245)); - window.draw(background); - - // chargement de la file d'affichage des objets - std::priority_queue, ObjectCompare> display_queue; - - for (unsigned int i = 0; i < objects.size(); i++) { - display_queue.push(objects[i]); - } - - // dessin des objets de la file d'affichage couche par couche - while (!display_queue.empty()) { - display_queue.top()->draw(manager); - display_queue.pop(); - } - - window.display(); -} diff --git a/src/level.cpp b/src/level.cpp new file mode 100644 index 0000000..5ce66b0 --- /dev/null +++ b/src/level.cpp @@ -0,0 +1,140 @@ +#include "constants.hpp" +#include "block.hpp" +#include "player.hpp" +#include +#include +#include +#include +#include "level.hpp" + +/** + * Dictionnaire associant les types d'objets + * à des instances qui seront utilisées pour la + * construction d'autres objets de ces types + */ +std::map(std::ifstream&)>> object_type_map = { + {Player::TYPE_ID, Player::load}, + {Block::TYPE_ID, Block::load} +}; + +Level::Level(Manager& manager) : View(manager) {} +Level::~Level() { + objects.clear(); +} + +void Level::load(std::ifstream& file) { + // vide le niveau précédent s'il y a lieu + if (objects.size() != 0) { + objects.clear(); + } + + // lecture de la signture du fichier ("BAR") + char signature[3]; + file.read(signature, sizeof(signature)); + + if (strncmp(signature, "BAR", sizeof(signature)) != 0) { + throw std::runtime_error( + "Impossible de lire le fichier : en-tête invalide" + ); + } + + // lecture de la version du fichier + char file_version; + file.read(&file_version, 1); + + if (file_version != 0) { + throw std::runtime_error( + "Impossible de lire le fichier : version non prise en charge" + ); + } + + // lecture du nom du niveau + std::getline(file, name, '\0'); + + // lecture de la zone de jeu + char control_points; + file.read(&control_points, 1); + zone.clear(); + + 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)); + + pos_x *= Constants::GRID; + pos_y *= Constants::GRID; + + zone.push_back(std::make_pair(pos_x, pos_y)); + } + + // lecture des chemins de la musique et du fond + std::string music_name, background_name; + ResourceManager& resource_manager = manager.getResourceManager(); + + std::getline(file, music_name, '\0'); + resource_manager.setMusic(music_name); + resource_manager.playMusic(); + + std::getline(file, background_name, '\0'); + background.setTexture(resource_manager.getTexture(background_name)); + + // lecture du nombre de blocs + int block_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); + + // vérifie que le type est pris en charge + // pour éviter une erreur de segmentation + if (object_type_map.count(block_type) == 0) { + throw std::runtime_error( + "Impossible de lire le fichier : type d'objet inconnu" + ); + } + + objects.push_back(object_type_map[block_type](file)); + } +} + +void Level::save() { + // TODO: faire une fonction d'enregistrement +} + +void Level::draw() { + // efface la scène précédente et dessine la couche de fond + sf::RenderWindow& window = manager.getWindow(); + window.clear(sf::Color(66, 165, 245)); + window.draw(background); + + // chargement de la file d'affichage des objets + std::priority_queue, ObjectCompare> display_queue; + + for (unsigned int i = 0; i < objects.size(); i++) { + display_queue.push(objects[i]); + } + + // dessin des objets de la file d'affichage couche par couche + while (!display_queue.empty()) { + display_queue.top()->draw(manager); + display_queue.pop(); + } + + window.display(); +} + +std::string Level::getName() { + return name; +} + +std::vector Level::getObjects() { + return objects; +} + +std::vector> Level::getZone() { + return zone; +}