Correction des collisions
Ajout de la correction positionelle, correction du rayon de détection
This commit is contained in:
		
							parent
							
								
									80a9a2ef26
								
							
						
					
					
						commit
						db18959575
					
				|  | @ -31,11 +31,12 @@ public: | |||
|     std::unique_ptr<sf::FloatRect> getAABB(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Calcule la normale de la collision de cet objet avec un autre | ||||
|      * Calcule les informations sur une éventuelle collision de | ||||
|      * cet objet avec un autre : la normale et la profondeur | ||||
|      */ | ||||
|     virtual bool getNormal(Object& obj, sf::Vector2f& normal); | ||||
|     virtual bool getNormal(Ball& obj, sf::Vector2f& normal); | ||||
|     virtual bool getNormal(Block& obj, sf::Vector2f& normal); | ||||
|     virtual bool getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth); | ||||
|     virtual bool getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth); | ||||
|     virtual bool getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -25,11 +25,12 @@ public: | |||
|     std::unique_ptr<sf::FloatRect> getAABB(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Calcule la normale de la collision de cet objet avec un autre | ||||
|      * Calcule les informations sur une éventuelle collision de | ||||
|      * cet objet avec un autre : la normale et la profondeur | ||||
|      */ | ||||
|     virtual bool getNormal(Object& obj, sf::Vector2f& normal); | ||||
|     virtual bool getNormal(Ball& obj, sf::Vector2f& normal); | ||||
|     virtual bool getNormal(Block& obj, sf::Vector2f& normal); | ||||
|     virtual bool getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth); | ||||
|     virtual bool getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth); | ||||
|     virtual bool getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -28,6 +28,13 @@ namespace Constants { | |||
|      * Taille de la grille des blocs en pixels | ||||
|      */ | ||||
|     static constexpr float GRID = 32; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Correction positionnelle : pourcentage de correction | ||||
|      * et seuil de correction | ||||
|      */ | ||||
|     static constexpr float CORRECTION_PERCENTAGE = .2f; | ||||
|     static constexpr float CORRECTION_THRESHOLD = .01f; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -49,11 +49,19 @@ public: | |||
|     virtual std::unique_ptr<sf::FloatRect> getAABB() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Calcule la normale de la collision de cet objet avec un autre | ||||
|      * Calcule les informations sur une éventuelle collision de | ||||
|      * cet objet avec un autre : la normale et la profondeur | ||||
|      */ | ||||
|     virtual bool getNormal(Object& obj, sf::Vector2f& normal); | ||||
|     virtual bool getNormal(Ball& obj, sf::Vector2f& normal) = 0; | ||||
|     virtual bool getNormal(Block& obj, sf::Vector2f& normal) = 0; | ||||
|     virtual bool getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth); | ||||
|     virtual bool getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth) = 0; | ||||
|     virtual bool getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth) = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Détecte s'il y a collision entre cet objet | ||||
|      * et l'objet passé en paramètre et résoud la collision | ||||
|      * si elle a lieu | ||||
|      */ | ||||
|     void collide(Object& obj); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Récupère l'accélération de l'objet | ||||
|  | @ -76,6 +84,12 @@ public: | |||
|      */ | ||||
|     sf::Vector2f getPosition(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Modifie la position de l'objet | ||||
|      * (à utiliser avec précaution, préférer modifier les forces) | ||||
|      */ | ||||
|     void setPosition(sf::Vector2f set_position); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Récupère la masse de l'objet | ||||
|      */ | ||||
|  |  | |||
							
								
								
									
										18
									
								
								src/ball.cpp
								
								
								
								
							
							
						
						
									
										18
									
								
								src/ball.cpp
								
								
								
								
							|  | @ -76,11 +76,11 @@ std::unique_ptr<sf::FloatRect> Ball::getAABB() { | |||
|     )); | ||||
| } | ||||
| 
 | ||||
| bool Ball::getNormal(Object& obj, sf::Vector2f& normal) { | ||||
|     return obj.getNormal(*this, normal); | ||||
| bool Ball::getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth) { | ||||
|     return obj.getCollisionInfo(*this, normal, depth); | ||||
| } | ||||
| 
 | ||||
| bool Ball::getNormal(Ball& obj, sf::Vector2f& normal) { | ||||
| bool Ball::getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth) { | ||||
|     sf::Vector2f dir = obj.getPosition() - getPosition(); | ||||
|     float squaredLength = dir.x * dir.x + dir.y * dir.y; | ||||
| 
 | ||||
|  | @ -96,17 +96,21 @@ bool Ball::getNormal(Ball& obj, sf::Vector2f& normal) { | |||
|     // les balles sont sur la même position.
 | ||||
|     // Renvoie une normale apte à séparer les deux balles
 | ||||
|     if (length == 0) { | ||||
|         // TODO: supprimer les valeurs magiques
 | ||||
|         depth = 10; | ||||
|         normal.x = 0; | ||||
|         normal.y = -1; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // TODO: supprimer les valeurs magiques
 | ||||
|     // il y a eu collision
 | ||||
|     depth = 10 - length; | ||||
|     normal = dir / length; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool Ball::getNormal(Block& obj, sf::Vector2f& normal) { | ||||
| bool Ball::getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth) { | ||||
|     // 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
 | ||||
|  | @ -165,11 +169,13 @@ bool Ball::getNormal(Block& obj, sf::Vector2f& normal) { | |||
|     // 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 >= 20 * 20) { | ||||
|     if (!isInside && squaredLength >= 10 * 10) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     normal = prenormal / std::sqrt(squaredLength); | ||||
|     float length = std::sqrt(squaredLength); | ||||
|     depth = 10 - length; | ||||
|     normal = prenormal / length; | ||||
| 
 | ||||
|     if (isInside) { | ||||
|         normal *= -1.f; | ||||
|  |  | |||
|  | @ -41,16 +41,16 @@ std::unique_ptr<sf::FloatRect> Block::getAABB() { | |||
|     )); | ||||
| } | ||||
| 
 | ||||
| bool Block::getNormal(Object& obj, sf::Vector2f& normal) { | ||||
|     return obj.getNormal(*this, normal); | ||||
| bool Block::getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth) { | ||||
|     return obj.getCollisionInfo(*this, normal, depth); | ||||
| } | ||||
| 
 | ||||
| bool Block::getNormal(Ball& obj, sf::Vector2f& normal) { | ||||
| bool Block::getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth) { | ||||
|     // TODO: coder cette fonction
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool Block::getNormal(Block& obj, sf::Vector2f& normal) { | ||||
| bool Block::getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth) { | ||||
|     // TODO: coder cette fonction
 | ||||
|     return false; | ||||
| } | ||||
|  |  | |||
|  | @ -55,43 +55,7 @@ void Engine::update() { | |||
| 
 | ||||
|         for (unsigned int j = i + 1; j < state.objects.size(); j++) { | ||||
|             Object* objB = state.objects[j]; | ||||
| 
 | ||||
|             // si les objets ne sont pas sur la même couche,
 | ||||
|             // ils ne peuvent pas entrer en collision
 | ||||
|             if (objA->getLayer() != objB->getLayer()) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             // 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; | ||||
|             } | ||||
| 
 | ||||
|             // calcule et applique l'impulsion de résolution de la collision
 | ||||
|             float restitution = std::min(objA->getRestitution(), objB->getRestitution()); | ||||
|             float impulse = (-(1 + restitution) * dotnormal) / | ||||
|                 (objA->getMassInvert() + objB->getMassInvert()); | ||||
| 
 | ||||
|             objA->setVelocity(objA->getVelocity() - objA->getMassInvert() * impulse * normal); | ||||
|             objB->setVelocity(objB->getVelocity() + objB->getMassInvert() * impulse * normal); | ||||
|             objA->collide(*objB); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -48,8 +48,61 @@ void Object::update(EngineState& state) { | |||
|     velocity += acceleration * state.delta; | ||||
| } | ||||
| 
 | ||||
| bool Object::getNormal(Object& obj, sf::Vector2f& normal) { | ||||
|     return obj.getNormal(*this, normal); | ||||
| bool Object::getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth) { | ||||
|     return obj.getCollisionInfo(*this, normal, depth); | ||||
| } | ||||
| 
 | ||||
| void Object::collide(Object& obj) { | ||||
|     // si les objets ne sont pas sur la même couche,
 | ||||
|     // ils ne peuvent pas entrer en collision
 | ||||
|     if (getLayer() != obj.getLayer()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // si les deux boîtes englobantes des deux objets, ne
 | ||||
|     // s'intersectent pas, il ne risque pas d'y avoir de collision
 | ||||
|     if (!getAABB()->intersects(*obj.getAABB())) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     sf::Vector2f normal; | ||||
|     float depth; | ||||
| 
 | ||||
|     // vérifie plus finement s'il y a collision et récupère
 | ||||
|     // les informations sur la collision (normale et profondeur)
 | ||||
|     if (!getCollisionInfo(obj, normal, depth)) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     sf::Vector2f codir = obj.getVelocity() - 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) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // calcule et applique l'impulsion de résolution de la collision
 | ||||
|     float restitution = std::min(getRestitution(), obj.getRestitution()); | ||||
|     float impulse = (-(1 + restitution) * dotnormal) / | ||||
|         (getMassInvert() + obj.getMassInvert()); | ||||
| 
 | ||||
|     setVelocity(getVelocity() - getMassInvert() * impulse * normal); | ||||
|     obj.setVelocity(obj.getVelocity() + obj.getMassInvert() * impulse * normal); | ||||
| 
 | ||||
|     // correction de la position des objets. En raison de l'imprécision
 | ||||
|     // des flottants sur la machine, les objets peuvent accumuler une
 | ||||
|     // erreur de positionnement qui les fait "plonger" les un dans les autres.
 | ||||
|     if (depth <= Constants::CORRECTION_THRESHOLD) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     sf::Vector2f positionCorrection = depth / (getMassInvert() + | ||||
|         obj.getMassInvert()) * Constants::CORRECTION_PERCENTAGE * normal; | ||||
| 
 | ||||
|     setPosition(getPosition() - getMassInvert() * positionCorrection); | ||||
|     obj.setPosition(obj.getPosition() + obj.getMassInvert() * positionCorrection); | ||||
| } | ||||
| 
 | ||||
| sf::Vector2f Object::getAcceleration() { | ||||
|  | @ -68,6 +121,10 @@ sf::Vector2f Object::getPosition() { | |||
|     return position; | ||||
| } | ||||
| 
 | ||||
| void Object::setPosition(sf::Vector2f set_position) { | ||||
|     position = set_position; | ||||
| } | ||||
| 
 | ||||
| float Object::getMass() { | ||||
|     return mass; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue