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