void PhysicsWorld::update(Scene * scene, unsigned dt){ /*std::cout << "<---- physics update ----> \n"; std::cout << "<---- collisons loop ----> \n";*/ /*std::cout << "i= "<< i << " | id = " << objectList[i]->getId() << " \n"; std::cout << "pos: (" << objectList[i]->getPosition().x << ", " << objectList[i]->getPosition().y << " )\n"; std::cout << "rigid body pos: (" << objectList[i]->getRigidBody()->getPosition().x << ", " << objectList[i]->getRigidBody()->getPosition().y << " )\n"; std::cout << "width: " << objectList[i]->getWidth() << "| height: " << objectList[i]->getHeight() << "\n";*/ this->collisions.clear(); scene->getCollisionLayer()->foreachPair(dt, [=](CollisionObject * a, CollisionObject * b, unsigned dt) { glm::vec2 mtv = a->getCollisionShape()->checkCollision(b->getCollisionShape()); if(mtv != glm::vec2()){ this->collisions.push_back(CollisionEvent(a,b,mtv)); this->resolveCollision(a,b,mtv); } }); scene->getCollisionLayer()->foreachObject(dt, [=](CollisionObject * collisionObject, unsigned dt) { if(!(collisionObject->getCollisionShape()->getIsStatic())) { collisionObject->getCollisionShape()->getRigidBody()->setForce(glm::vec2()); applyForce(collisionObject->getCollisionShape()->getRigidBody() ,this->gravity); collisionObject->step(dt); } }); }
inline void CollisionBox<ScalarT, dimN>::queueCellChanges( typename CollisionBox<ScalarT, dimN>::Particle* particle, const typename CollisionBox<ScalarT, dimN>::Point& newPosition, typename CollisionBox<ScalarT, dimN>::Scalar timeStep, typename CollisionBox<ScalarT, dimN>::CollisionQueue& collisionQueue) { /* Check for crossing of any cell borders: */ GridCell* cell=particle->cell; Scalar cellChangeTime=timeStep; int cellChangeDirection=-1; for (int i=0;i<dimension;++i) { if (newPosition[i]<cell->boundaries.min[i]) { Scalar collisionTime=particle->timeStamp+(cell->boundaries.min[i]-particle->position[i])/particle->velocity[i]; if (cellChangeTime>collisionTime) { cellChangeTime=collisionTime; cellChangeDirection=2*i+0; } } else if (newPosition[i]>cell->boundaries.max[i]) { Scalar collisionTime=particle->timeStamp+(cell->boundaries.max[i]-particle->position[i])/particle->velocity[i]; if (cellChangeTime>collisionTime) { cellChangeTime=collisionTime; cellChangeDirection=2*i+1; } } } if (cellChangeDirection>=0) { collisionQueue.insert(CollisionEvent(cellChangeTime,particle,cellChangeDirection)); } }
inline void CollisionBox<ScalarT, dimN>::queueCollisionsInCell( typename CollisionBox<ScalarT, dimN>::GridCell* cell, typename CollisionBox<ScalarT, dimN>::Particle* particle1, typename CollisionBox<ScalarT, dimN>::Scalar timeStep, bool symmetric, typename CollisionBox<ScalarT, dimN>::Particle* otherParticle, typename CollisionBox<ScalarT, dimN>::CollisionQueue& collisionQueue) { /* Calculate all intersections between two particles: */ for (Particle* particle2=cell->particlesHead;particle2!=0;particle2=particle2->cellSucc) { if (particle2!=particle1 && particle2!=otherParticle && (symmetric||particle2>particle1)) { /* Calculate any possible intersection time between the two particles: */ Vector d=particle1->position-particle2->position; d-=particle1->velocity*particle1->timeStamp; d+=particle2->velocity*particle2->timeStamp; Vector vd=particle1->velocity-particle2->velocity; Scalar vd2=Geometry::sqr(vd); if (vd2>Scalar(0)) // Are the two particles' velocities different? { /* Solve the quadratic equation determining possible collisions: */ Scalar ph=(d*vd)/vd2; Scalar q=(Geometry::sqr(d)-Scalar(4)*particleRadius2)/vd2; Scalar det=Math::sqr(ph)-q; if (det>=Scalar(0)) // Are there any solutions? { /* Calculate the first solution (only that can be valid): */ Scalar collisionTime=-ph-Math::sqrt(det); /* If the collision is valid, i.e., occurs past the last update of both particles, queue it: */ if (collisionTime>particle1->timeStamp && collisionTime>particle2->timeStamp && collisionTime<=timeStep) collisionQueue.insert(CollisionEvent(collisionTime,particle1,particle2)); } } } } }
void PhysicsComponent::callOnCollision(GameObject& other, Scene& scene) { ColliderComponent* otherCollider = other.getComponent<ColliderComponent>(); owner_.broadcastEvent(CollisionEvent(scene, other, *otherCollider)); other.broadcastEvent(CollisionEvent(scene, owner_, *collider_)); }
inline void CollisionBox<ScalarT, dimN>::queueCollisions( typename CollisionBox<ScalarT, dimN>::Particle* particle1, typename CollisionBox<ScalarT, dimN>::Scalar timeStep, bool symmetric, typename CollisionBox<ScalarT, dimN>::Particle* otherParticle, typename CollisionBox<ScalarT, dimN>::CollisionQueue& collisionQueue) { /* Calculate the particle's position at the end of this time step: */ Point newPosition=particle1->position+particle1->velocity*(timeStep-particle1->timeStamp); /* Check for crossing of cell borders: */ queueCellChanges(particle1,newPosition,timeStep,collisionQueue); /* Check for collision with any of the collision box's walls: */ for (int i=0;i<dimension;++i) { if (newPosition[i]<boundaries.min[i]+particleRadius) { Scalar collisionTime=particle1->timeStamp+(boundaries.min[i]+particleRadius-particle1->position[i])/particle1->velocity[i]; if (collisionTime<particle1->timeStamp) collisionTime=particle1->timeStamp; else if (collisionTime>timeStep) collisionTime=timeStep; Vector wallNormal=Vector::zero; wallNormal[i]=Scalar(1); collisionQueue.insert(CollisionEvent(collisionTime,particle1,wallNormal)); } else if (newPosition[i]>boundaries.max[i]-particleRadius) { Scalar collisionTime=particle1->timeStamp+(boundaries.max[i]-particleRadius-particle1->position[i])/particle1->velocity[i]; if (collisionTime<particle1->timeStamp) collisionTime=particle1->timeStamp; else if (collisionTime>timeStep) collisionTime=timeStep; Vector wallNormal=Vector::zero; wallNormal[i]=Scalar(-1); collisionQueue.insert(CollisionEvent(collisionTime,particle1,wallNormal)); } } /* Check for collision with the spherical obstacle: */ Vector d=particle1->position-spherePosition; d-=particle1->velocity*particle1->timeStamp; d+=sphereVelocity*sphereTimeStamp; Vector vd=particle1->velocity-sphereVelocity; Scalar vd2=Geometry::sqr(vd); if (vd2>Scalar(0)) { // Are the two particles' velocities different? /* Solve the quadratic equation determining possible collisions: */ Scalar ph=(d*vd)/vd2; Scalar q=(Geometry::sqr(d)-Math::sqr(particleRadius+sphereRadius))/vd2; Scalar det=Math::sqr(ph)-q; if (det>=Scalar(0)) { // Are there any solutions? /* Calculate the first solution (only that can be valid): */ Scalar collisionTime=-ph-Math::sqrt(det); /* If the collision is valid, i.e., occurs past the last update of both particles, queue it: */ if (collisionTime>particle1->timeStamp && collisionTime>sphereTimeStamp && collisionTime<=timeStep) { collisionQueue.insert(CollisionEvent(collisionTime,particle1,sphereTimeStamp)); } } } /* Check for collision with any other particle: */ GridCell* baseCell=particle1->cell; for (int i=0;i<numNeighbors;++i) { GridCell* cell=baseCell+neighborOffsets[i]; queueCollisionsInCell(cell,particle1,timeStep,symmetric,otherParticle,collisionQueue); } }
void BulletOpenGLApplication::CheckForCollisionEvents() { // keep a list of the collision pairs we // found during the current update CollisionPairs pairsThisUpdate; // iterate through all of the manifolds in the dispatcher for (int i = 0; i < m_pDispatcher->getNumManifolds(); ++i) { // get the manifold btPersistentManifold* pManifold = m_pDispatcher->getManifoldByIndexInternal(i); // ignore manifolds that have // no contact points. if (pManifold->getNumContacts() > 0) { // get the two rigid bodies involved in the collision const btRigidBody* pBody0 = static_cast<const btRigidBody*>(pManifold->getBody0()); const btRigidBody* pBody1 = static_cast<const btRigidBody*>(pManifold->getBody1()); // always create the pair in a predictable order // (use the pointer value..) bool const swapped = pBody0 > pBody1; const btRigidBody* pSortedBodyA = swapped ? pBody1 : pBody0; const btRigidBody* pSortedBodyB = swapped ? pBody0 : pBody1; // create the pair CollisionPair thisPair = std::make_pair(pSortedBodyA, pSortedBodyB); // insert the pair into the current list pairsThisUpdate.insert(thisPair); // if this pair doesn't exist in the list // from the previous update, it is a new // pair and we must send a collision event if (m_pairsLastUpdate.find(thisPair) == m_pairsLastUpdate.end()) { CollisionEvent((btRigidBody*)pBody0, (btRigidBody*)pBody1); } } } // create another list for pairs that // were removed this update CollisionPairs removedPairs; // this handy function gets the difference beween // two sets. It takes the difference between // collision pairs from the last update, and this // update and pushes them into the removed pairs list std::set_difference( m_pairsLastUpdate.begin(), m_pairsLastUpdate.end(), pairsThisUpdate.begin(), pairsThisUpdate.end(), std::inserter(removedPairs, removedPairs.begin())); // iterate through all of the removed pairs // sending separation events for them for (CollisionPairs::const_iterator iter = removedPairs.begin(); iter != removedPairs.end(); ++iter) { SeparationEvent((btRigidBody*)iter->first, (btRigidBody*)iter->second); } // in the next iteration we'll want to // compare against the pairs we found // in this iteration m_pairsLastUpdate = pairsThisUpdate; }