skizzle/src/object.cpp

254 lines
7.6 KiB
C++
Raw Normal View History

2016-03-08 17:07:09 +00:00
#include "object.hpp"
#include "constants.hpp"
2016-03-08 17:07:09 +00:00
Object::Object(float x, float y) :
acceleration(0, 0), velocity(0, 0), position(x, y),
2016-03-20 21:21:01 +00:00
acceleration_line(sf::Lines, 2),
velocity_line(sf::Lines, 2),
mass(Constants::DEFAULT_MASS),
inv_mass(1.f / Constants::DEFAULT_MASS),
charge(Constants::DEFAULT_CHARGE),
restitution(Constants::DEFAULT_RESTITUTION),
2016-03-20 21:21:01 +00:00
static_friction(0.4f),
dynamic_friction(0.2f),
layer(Constants::DEFAULT_LAYER) {}
sf::Vector2f Object::getForces(EngineState& state) {
sf::Vector2f forces(0, 0);
// force de gravité
forces += sf::Vector2f(0, Constants::GRAVITY);
2016-03-19 14:38:08 +00:00
// force d'attraction entre objets chargés
if (getCharge() != 0) {
for (unsigned int j = 0; j < state.objects.size(); j++) {
Object *attractive = state.objects[j];
if (attractive == this || attractive->getCharge() == 0) {
continue;
}
// vecteur allant de l'objet attracteur vers l'objet actuel
sf::Vector2f attraction(getPosition() - attractive->getPosition());
// la norme de ce vecteur est la distance entre les objets
2016-03-20 21:21:01 +00:00
float distance_squared = attraction.x * attraction.x +
2016-03-19 14:38:08 +00:00
attraction.y * attraction.y;
// éviter la division par zéro
2016-03-20 21:21:01 +00:00
if (distance_squared == 0) {
2016-03-19 14:38:08 +00:00
continue;
}
// normalisation du vecteur direction qui porte
// la force d'attraction, puis application de la norme
2016-03-20 21:21:01 +00:00
attraction /= std::sqrt(distance_squared);
2016-03-19 14:38:08 +00:00
attraction *= Constants::ATTRACTION * (
(getCharge() * attractive->getCharge()) /
2016-03-20 21:21:01 +00:00
distance_squared
2016-03-19 14:38:08 +00:00
);
forces += attraction;
}
}
return forces;
}
void Object::draw(sf::RenderWindow& window, ResourceManager& resources) {
2016-03-18 18:14:08 +00:00
if (Constants::DEBUG_MODE) {
2016-03-20 21:21:01 +00:00
velocity_line[0].position = position;
velocity_line[0].color = sf::Color::Green;
velocity_line[1].position = position + velocity * 1.f;
velocity_line[1].color = sf::Color::Green;
acceleration_line[0].position = position;
acceleration_line[0].color = sf::Color::Red;
acceleration_line[1].position = position + acceleration * 1.f;
acceleration_line[1].color = sf::Color::Red;
window.draw(velocity_line);
window.draw(acceleration_line);
2016-03-18 18:14:08 +00:00
}
}
void Object::update(EngineState& state) {
// intégration de la vitesse dans la position
position += velocity * Constants::PHYSICS_TIME;
// intégration des forces appliquées sur l'objet dans la vitesse
2016-03-20 21:21:01 +00:00
acceleration = getForces(state) * getMassInvert();
velocity += acceleration * Constants::PHYSICS_TIME;
}
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;
}
2016-03-20 21:21:01 +00:00
sf::Vector2f rel_velo = obj.getVelocity() - getVelocity();
float dot_normal = rel_velo.x * normal.x + rel_velo.y * normal.y;
// si les directions sont divergentes, pas besoin
// de résoudre la collision
2016-03-20 21:21:01 +00:00
if (dot_normal >= 0) {
return;
}
// calcule et applique l'impulsion de résolution de la collision
float restitution = std::min(getRestitution(), obj.getRestitution());
2016-03-20 21:21:01 +00:00
float collision_impulse = (-(1 + restitution) * dot_normal) /
(getMassInvert() + obj.getMassInvert());
setVelocity(getVelocity() - getMassInvert() * collision_impulse * normal);
obj.setVelocity(obj.getVelocity() + obj.getMassInvert() * collision_impulse * normal);
// application des forces de frottement entre les deux objets
// on calcule le vecteur tangent qui porte la force de frottement.
// les coefficients de friction utilisés sont les moyennes de ceux des deux objets
rel_velo = obj.getVelocity() - getVelocity();
dot_normal = rel_velo.x * normal.x + rel_velo.y * normal.y;
sf::Vector2f tangent = rel_velo - dot_normal * normal;
float tangent_length = std::sqrt(tangent.x * tangent.x + tangent.y * tangent.y);
tangent /= tangent_length;
float magnitude = -(rel_velo.x * tangent.x + rel_velo.y * tangent.y) /
(getMassInvert() + obj.getMassInvert());
2016-03-20 21:21:01 +00:00
float static_friction = (getStaticFriction() + obj.getStaticFriction()) / 2.f;
float dynamic_friction = (getDynamicFriction() + obj.getDynamicFriction()) / 2.f;
float friction_impulse;
// utilisation de la loi de Coulomb sur les frottements dynamiques/statiques
// cf https://fr.wikipedia.org/wiki/Loi_de_Coulomb_(m%C3%A9canique)
if (std::abs(magnitude) < collision_impulse * static_friction) {
friction_impulse = magnitude;
} else {
friction_impulse = -collision_impulse * dynamic_friction;
}
2016-03-20 21:21:01 +00:00
setVelocity(getVelocity() - getMassInvert() * friction_impulse * tangent);
obj.setVelocity(obj.getVelocity() + obj.getMassInvert() * friction_impulse * tangent);
// 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;
}
2016-03-20 21:21:01 +00:00
float position_correction = depth / (getMassInvert() + obj.getMassInvert()) *
Constants::CORRECTION_PERCENTAGE;
2016-03-20 21:21:01 +00:00
setPosition(getPosition() - getMassInvert() * position_correction * normal);
obj.setPosition(obj.getPosition() + obj.getMassInvert() * position_correction * normal);
}
sf::Vector2f Object::getAcceleration() {
return acceleration;
}
sf::Vector2f Object::getVelocity() {
return velocity;
}
void Object::setVelocity(sf::Vector2f set_velocity) {
velocity = set_velocity;
}
2016-03-08 17:07:09 +00:00
sf::Vector2f Object::getPosition() {
return position;
}
void Object::setPosition(sf::Vector2f set_position) {
position = set_position;
}
float Object::getMass() {
return mass;
}
2016-03-15 21:09:40 +00:00
float Object::getMassInvert() {
if (inv_mass >= 0) {
return inv_mass;
}
if (mass == 0) {
inv_mass = 0;
return inv_mass;
}
inv_mass = 1 / mass;
return inv_mass;
}
void Object::setMass(float set_mass) {
mass = set_mass;
2016-03-15 21:09:40 +00:00
inv_mass = -1.f;
}
2016-03-14 20:43:27 +00:00
float Object::getCharge() {
2016-03-08 17:07:09 +00:00
return charge;
}
2016-03-14 20:43:27 +00:00
void Object::setCharge(float set_charge) {
charge = set_charge;
}
float Object::getRestitution() {
return restitution;
}
void Object::setRestitution(float set_restitution) {
restitution = set_restitution;
}
2016-03-20 21:21:01 +00:00
float Object::getStaticFriction() {
return static_friction;
}
void Object::setStaticFriction(float set_static_friction) {
static_friction = set_static_friction;
}
float Object::getDynamicFriction() {
return dynamic_friction;
}
void Object::setDynamicFriction(float set_dynamic_friction) {
dynamic_friction = set_dynamic_friction;
}
unsigned int Object::getLayer() {
return layer;
}
void Object::setLayer(unsigned int set_layer) {
layer = set_layer;
}
bool ObjectCompare::operator()(Object* const &t1, Object* const &t2) {
return t1->getLayer() > t2->getLayer();
}