2016-03-04 15:29:31 +00:00
|
|
|
#include "engine.hpp"
|
|
|
|
#include <cmath>
|
2016-03-08 18:52:55 +00:00
|
|
|
#include <queue>
|
2016-03-04 15:29:31 +00:00
|
|
|
|
2016-03-10 09:40:50 +00:00
|
|
|
Engine::Engine() : window(
|
2016-03-11 15:11:30 +00:00
|
|
|
sf::VideoMode(400, 300), "Projet CMI",
|
2016-03-10 09:40:50 +00:00
|
|
|
sf::Style::Default & ~sf::Style::Resize,
|
|
|
|
sf::ContextSettings(0, 0, 2)
|
2016-03-13 16:03:56 +00:00
|
|
|
) {
|
2016-03-04 15:29:31 +00:00
|
|
|
window.setVerticalSyncEnabled(true);
|
2016-03-09 18:33:43 +00:00
|
|
|
}
|
2016-03-04 15:29:31 +00:00
|
|
|
|
2016-03-09 18:33:43 +00:00
|
|
|
void Engine::start() {
|
2016-03-04 15:29:31 +00:00
|
|
|
// boucle d'événements sur la fenêtre
|
|
|
|
while (window.isOpen()) {
|
|
|
|
sf::Event event;
|
|
|
|
|
|
|
|
// traitement des évènements reçus
|
|
|
|
while (window.pollEvent(event)) {
|
|
|
|
// fermeture de la fenêtre
|
|
|
|
if (event.type == sf::Event::Closed) {
|
|
|
|
window.close();
|
|
|
|
}
|
|
|
|
|
2016-03-13 16:03:56 +00:00
|
|
|
// suivi de l'enfoncement et du relâchement des touches
|
2016-03-04 15:29:31 +00:00
|
|
|
if (event.type == sf::Event::KeyPressed) {
|
2016-03-13 16:03:56 +00:00
|
|
|
state.keys[event.key.code] = true;
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (event.type == sf::Event::KeyReleased) {
|
2016-03-13 16:03:56 +00:00
|
|
|
state.keys[event.key.code] = false;
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-13 16:03:56 +00:00
|
|
|
state.delta = clock.restart().asSeconds();
|
|
|
|
|
2016-03-09 18:21:38 +00:00
|
|
|
update();
|
2016-03-04 15:29:31 +00:00
|
|
|
draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-12 18:45:16 +00:00
|
|
|
void Engine::addObject(Object& object) {
|
2016-03-13 16:03:56 +00:00
|
|
|
state.objects.push_back(&object);
|
2016-03-09 18:35:40 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 18:21:38 +00:00
|
|
|
void Engine::update() {
|
2016-03-08 18:52:55 +00:00
|
|
|
// demande la mise à jour de tous les objets du jeu
|
2016-03-13 16:03:56 +00:00
|
|
|
for (unsigned int i = 0; i < state.objects.size(); i++) {
|
|
|
|
state.objects[i]->update(state);
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|
2016-03-13 18:07:35 +00:00
|
|
|
|
2016-03-15 21:00:03 +00:00
|
|
|
// gère les collisions entre les objets
|
2016-03-13 18:07:35 +00:00
|
|
|
for (unsigned int i = 0; i < state.objects.size(); i++) {
|
|
|
|
Object* objA = state.objects[i];
|
|
|
|
|
|
|
|
for (unsigned int j = i + 1; j < state.objects.size(); j++) {
|
|
|
|
Object* objB = state.objects[j];
|
|
|
|
|
2016-03-15 21:00:03 +00:00
|
|
|
// si les objets ne sont pas sur la même couche,
|
|
|
|
// ils ne peuvent pas entrer en collision
|
|
|
|
if (objA->getLayer() != objB->getLayer()) {
|
|
|
|
continue;
|
2016-03-13 18:07:35 +00:00
|
|
|
}
|
2016-03-15 21:00:03 +00:00
|
|
|
|
|
|
|
// si les deux boîtes englobantes des deux objets,
|
|
|
|
// il ne risque pas d'y avoir de collision
|
|
|
|
if (!objA->getAABB()->intersects(*objB->getAABB())) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sf::Vector2f normal;
|
|
|
|
|
|
|
|
// vérifie plus finement s'il y a collision et
|
|
|
|
// calcule la normale
|
|
|
|
if (!objA->getNormal(*objB, normal)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sf::Vector2f codir = objB->getVelocity() - objA->getVelocity();
|
|
|
|
float dotnormal = codir.x * normal.x + codir.y * normal.y;
|
|
|
|
|
|
|
|
// si les directions sont divergentes, pas besoin
|
|
|
|
// de résoudre la collision
|
|
|
|
if (dotnormal >= 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
float restitution = std::min(objA->getRestitution(), objB->getRestitution());
|
|
|
|
|
|
|
|
// calcul de l'inverse des masses de A et B. Pour rappel,
|
|
|
|
// une masse infinie est modélisée par 0, donc l'inverse
|
|
|
|
// d'une telle masse est nul
|
|
|
|
float invMassA = objA->getMass();
|
|
|
|
float invMassB = objB->getMass();
|
|
|
|
|
|
|
|
if (invMassA != 0) {
|
|
|
|
invMassA = 1.f / invMassA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (invMassB != 0) {
|
|
|
|
invMassB = 1.f / invMassB;
|
|
|
|
}
|
|
|
|
|
|
|
|
// calcule et applique l'impulsion de résolution de la collision
|
|
|
|
float impulse = (-(1 + restitution) * dotnormal) / (invMassA + invMassB);
|
|
|
|
objA->setVelocity(objA->getVelocity() - invMassA * impulse * normal);
|
|
|
|
objB->setVelocity(objB->getVelocity() + invMassB * impulse * normal);
|
2016-03-13 18:07:35 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::draw() {
|
2016-03-08 18:52:55 +00:00
|
|
|
// efface la scène précédente et dessine la couche de fond
|
2016-03-04 15:29:31 +00:00
|
|
|
window.clear(sf::Color(66, 165, 245));
|
|
|
|
|
2016-03-08 18:52:55 +00:00
|
|
|
// chargement de la file d'affichage des objets
|
2016-03-10 21:47:53 +00:00
|
|
|
std::priority_queue<Object*, std::vector<Object*>, ObjectCompare> display_queue;
|
2016-03-08 18:52:55 +00:00
|
|
|
|
2016-03-13 16:03:56 +00:00
|
|
|
for (unsigned int i = 0; i < state.objects.size(); i++) {
|
|
|
|
display_queue.push(state.objects[i]);
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|
|
|
|
|
2016-03-08 18:52:55 +00:00
|
|
|
// dessin des objets de la file d'affichage couche par couche
|
|
|
|
while (!display_queue.empty()) {
|
2016-03-08 21:50:42 +00:00
|
|
|
display_queue.top()->draw(window);
|
|
|
|
display_queue.pop();
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|
2016-03-10 18:18:50 +00:00
|
|
|
|
|
|
|
window.display();
|
2016-03-04 15:29:31 +00:00
|
|
|
}
|