diff --git a/include/block.hpp b/include/block.hpp index 5ceaec2..3c86f4b 100644 --- a/include/block.hpp +++ b/include/block.hpp @@ -30,6 +30,11 @@ public: */ virtual std::unique_ptr getAABB() const; + /** + * Récupère le rayon du bloc + */ + virtual float getRadius() const; + /** * Opérations de préparation de la texture du bloc */ @@ -50,6 +55,11 @@ public: */ virtual unsigned int getTypeId() const; + /** + * Récupère le type de collision des blocs + */ + virtual CollisionType getCollisionType() const; + /** * Chargement du bloc depuis le fichier donné */ diff --git a/include/collision.hpp b/include/collision.hpp index f068ca7..1f9978d 100644 --- a/include/collision.hpp +++ b/include/collision.hpp @@ -6,23 +6,29 @@ class Object; /** - * Structure qui retient des informations + * Type de collision : entre deux rectangles ou + * entre deux cercles + */ +enum class CollisionType {AABB, CIRCLE}; + +/** + * Structure qui retient les informations * sur les collisions */ struct CollisionData { sf::Vector2f normal; float depth; - Object& objA; - Object& objB; + Object& obj_a; + Object& obj_b; - CollisionData(Object& objA, Object& objB); + CollisionData(Object& obj_a, Object& obj_b); }; /** * Détermine les informations sur la collision - * entre les deux objets donnés dans data et - * les stocke dans data + * entre les deux objets donnés dans data et stocke + * ces informations dans data */ bool getCollisionData(CollisionData& data); diff --git a/include/object.hpp b/include/object.hpp index 5757e4a..969766e 100644 --- a/include/object.hpp +++ b/include/object.hpp @@ -58,6 +58,11 @@ public: */ virtual std::unique_ptr getAABB() const = 0; + /** + * Récupère le rayon de l'objet + */ + virtual float getRadius() const = 0; + /** * Dessine l'objet dans la fenêtre donnée */ @@ -73,6 +78,11 @@ public: */ virtual unsigned int getTypeId() const = 0; + /** + * Récupère le type de collision de cet objet + */ + virtual CollisionType getCollisionType() const = 0; + /** * Charge les propriétés communes à tous les objets * depuis le fichier donné dans l'objet donné diff --git a/include/player.hpp b/include/player.hpp index b37a226..c72c988 100644 --- a/include/player.hpp +++ b/include/player.hpp @@ -34,6 +34,11 @@ public: */ virtual std::unique_ptr getAABB() const; + /** + * Récupère le rayon du joueur + */ + virtual float getRadius() const; + /** * Dessine le joueur dans la fenêtre donnée */ @@ -49,6 +54,11 @@ public: */ virtual unsigned int getTypeId() const; + /** + * Récupère le type de collision des joueurs + */ + virtual CollisionType getCollisionType() const; + /** * Chargement du joueur depuis le fichier donné */ @@ -60,11 +70,6 @@ public: */ virtual void updatePosition(); - /** - * Renvoie le rayon de la balle du joueur - */ - float getRadius() const; - /** * Renvoie le numéro du joueur */ diff --git a/src/block.cpp b/src/block.cpp index 6d176d7..7a47d1e 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -79,6 +79,14 @@ std::unique_ptr Block::getAABB() const { )); } +float Block::getRadius() const { + return Constants::GRID / 2; +} + unsigned int Block::getTypeId() const { return TYPE_ID; } + +CollisionType Block::getCollisionType() const { + return CollisionType::AABB; +} diff --git a/src/collision.cpp b/src/collision.cpp index 18c49ce..fc67eab 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -9,81 +9,79 @@ /** * Détermination des informations sur une collision entre - * un joueur et un bloc (normale et profondeur de collision) + * un cercle et un rectangle */ -bool playerToBlock(CollisionData& data) { - Player player = dynamic_cast(data.objA); - Block block = dynamic_cast(data.objB); +bool circleToAABB(CollisionData& data) { + Object& circle = data.obj_a; + Object& aabb = data.obj_b; - // recherche du point le plus proche du centre de la - // balle sur le bloc. On regarde la position relative - // du cercle par rapport au bloc - std::unique_ptr aabb = block.getAABB(); - sf::Vector2f relpos = block.getPosition() - player.getPosition(); + // recherche du point le plus proche du centre du cercle + // sur le rectangle. On regarde la position relative du cercle + // par rapport au rectangle + std::unique_ptr box = aabb.getAABB(); + sf::Vector2f relpos = aabb.getPosition() - circle.getPosition(); sf::Vector2f closest = relpos; // on restreint la position relative pour rester - // à l'intérieur du bloc - if (closest.x < -aabb->width / 2) { - closest.x = -aabb->width / 2; + // à l'intérieur du rectangle + if (closest.x < -box->width / 2) { + closest.x = -box->width / 2; } - if (closest.x > aabb->width / 2) { - closest.x = aabb->width / 2; + if (closest.x > box->width / 2) { + closest.x = box->width / 2; } - if (closest.y < -aabb->height / 2) { - closest.y = -aabb->height / 2; + if (closest.y < -box->height / 2) { + closest.y = -box->height / 2; } - if (closest.y > aabb->height / 2) { - closest.y = aabb->height / 2; + if (closest.y > box->height / 2) { + closest.y = box->height / 2; } - // si la position n'a pas été changée, elle - // était déjà à l'intérieur du cercle : le cercle - // est dans le bloc - float isInside = false; + // si la position n'a pas été changée, elle était déjà + // à l'intérieur du cercle : le cercle est dans le rectangle + float is_inside = false; if (relpos == closest) { - isInside = true; + is_inside = true; - // on se colle au bord le plus proche du bloc + // on se colle au bord le plus proche du rectangle if (std::abs(relpos.x) > std::abs(relpos.y)) { if (closest.x > 0) { - closest.x = aabb->width / 2; + closest.x = box->width / 2; } else { - closest.x = -aabb->width / 2; + closest.x = -box->width / 2; } } else { if (closest.y > 0) { - closest.y = aabb->height / 2; + closest.y = box->height / 2; } else { - closest.y = -aabb->height / 2; + closest.y = -box->height / 2; } } } // la normale est portée par la direction - // du point le plus proche au centre de la balle + // du point le plus proche au centre du cercle sf::Vector2f prenormal = relpos - closest; - float squaredLength = prenormal.x * prenormal.x + prenormal.y * prenormal.y; + float squared_length = prenormal.x * prenormal.x + prenormal.y * prenormal.y; - // si la balle est à l'extérieur et que - // la normale est plus longue que son rayon, - // il n'y a pas collision - if (!isInside && squaredLength >= player.getRadius() * player.getRadius()) { + // si le cercle est à l'extérieur et que la normale est plus + // longue que son rayon, il n'y a pas collision + if (!is_inside && squared_length >= circle.getRadius() * circle.getRadius()) { return false; } - float length = std::sqrt(squaredLength); - data.depth = player.getRadius() - length; + float length = std::sqrt(squared_length); + data.depth = circle.getRadius() - length; if (length != 0) { data.normal = prenormal / length; } - if (isInside) { + if (is_inside) { data.normal *= -1.f; } @@ -92,66 +90,66 @@ bool playerToBlock(CollisionData& data) { /** * Détermination des informations sur une collision entre - * un bloc et un joueur (normale et profondeur de collision) + * un rectangle et un cercle */ -bool blockToPlayer(CollisionData& data) { - // la collision Block -> Player est la collision Player -> Block - Object& objT = data.objB; - data.objB = data.objA; - data.objA = objT; +bool AABBToCircle(CollisionData& data) { + // la collision rectangle -> cercle est la collision cercle -> rectangle + Object& transfer = data.obj_b; + data.obj_b = data.obj_a; + data.obj_a = transfer; - return playerToBlock(data); + return circleToAABB(data); } /** * Détermination des informations sur une collision entre - * deux joueurs (normale et profondeur de collision) + * deux cercles */ -bool playerToPlayer(CollisionData& data) { - Player playerA = dynamic_cast(data.objA); - Player playerB = dynamic_cast(data.objB); +bool circleToCircle(CollisionData& data) { + Object& circle_a = data.obj_a; + Object& circle_b = data.obj_b; - sf::Vector2f dir = playerB.getPosition() - playerA.getPosition(); - float squaredLength = dir.x * dir.x + dir.y * dir.y; - float totalRadius = playerB.getRadius() + playerA.getRadius(); + sf::Vector2f dir = circle_b.getPosition() - circle_a.getPosition(); + float squared_length = dir.x * dir.x + dir.y * dir.y; + float total_radius = circle_b.getRadius() + circle_a.getRadius(); - // si les deux balles sont à une distance supérieure + // si les deux cercles sont à une distance supérieure // à la somme de leurs deux rayons, il n'y a pas eu collision - if (squaredLength > totalRadius * totalRadius) { + if (squared_length > total_radius * total_radius) { return false; } - float length = std::sqrt(squaredLength); + float length = std::sqrt(squared_length); - // les balles sont sur la même position. - // Renvoie une normale apte à séparer les deux balles + // les cercles sont sur la même position. + // Renvoie une normale apte à séparer les deux cercles if (length == 0) { - data.depth = totalRadius; + data.depth = total_radius; data.normal.x = 0; data.normal.y = -1; return true; } // il y a eu collision - data.depth = totalRadius - length; + data.depth = total_radius - length; data.normal = dir / length; return true; } /** * Détermination des informations sur une collision entre - * deux blocs (normale et profondeur de collision) + * deux rectangles */ -bool blockToBlock(CollisionData& data) { - Block blockA = dynamic_cast(data.objA); - Block blockB = dynamic_cast(data.objB); +bool AABBToAABB(CollisionData& data) { + Object& aabb_a = data.obj_a; + Object& aabb_b = data.obj_b; - std::unique_ptr aabb = blockA.getAABB(); - std::unique_ptr obj_aabb = blockB.getAABB(); - sf::Vector2f relpos = blockB.getPosition() - blockA.getPosition(); + std::unique_ptr box_a = aabb_a.getAABB(); + std::unique_ptr box_b = aabb_b.getAABB(); + sf::Vector2f relpos = aabb_b.getPosition() - aabb_a.getPosition(); - float overlap_x = aabb->width / 2 + obj_aabb->width / 2 - std::abs(relpos.x); - float overlap_y = aabb->height / 2 + obj_aabb->height / 2 - std::abs(relpos.y); + float overlap_x = box_a->width / 2 + box_b->width / 2 - std::abs(relpos.x); + float overlap_y = box_a->height / 2 + box_b->height / 2 - std::abs(relpos.y); // si il n'y a pas de chauvauchement sur l'axe X et Y, pas de collision if (overlap_x <= 0 || overlap_y <= 0) { @@ -187,26 +185,19 @@ bool blockToBlock(CollisionData& data) { * dans une collision à leur fonction de résolution */ std::map< - std::pair, + std::pair, std::function > collision_map = { - {std::make_pair(Player::TYPE_ID, Player::TYPE_ID), playerToPlayer}, - {std::make_pair(Player::TYPE_ID, Block::TYPE_ID), playerToBlock}, - {std::make_pair(Player::TYPE_ID, GravityBlock::TYPE_ID), playerToBlock}, - {std::make_pair(Block::TYPE_ID, Block::TYPE_ID), blockToBlock}, - {std::make_pair(Block::TYPE_ID, GravityBlock::TYPE_ID), blockToBlock}, - {std::make_pair(Block::TYPE_ID, Player::TYPE_ID), blockToPlayer}, - {std::make_pair(GravityBlock::TYPE_ID, Block::TYPE_ID), blockToBlock}, - {std::make_pair(GravityBlock::TYPE_ID, GravityBlock::TYPE_ID), blockToBlock}, - {std::make_pair(GravityBlock::TYPE_ID, Player::TYPE_ID), blockToPlayer} + {std::make_pair(CollisionType::CIRCLE, CollisionType::CIRCLE), circleToCircle}, + {std::make_pair(CollisionType::CIRCLE, CollisionType::AABB), circleToAABB}, + {std::make_pair(CollisionType::AABB, CollisionType::AABB), AABBToAABB}, + {std::make_pair(CollisionType::AABB, CollisionType::CIRCLE), AABBToCircle} }; -CollisionData::CollisionData(Object& objA, Object& objB) : - objA(objA), objB(objB) {} - +CollisionData::CollisionData(Object& obj_a, Object& obj_b) : obj_a(obj_a), obj_b(obj_b) {} bool getCollisionData(CollisionData& data) { return collision_map[std::make_pair( - data.objA.getTypeId(), - data.objB.getTypeId() + data.obj_a.getCollisionType(), + data.obj_b.getCollisionType() )](data); } diff --git a/src/game.cpp b/src/game.cpp index 7d11f82..6bd5c47 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -91,13 +91,13 @@ void Game::update() { // détection des objets en collision for (unsigned int i = 0; i < getObjects().size(); i++) { - ObjectPtr objA = getObjects()[i]; + ObjectPtr obj_a = getObjects()[i]; for (unsigned int j = i + 1; j < getObjects().size(); j++) { - ObjectPtr objB = getObjects()[j]; - CollisionData data(*objA, *objB); + ObjectPtr obj_b = getObjects()[j]; + CollisionData data(*obj_a, *obj_b); - if (objA->detectCollision(*objB, data)) { + if (obj_a->detectCollision(*obj_b, data)) { colliding.push_back(data); } } @@ -111,7 +111,7 @@ void Game::update() { // résolution des collisions détectées for (unsigned int i = 0; i < colliding.size(); i++) { CollisionData& collided = colliding[i]; - collided.objA.solveCollision(*this, collided.objB, collided.normal); + collided.obj_a.solveCollision(*this, collided.obj_b, collided.normal); } // intégration de la vitesse dans la position @@ -122,8 +122,8 @@ void Game::update() { // 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 + collided.obj_a.positionalCorrection( + collided.obj_b, collided.normal, collided.depth ); } } diff --git a/src/player.cpp b/src/player.cpp index 56cfd95..2b3988d 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -108,12 +108,16 @@ std::unique_ptr Player::getAABB() const { )); } +float Player::getRadius() const { + return 10 * getMass(); +} + unsigned int Player::getTypeId() const { return TYPE_ID; } -float Player::getRadius() const { - return 10 * getMass(); +CollisionType Player::getCollisionType() const { + return CollisionType::CIRCLE; } unsigned int Player::getPlayerNumber() const {