static inline int GetCollidingSide2( Rect A,Rect B ){ if (!IsColliding(A,B)) return -1; Point Center1 = A.GetCenter(); Point Center2 = B.GetCenter(); int dir = 0; float angle = Center2.GetDirection(Center1); /* 0 left 1 top 2 right 3 bottom */ angle = Geometry::toDeg(angle); if (angle <= 45 || angle > 315){ dir = 0; }else if(angle > 45 && angle <= 135){ dir = 1; }else if(angle > 135 && angle <= 225){ dir = 2; }else if(angle > 225 && angle <= 315){ dir = 3; } return dir; }
void DynamicEntity::TakeAStep() { mySpeed.y+=myGravity; SetPosition(GetPosition()+mySpeed); CollisionGrid::AssignCells(this); std::list<GridCell*>::iterator accesIt; std::list<CollisionEntity*>::iterator cellIt; //std::cout<<"Number of Cells containing object:"<<CollisionGrid::accessList.size()<<std::endl; for (accesIt=CollisionGrid::accessList.begin(); accesIt!=CollisionGrid::accessList.end(); accesIt++) { //std::cout<<"Number of entities inside the cell "<<(*accesIt)<<" :"<<(*accesIt)->myInstances.size()<<std::endl; for (cellIt=(*accesIt)->myInstances.begin(); cellIt!=(*accesIt)->myInstances.end(); cellIt++) { //Ne pas vérifier avec soi même! if ((*cellIt)==this) break; if (IsColliding(**cellIt)) { //std::cout<<"Collision!\n"; //Check relative position and bounce mySpeed.y=-(mySpeed.y*0.8f); } } } }
void Collision::compareColliders(Collider *collider_a, ECS::RigidBody2D *a, Collider *collider_b, ECS::RigidBody2D *b, Contacts &contacts) { if (IsColliding(*collider_a, *collider_b, contacts)) { collider_a->is_colliding = collider_b->is_colliding = true; } }
Rect Collision::GetIntersectRect(Rect& a, Rect& b){ if (!IsColliding(a,b)){ return Rect(0,0,0,0); } float c1 = std::max(a.x, b.x); float c2 = std::max(a.y, b.y); float c3 = std::min(a.x+a.w,b.x + b.w); float c4 = std::min(a.y + a.h, b.y + b.h); return Rect(c1,c2, c3-c1,c4-c2 ); }
bool MyOctant::ContainsMoreThan(uint a_nBOs) { uint nCount = 0; for (uint n = 0; n < m_pBOMngr->GetObjectCount(); n++) { if (IsColliding(n)) nCount++; if (nCount > a_nBOs) return true; } return false; }
static inline int GetCollidingDepth(Rect& a, Rect& b){ if (!IsColliding(a,b)){ return 0; } int side = GetCollidingSide2(a,b); if (side == 0){ return abs(a.x - (b.x+b.w) ); }else if (side == 1){ return abs(a.y - (b.y+b.h) ); }else if (side == 2){ return abs(a.x + a.w - (b.x) ); }else if (side == 3){ return abs(a.y + a.h - (b.y) ); }else{ return -1; } }
// Essa é uma implementação do SAT feita pelo Lucas Neves. // Recebe dois Rects e suas rotações, e detecta se os retângulos colidem. // Mais informações sobre o método podem ser encontradas nos seguintes links: // http://www.metanetsoftware.com/technique/tutorialA.html // http://www.gamedev.net/page/resources/_/technical/game-programming/2d-rotated-rectangle-collision-r2604 static inline bool IsColliding(Rect& a, Rect& b, float angleOfA, float angleOfB) { if (angleOfA == 0.0f && angleOfB == 0.0f){ return IsColliding(a,b); } Point A[] = { Point( a.x, a.y + a.h ), Point( a.x + a.w, a.y + a.h ), Point( a.x + a.w, a.y ), Point( a.x, a.y ) }; Point B[] = { Point( b.x, b.y + b.h ), Point( b.x + b.w, b.y + b.h ), Point( b.x + b.w, b.y ), Point( b.x, b.y ) }; for (auto& v : A) { v = Rotate(v - a.GetCenter(), angleOfA) + a.GetCenter(); } for (auto& v : B) { v = Rotate(v - b.GetCenter(), angleOfB) + b.GetCenter(); } Point axes[] = { Norm(A[0] - A[1]), Norm(A[1] - A[2]), Norm(B[0] - B[1]), Norm(B[1] - B[2]) }; for (auto& axis : axes) { float P[4]; for (int i = 0; i < 4; ++i) P[i] = Dot(A[i], axis); float minA = *std::min_element(P, P + 4); float maxA = *std::max_element(P, P + 4); for (int i = 0; i < 4; ++i) P[i] = Dot(B[i], axis); float minB = *std::min_element(P, P + 4); float maxB = *std::max_element(P, P + 4); if (maxA <= minB || minA >= maxB) return false; } return true; }
void MyOctant::AssignIDtoBO(void) { //traverse until you reach a leaf for (uint nChild = 0; nChild < m_nChildren; nChild++) { m_pChild[nChild]->AssignIDtoBO(); } if(m_nChildren == 0) //if this is a leaf { uint nBOs = m_pBOMngr->GetObjectCount(); for (uint nIndex = 0; nIndex < nBOs; nIndex++) { if (IsColliding(nIndex)) { m_lBOs.push_back(nIndex); } } } }
/** * Corrects the box position so as not to collide with * the walls. */ Rect MovementMap::CorrectPosition(Rect box) { std::cout << "Pos:(" << previousPos.GetX() << "," << previousPos.GetY() << ")" << std::endl; std::cout << "Width: " << previousPos.GetW() << std::endl; std::cout << "Height: " << previousPos.GetH() << std::endl; std::vector<Rect> collidingTiles; while (IsColliding(box)) { collidingTiles = GetCollidingTiles(box); SortVector(collidingTiles); for (int i = 0; i < (int)collidingTiles.size(); i++) CorrectCollision(box, collidingTiles[i]); collidingTiles.clear(); std::cout << "LOOP LULZ" << std::endl; } std::cout << "EXIT LOOP" << std::endl; return box; }
bool Collision::CircleToAABB(PhysicBody* first, const Shape* firstShape, PhysicBody* second, const Shape* secondShape, sf::Vector2f& minDisplacement) { const CircleShape* circle = static_cast<const CircleShape*>(firstShape); const RectangleShape* aabb = static_cast<const RectangleShape*>(secondShape); sf::Vector2f position1 = first->GetPosition(); sf::Vector2f position2 = second->GetPosition(); sf::Vector2f boxHalfSize = aabb->GetHalfSize(); if (!IsColliding(circle, position1, aabb, position2)) return false; //TODO : set minDisplacement /* sf::Vector2f nearestPoint = position1 - position2; nearestPoint.x = std::min(std::max(nearestPoint.x, -boxHalfSize.x), boxHalfSize.x); nearestPoint.y = std::min(std::max(nearestPoint.y, -boxHalfSize.y), boxHalfSize.y); nearestPoint += position2; float smallestX = std::min(nearestPoint.x - (position2.x - boxHalfSize.x), (position2.x + boxHalfSize.x) - nearestPoint.x); float smallestY = std::min(nearestPoint.y - (position2.y - boxHalfSize.y), (position2.y + boxHalfSize.y) - nearestPoint.y); if (smallestX < smallestY) { if (velocity1.x < 0.f) firstShape->SetPosition(sf::Vector2f(nearestPoint.x + circle->GetRadius(), position1.y)); else firstShape->SetPosition(sf::Vector2f(nearestPoint.x - circle->GetRadius(), position1.y)); } else { if (velocity1.y < 0.f) firstShape->SetPosition(sf::Vector2f(position1.x, nearestPoint.y + circle->GetRadius())); else firstShape->SetPosition(sf::Vector2f(position1.x, nearestPoint.y - circle->GetRadius())); }*/ return true; }
bool CCharacterController::RecoverFromPenetration(btCollisionWorld* pCollisionWorld) { if (!IsColliding()) return false; bool bPenetration = false; pCollisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_pGhostObject->getOverlappingPairCache(), pCollisionWorld->getDispatchInfo(), pCollisionWorld->getDispatcher()); btVector3 vecCurrentPosition = m_pGhostObject->getWorldTransform().getOrigin(); btVector3 vecOriginalPosition = vecCurrentPosition; btScalar maxPen = btScalar(0.0); for (int i = 0; i < m_pGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) { m_aManifolds.resize(0); btBroadphasePair* pCollisionPair = &m_pGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; btCollisionObject* pObject0 = static_cast<btCollisionObject*>(pCollisionPair->m_pProxy0->m_clientObject); btCollisionObject* pObject1 = static_cast<btCollisionObject*>(pCollisionPair->m_pProxy1->m_clientObject); if (!pObject0->hasContactResponse() || !pObject1->hasContactResponse()) continue; if (pObject0->getBroadphaseHandle()->m_collisionFilterGroup == CG_TRIGGER || pObject1->getBroadphaseHandle()->m_collisionFilterGroup == CG_TRIGGER) continue; if (pCollisionPair->m_algorithm) pCollisionPair->m_algorithm->getAllContactManifolds(m_aManifolds); for (int j = 0; j < m_aManifolds.size(); j++) { btPersistentManifold* pManifold = m_aManifolds[j]; const btCollisionObject* obA = static_cast<const btCollisionObject*>(pManifold->getBody0()); const btCollisionObject* obB = static_cast<const btCollisionObject*>(pManifold->getBody1()); btScalar directionSign; CEntityHandle<CBaseEntity> hOther; size_t iExtra; if (obA == m_pGhostObject) { if (obB->getBroadphaseHandle()->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) continue; directionSign = btScalar(-1.0); hOther = CEntityHandle<CBaseEntity>((size_t)obB->getUserPointer()); iExtra = (size_t)obB->getUserPointer()-GameServer()->GetMaxEntities(); if (obB->getCollisionFlags()&btCollisionObject::CF_CHARACTER_OBJECT) { // If I'm heavier than he, don't let him push me around if (hOther->GetMass() < m_hEntity->GetMass()) continue; } } else { if (obA->getBroadphaseHandle()->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) continue; directionSign = btScalar(1.0); hOther = CEntityHandle<CBaseEntity>((size_t)obA->getUserPointer()); iExtra = (size_t)obB->getUserPointer()-GameServer()->GetMaxEntities(); if (obA->getCollisionFlags()&btCollisionObject::CF_CHARACTER_OBJECT) { // If I'm heavier than he, don't let him push me around if (hOther->GetMass() < m_hEntity->GetMass()) continue; } } for (int p = 0; p < pManifold->getNumContacts(); p++) { const btManifoldPoint& pt = pManifold->getContactPoint(p); if (obA == m_pGhostObject) { if (hOther) { if (!m_hEntity->ShouldCollideWith(hOther, Vector(pt.getPositionWorldOnB()))) continue; } else { if (!m_hEntity->ShouldCollideWithExtra(iExtra, Vector(pt.getPositionWorldOnB()))) continue; } } else { if (hOther) { if (!m_hEntity->ShouldCollideWith(hOther, Vector(pt.getPositionWorldOnA()))) continue; } else { if (!m_hEntity->ShouldCollideWithExtra(iExtra, Vector(pt.getPositionWorldOnA()))) continue; } } btScalar flDistance = pt.getDistance(); btScalar flMargin = std::max(obA->getCollisionShape()->getMargin(), obB->getCollisionShape()->getMargin()); if (flDistance < -flMargin) { flDistance += flMargin; if (flDistance < maxPen) maxPen = flDistance; btScalar flDot = pt.m_normalWorldOnB.dot(GetUpVector()); btVector3 vecAdjustment; if (flDot > 0.707f) vecAdjustment = GetUpVector() * (directionSign * flDistance * 1.001f); else vecAdjustment = pt.m_normalWorldOnB * (directionSign * flDistance * 1.001f); if (vecAdjustment.length2() < 0.001*0.001) continue; vecCurrentPosition += vecAdjustment; bPenetration = true; } else { //printf("touching %f\n", dist); } } //pManifold->clearManifold(); } } btTransform mNew = m_pGhostObject->getWorldTransform(); mNew.setOrigin(mNew.getOrigin() + (vecCurrentPosition - vecOriginalPosition) * m_vecLinearFactor); m_pGhostObject->setWorldTransform(mNew); return bPenetration; }
void CollisionSystem::CheckCollisions() { float maxDistance = CFG_GETF("COLLISION_MAX_DISTANCE"); Quadtree<std::shared_ptr<Entity>> quadtree(Rectangle(CFG_GETF("LEVEL_MIN_X"), CFG_GETF("LEVEL_MIN_Y"), CFG_GETF("LEVEL_MAX_X") - CFG_GETF("LEVEL_MIN_X"), CFG_GETF("LEVEL_MAX_Y") - CFG_GETF("LEVEL_MIN_Y"))); auto cameraEntities = Engine::GetInstance().GetAllEntitiesWithComponentOfClass("CameraComponent"); collidableEntities = Engine::GetInstance().GetAllEntitiesWithComponentOfClass("ColliderComponent"); // Clear deleted entities from last iteration. deletedEntities.clear(); std::shared_ptr<Entity> cameraEntity; if (cameraEntities.size() > 0) cameraEntity = cameraEntities[0]; // Build quadtree for close enough entities. for (auto entity : collidableEntities) { auto particleComponent = std::static_pointer_cast<ParticleComponent>(Engine::GetInstance().GetSingleComponentOfClass(entity, "ParticleComponent")); auto position = particleComponent->GetPosition(); // Ignore collision from things that aren't visible. if (cameraEntity) { auto cameraComponent = std::static_pointer_cast<CameraComponent>(Engine::GetInstance().GetSingleComponentOfClass(cameraEntity, "CameraComponent")); auto cameraPosition = cameraComponent->GetPosition(); if (cameraPosition.CalculateDistance(position) > maxDistance) continue; else quadtree.Add(entity, position); } else { quadtree.Add(entity, position); } } // Detect and solve collisions. for (unsigned int i = 0; i < collidableEntities.size(); ++i) { auto entity = collidableEntities[i]; auto particleComponent = std::static_pointer_cast<ParticleComponent>(Engine::GetInstance().GetSingleComponentOfClass(entity, "ParticleComponent")); auto position = particleComponent->GetPosition(); auto quadtreeEntities = quadtree.Get(position); for (unsigned int j = 0; j < quadtreeEntities.size(); ++j) { auto otherEntity = quadtreeEntities[j]; if (std::find(deletedEntities.begin(), deletedEntities.end(), entity->GetId()) != deletedEntities.end()) continue; if (std::find(deletedEntities.begin(), deletedEntities.end(), otherEntity->GetId()) != deletedEntities.end()) continue; if (entity->GetId() != otherEntity->GetId() && IsColliding(entity, otherEntity)) SolveCollision(entity, otherEntity); } } }
bool Scene::IsColliding(const Vec2& vec, const Rect& rect) const { return IsColliding(rect,Rect(vec.x,vec.y,1,1)); }
void SATCollision::TestCollision() { const int winWidth = 800; const int winHeight = 600; initRandom(); sf::RenderWindow window(sf::VideoMode(winWidth, winHeight), "Test"); sf::RectangleShape rect1(sf::Vector2f(20, 100)); rect1.setFillColor(sf::Color(0, 255, 0, 255)); rect1.setOrigin(10, 10); rect1.setPosition(300, 400); sf::RectangleShape rect2(sf::Vector2f(50, 50)); rect2.setFillColor(sf::Color(255, 0, 0, 255)); rect2.setOrigin(rect2.getSize()/2.0f); rect2.setPosition(355, 400); bool rotLeft = false; bool rotRight = false; while(true){ sf::Event anEvent; while(window.pollEvent(anEvent)) { if(anEvent.type == sf::Event::KeyPressed) { switch(anEvent.key.code) { case sf::Keyboard::A : rotLeft = true; break; case sf::Keyboard::D : rotRight = true; break; } } else if(anEvent.type == sf::Event::KeyReleased) { switch(anEvent.key.code) { case sf::Keyboard::A : rotLeft = false; break; case sf::Keyboard::D : rotRight = false; break; } } } if(rotLeft) { rect1.setRotation(rect1.getRotation()-1.0f); } if(rotRight) { rect1.setRotation(rect1.getRotation()+1.0f); } sf::FloatRect bbox1 = rect1.getLocalBounds(); sf::FloatRect bbox2 = rect2.getLocalBounds(); std::vector<sf::Vector2f> rect1pts = GetTransformedRect(rect1, bbox1); std::vector<sf::Vector2f> rect2pts = GetTransformedRect(rect2, bbox2); bool collide = IsColliding(rect1pts, rect2pts); printf("%s\n", (collide?"colliding":"not colliding")); sf::CircleShape point(3.0f); point.setOrigin(point.getRadius()/2.0f, point.getRadius()/2.0f); window.clear(); window.draw(rect1); window.draw(rect2); for(unsigned int i = 0; i < rect1pts.size(); i++) { point.setPosition(rect1pts[i]); window.draw(point); } for(unsigned int i = 0; i < rect2pts.size(); i++) { point.setPosition(rect2pts[i]); window.draw(point); } window.display(); sf::sleep(sf::seconds(0.005f)); } }