skizzle/src/game.cpp

192 lines
5.5 KiB
C++
Raw Normal View History

2016-03-28 13:05:18 +00:00
#include "game.hpp"
2016-03-20 13:32:34 +00:00
#include "constants.hpp"
#include "object.hpp"
#include "block.hpp"
2016-03-28 18:02:23 +00:00
#include "player.hpp"
#include <arpa/inet.h>
2016-03-30 12:03:52 +00:00
#include <cstring>
#include <queue>
2016-03-30 12:03:52 +00:00
#include <utility>
#include <iostream>
2016-03-04 15:29:31 +00:00
/**
* Dictionnaire associant les types d'objets
* à des instances qui seront utilisées pour la
* construction d'autres objets de ces types
*/
std::map<unsigned int, std::function<std::shared_ptr<Object>(std::ifstream&)>> object_type_map = {
{Player::TYPE_ID, Player::load},
{Block::TYPE_ID, Block::load}
};
2016-03-30 12:03:52 +00:00
Game::Game(Manager& manager) : View(manager), accumulator(0.f) {}
2016-03-28 17:57:55 +00:00
Game::~Game() {
2016-04-01 08:40:10 +00:00
objects.clear();
}
2016-03-20 13:32:34 +00:00
2016-03-30 12:03:52 +00:00
void Game::load(std::ifstream& file) {
2016-03-28 17:57:55 +00:00
// vide le niveau précédent s'il y a lieu
2016-04-01 08:40:10 +00:00
if (objects.size() != 0) {
objects.clear();
2016-03-28 17:57:55 +00:00
}
2016-03-30 12:03:52 +00:00
// lecture de la signture du fichier ("BAR")
char signature[3];
file.read(signature, sizeof(signature));
2016-04-01 08:40:10 +00:00
if (strncmp(signature, "BAR", sizeof(signature)) != 0) {
2016-03-30 12:03:52 +00:00
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');
2016-03-30 20:13:29 +00:00
// lecture de la zone de jeu
2016-03-30 12:03:52 +00:00
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<char*>(&pos_x), sizeof(pos_x));
file.read(reinterpret_cast<char*>(&pos_y), sizeof(pos_y));
2016-03-30 12:03:52 +00:00
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
2016-03-30 20:13:29 +00:00
std::string music_name, background_name;
ResourceManager& resource_manager = manager.getResourceManager();
2016-03-30 12:03:52 +00:00
2016-03-30 20:13:29 +00:00
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<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);
// 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));
}
2016-03-28 17:57:55 +00:00
}
void Game::save() {
// TODO: faire une fonction d'enregistrement
// TODO: migrer sur une classe commune Game <-> Editor
}
2016-03-30 12:03:52 +00:00
void Game::frame() {
accumulator += manager.getElapsedTime();
// tant qu'il reste du temps à passer,
// effectuer la simulation physique étape par étape
while (accumulator >= Constants::PHYSICS_TIME) {
accumulator -= Constants::PHYSICS_TIME;
2016-03-30 12:03:52 +00:00
update();
2016-03-04 15:29:31 +00:00
}
2016-03-30 12:03:52 +00:00
draw();
}
2016-03-30 12:03:52 +00:00
void Game::update() {
std::vector<CollisionData> colliding;
// détection des objets en collision
for (unsigned int i = 0; i < objects.size(); i++) {
2016-03-30 12:03:52 +00:00
ObjectPtr objA = objects[i];
for (unsigned int j = i + 1; j < objects.size(); j++) {
2016-03-30 12:03:52 +00:00
ObjectPtr objB = objects[j];
CollisionData data(*objA, *objB);
if (objA->detectCollision(*objB, data)) {
colliding.push_back(data);
}
}
}
// 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 / 2);
}
// résolution des collisions détectées
for (unsigned int i = 0; i < colliding.size(); i++) {
CollisionData& collided = colliding[i];
collided.objA.solveCollision(collided.objB, collided.normal);
}
// intégration de la vitesse dans la position
for (unsigned int i = 0; i < objects.size(); i++) {
objects[i]->updatePosition(Constants::PHYSICS_TIME);
}
// application de la correction positionnelle
for (unsigned int i = 0; i < colliding.size(); i++) {
CollisionData& collided = colliding[i];
collided.objA.positionalCorrection(
collided.objB, collided.normal, collided.depth
);
}
// 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 / 2);
}
2016-03-04 15:29:31 +00:00
}
2016-03-30 12:03:52 +00:00
void Game::draw() {
// efface la scène précédente et dessine la couche de fond
2016-03-30 20:13:29 +00:00
sf::RenderWindow& window = manager.getWindow();
window.clear(sf::Color(66, 165, 245));
window.draw(background);
2016-03-04 15:29:31 +00:00
// chargement de la file d'affichage des objets
2016-03-30 12:03:52 +00:00
std::priority_queue<ObjectPtr, std::vector<ObjectPtr>, ObjectCompare> display_queue;
for (unsigned int i = 0; i < objects.size(); i++) {
display_queue.push(objects[i]);
2016-03-04 15:29:31 +00:00
}
// dessin des objets de la file d'affichage couche par couche
while (!display_queue.empty()) {
display_queue.top()->draw(manager);
display_queue.pop();
2016-03-04 15:29:31 +00:00
}
2016-03-10 18:18:50 +00:00
2016-03-30 20:13:29 +00:00
window.display();
2016-03-04 15:29:31 +00:00
}