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();
|
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 getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth);
|
||||||
virtual bool getNormal(Ball& obj, sf::Vector2f& normal);
|
virtual bool getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth);
|
||||||
virtual bool getNormal(Block& obj, sf::Vector2f& normal);
|
virtual bool getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,11 +25,12 @@ public:
|
||||||
std::unique_ptr<sf::FloatRect> getAABB();
|
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 getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth);
|
||||||
virtual bool getNormal(Ball& obj, sf::Vector2f& normal);
|
virtual bool getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth);
|
||||||
virtual bool getNormal(Block& obj, sf::Vector2f& normal);
|
virtual bool getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,6 +28,13 @@ namespace Constants {
|
||||||
* Taille de la grille des blocs en pixels
|
* Taille de la grille des blocs en pixels
|
||||||
*/
|
*/
|
||||||
static constexpr float GRID = 32;
|
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
|
#endif
|
||||||
|
|
|
@ -49,11 +49,19 @@ public:
|
||||||
virtual std::unique_ptr<sf::FloatRect> getAABB() = 0;
|
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 getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth);
|
||||||
virtual bool getNormal(Ball& obj, sf::Vector2f& normal) = 0;
|
virtual bool getCollisionInfo(Ball& obj, sf::Vector2f& normal, float& depth) = 0;
|
||||||
virtual bool getNormal(Block& obj, sf::Vector2f& normal) = 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
|
* Récupère l'accélération de l'objet
|
||||||
|
@ -76,6 +84,12 @@ public:
|
||||||
*/
|
*/
|
||||||
sf::Vector2f getPosition();
|
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
|
* 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) {
|
bool Ball::getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth) {
|
||||||
return obj.getNormal(*this, normal);
|
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();
|
sf::Vector2f dir = obj.getPosition() - getPosition();
|
||||||
float squaredLength = dir.x * dir.x + dir.y * dir.y;
|
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.
|
// les balles sont sur la même position.
|
||||||
// Renvoie une normale apte à séparer les deux balles
|
// Renvoie une normale apte à séparer les deux balles
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
|
// TODO: supprimer les valeurs magiques
|
||||||
|
depth = 10;
|
||||||
normal.x = 0;
|
normal.x = 0;
|
||||||
normal.y = -1;
|
normal.y = -1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: supprimer les valeurs magiques
|
||||||
// il y a eu collision
|
// il y a eu collision
|
||||||
|
depth = 10 - length;
|
||||||
normal = dir / length;
|
normal = dir / length;
|
||||||
return true;
|
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
|
// recherche du point le plus proche du centre de la
|
||||||
// balle sur le bloc. On regarde la position relative
|
// balle sur le bloc. On regarde la position relative
|
||||||
// du cercle par rapport au bloc
|
// 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
|
// si la balle est à l'extérieur et que
|
||||||
// la normale est plus longue que son rayon,
|
// la normale est plus longue que son rayon,
|
||||||
// il n'y a pas collision
|
// il n'y a pas collision
|
||||||
if (!isInside && squaredLength >= 20 * 20) {
|
if (!isInside && squaredLength >= 10 * 10) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
normal = prenormal / std::sqrt(squaredLength);
|
float length = std::sqrt(squaredLength);
|
||||||
|
depth = 10 - length;
|
||||||
|
normal = prenormal / length;
|
||||||
|
|
||||||
if (isInside) {
|
if (isInside) {
|
||||||
normal *= -1.f;
|
normal *= -1.f;
|
||||||
|
|
|
@ -41,16 +41,16 @@ std::unique_ptr<sf::FloatRect> Block::getAABB() {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Block::getNormal(Object& obj, sf::Vector2f& normal) {
|
bool Block::getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth) {
|
||||||
return obj.getNormal(*this, normal);
|
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
|
// TODO: coder cette fonction
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Block::getNormal(Block& obj, sf::Vector2f& normal) {
|
bool Block::getCollisionInfo(Block& obj, sf::Vector2f& normal, float& depth) {
|
||||||
// TODO: coder cette fonction
|
// TODO: coder cette fonction
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,43 +55,7 @@ void Engine::update() {
|
||||||
|
|
||||||
for (unsigned int j = i + 1; j < state.objects.size(); j++) {
|
for (unsigned int j = i + 1; j < state.objects.size(); j++) {
|
||||||
Object* objB = state.objects[j];
|
Object* objB = state.objects[j];
|
||||||
|
objA->collide(*objB);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,61 @@ void Object::update(EngineState& state) {
|
||||||
velocity += acceleration * state.delta;
|
velocity += acceleration * state.delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Object::getNormal(Object& obj, sf::Vector2f& normal) {
|
bool Object::getCollisionInfo(Object& obj, sf::Vector2f& normal, float& depth) {
|
||||||
return obj.getNormal(*this, normal);
|
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() {
|
sf::Vector2f Object::getAcceleration() {
|
||||||
|
@ -68,6 +121,10 @@ sf::Vector2f Object::getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Object::setPosition(sf::Vector2f set_position) {
|
||||||
|
position = set_position;
|
||||||
|
}
|
||||||
|
|
||||||
float Object::getMass() {
|
float Object::getMass() {
|
||||||
return mass;
|
return mass;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue