Zenn_

CollisionSystem.cpp

Aug 21st, 2019
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.68 KB | None | 0 0
  1. #include <math.h>
  2. #include <iostream>
  3. #include "CollisionSystem.h"
  4. #include "ECS.h"
  5. #include "GameData.h"
  6. #include "CONFIG.h"
  7. #include "EnabledSystem.h"
  8. #include "PositionSystem.h"
  9. #include "VelocitySystem.h"
  10. #include "BoundsSystem.h"
  11.  
  12. namespace station {
  13.     CollisionSystem::CollisionSystem(GameData* DATA) : System(DATA) {
  14.  
  15.     }
  16.     CollisionSystem::~CollisionSystem() {
  17.  
  18.     }
  19.  
  20.     void CollisionSystem::init() {
  21.  
  22.     }
  23.     void CollisionSystem::update(float dt) {
  24.         //set all grounded flags to false first
  25.         for (int i = 0; i < components.size(); i++) {
  26.             components.at(i)->groundedOnEntity = false;
  27.         }
  28.         for (int i = 0; i < components.size(); i++) {
  29.             for (int i2 = i; i2 < components.size(); i2++) {
  30.                 if (!DEBUG_DISABLECOLLISION && i != i2) {
  31.                     IFDISABLED(components.at(i)->getCompID())
  32.                         IFDISABLED(components.at(i2)->getCompID()) continue;
  33.  
  34.                     if (components.at(i)->staticCollider && components.at(i2)->staticCollider) continue;
  35.  
  36.                     pos1 = data->ecs->positionSystem->getComp(components.at(i)->getCompID());
  37.                     pos2 = data->ecs->positionSystem->getComp(components.at(i2)->getCompID());
  38.                     bounds1 = data->ecs->boundsSystem->getComp(components.at(i)->getCompID());
  39.                     bounds2 = data->ecs->boundsSystem->getComp(components.at(i2)->getCompID());
  40.                     v1 = data->ecs->velocitySystem->getComp(components.at(i)->getCompID());
  41.                     v2 = data->ecs->velocitySystem->getComp(components.at(i2)->getCompID());
  42.  
  43.                     if (COLLISIONSYSTEM_EXCESSIVEDEBUG && !COLLISIONSYSTEM_IGNOREII) std::cout << "Checking intersections:\n";
  44.                     //detect collision
  45.                     IntersectionInfo ii = detectCollision(i, i2);
  46.                     //collision detected?
  47.                     if (ii.collided) {
  48.                         //resolve collision
  49.                         resolveCollision(ii, i, i2);
  50.                         correctPosition(ii, i, i2);
  51.                     }
  52.                 }
  53.             }
  54.         }
  55.     }
  56.     void CollisionSystem::draw(sf::RenderTarget &target, sf::RenderStates states) const {
  57.         if (DEBUG_DRAWCOLLIDERS) {
  58.             sf::Vertex line[4];
  59.             for (CollisionComponent* v : components) {
  60.                 IFDISABLED(v->getCompID()) continue;
  61.                 PositionComponent* p = data->ecs->positionSystem->
  62.                     getComp(v->getCompID());
  63.                 BoundsComponent* b = data->ecs->boundsSystem->
  64.                     getComp(v->getCompID());
  65.                 sf::Color crossColor;
  66.                 if (v->staticCollider) crossColor = sf::Color(255, 0, 0);
  67.                 else crossColor = sf::Color(0, 255, 0);
  68.                 //top left to bottom right
  69.                 line[0].position.x = p->position.x - (b->bounds.x / 2);
  70.                 line[0].position.y = p->position.y - (b->bounds.y / 2);
  71.                 line[0].color = crossColor;
  72.                 line[1].position.x = p->position.x + (b->bounds.x / 2);
  73.                 line[1].position.y = p->position.y + (b->bounds.y / 2);
  74.                 line[1].color = crossColor;
  75.                 //bottom left to top right
  76.                 line[2].position.x = p->position.x - (b->bounds.x / 2);
  77.                 line[2].position.y = p->position.y + (b->bounds.y / 2);
  78.                 line[2].color = crossColor;
  79.                 line[3].position.x = p->position.x + (b->bounds.x / 2);
  80.                 line[3].position.y = p->position.y - (b->bounds.y / 2);
  81.                 line[3].color = crossColor;
  82.                 target.draw(line, (sizeof(line) / sizeof(*line)), sf::Lines);
  83.             }
  84.         }
  85.     }
  86.  
  87.  
  88. #pragma region collision detection
  89.     IntersectionInfo CollisionSystem::detectCollision(int componentat1, int componentat2) {
  90.         if (COLLISIONSYSTEM_EXCESSIVEDEBUG && !COLLISIONSYSTEM_IGNOREII)
  91.             std::cout << "Testing intersection between entity " << componentat1 << " and " << componentat2 << '\n';
  92.  
  93.         IntersectionInfo ii;
  94.  
  95.         //calculate directional vector from collider 1 to 2
  96.         sf::Vector2f dir(pos1->position.x - pos2->position.x, pos1->position.y - pos2->position.y);
  97.         /*this is the part where im admitting that i tried to do collision myself and utterly failed
  98.         as one can see in the CollisionComponent.cppold file. This code is closely following the code
  99.         showed by Randy Gaul on his AABB collision tutsplus blogpost. https://goo.gl/5q4DPN */
  100.         //overlap between the two colliders in the x axis
  101.         float x_overlap = (bounds1->bounds.x * 0.5f) + (bounds2->bounds.x * 0.5f) - abs(dir.x);
  102.         //overlap between the two colliders in the y axis
  103.         float y_overlap = (bounds1->bounds.y * 0.5f) + (bounds2->bounds.y * 0.5f) - abs(dir.y);
  104.         if (false || (COLLISIONSYSTEM_EXCESSIVEDEBUG && !COLLISIONSYSTEM_IGNOREII))
  105.             std::cout << "x_overlap: " << x_overlap << ", y_overlap: " << y_overlap << '\n';
  106.  
  107.         if (x_overlap > 0 && y_overlap > 0) {
  108.  
  109.             //std::cout << v1 << " " << v2 << "\n";
  110.  
  111.             //collision!
  112.             ii.collided = true;
  113.             //calculate collision normal (determines in what direction to apply impulse)
  114.             //penetrationDepth is just the least amount of overlap (either x or y axis)
  115.             /*x_over_y_bias helps with small steps etc.*/
  116.             if (x_overlap < y_overlap) {
  117.                 if (dir.x < 0) {
  118.                     ii.collisionNormal = sf::Vector2f(-1.0f, 0.0f);
  119.                 }
  120.                 else {
  121.                     ii.collisionNormal = sf::Vector2f(1.0f, 0.0f);
  122.                 }
  123.                 ii.penetrationDepth = x_overlap;
  124.             }
  125.             else {
  126.                 if (dir.y < 0) {
  127.                     ii.collisionNormal = sf::Vector2f(0.0f, -1.0f);
  128.                     components.at(componentat1)->groundedOnEntity = true;
  129.                     components.at(componentat1)->entityGroundedOn =
  130.                         components.at(componentat2);
  131.                 }
  132.                 else {
  133.                     ii.collisionNormal = sf::Vector2f(0.0f, 1.0f);
  134.                     components.at(componentat2)->groundedOnEntity = true;
  135.                     components.at(componentat2)->entityGroundedOn =
  136.                         components.at(componentat1);
  137.                 }
  138.                 ii.penetrationDepth = y_overlap;
  139.             }
  140.             if (false || (COLLISIONSYSTEM_EXCESSIVEDEBUG && !COLLISIONSYSTEM_IGNOREII))
  141.                 std::cout << "Collision between entity " << componentat1 << " and " << componentat2 << ":\n"
  142.                 << "CNormal: (" << ii.collisionNormal.x << ", " << ii.collisionNormal.y <<
  143.                 "), PDepth: " << ii.penetrationDepth << '\n';
  144.         }
  145.         else {
  146.             //no collision :-(
  147.             ii.collided = false;
  148.             if (COLLISIONSYSTEM_EXCESSIVEDEBUG && !COLLISIONSYSTEM_IGNOREII)
  149.                 std::cout << "No collision between entity " << componentat1 << " and " << componentat2 << ".\n";
  150.         }
  151.  
  152.         return ii;
  153.     }
  154. #pragma endregion
  155. #pragma region resolve Collision
  156.     void CollisionSystem::resolveCollision(IntersectionInfo ii, int componentat1, int componentat2) {
  157.         //calc inverse masses
  158.         invMass1 = components.at(componentat1)->staticCollider ? 0 : 1 / components.at(componentat1)->mass;
  159.         invMass2 = components.at(componentat2)->staticCollider ? 0 : 1 / components.at(componentat2)->mass;
  160.  
  161.         //calculate relative velocity
  162.         sf::Vector2f relativeVelocity(
  163.             (v1 ? v1->velocity : sf::Vector2f()) -
  164.             (v2 ? v2->velocity : sf::Vector2f())
  165.         );
  166.         //calculate relative velocity in terms of the normal direction. omegalul
  167.         float velAlongNormal =
  168.             relativeVelocity.x * ii.collisionNormal.x +
  169.             relativeVelocity.y * ii.collisionNormal.y;
  170.  
  171.         //dont resolve if velocities are seperating (if the colliders are moving apart)
  172.         if (velAlongNormal > 0) return;
  173.  
  174.         //calculate restitution (bounciness)
  175.         float restitution = std::min(
  176.             components.at(componentat1)->restitution,
  177.             components.at(componentat2)->restitution
  178.         );
  179.        
  180.         //calculate impulse scalar (how big the pushy force out do)
  181.         float j = -(1 + ii.penetrationDepth) * velAlongNormal;
  182.         j /= invMass1 + invMass2;
  183.  
  184.         //apply impulse
  185.         sf::Vector2f impulse = ii.collisionNormal * j; //collision direction times the impulse force j
  186.         if(v1) v1->velocity += invMass1 * impulse;
  187.         if(v2) v2->velocity -= invMass2 * impulse;
  188.     }
  189. #pragma endregion
  190. #pragma region correct position
  191.     void CollisionSystem::correctPosition(IntersectionInfo ii, int componentat1, int componentat2) {
  192.         sf::Vector2f correction =
  193.             std::max(ii.penetrationDepth - COLLISIONSYSTEM_SLOP, 0.0f) /
  194.             (invMass1 + invMass2) *
  195.             COLLISIONSYSTEM_PROJECTIONPERCENTAGE *
  196.             ii.collisionNormal;
  197.         pos1->position += invMass1 * correction;
  198.         pos2->position -= invMass2 * correction;
  199.     }
  200. #pragma endregion
  201. }
Advertisement
Add Comment
Please, Sign In to add comment