bool CBurnBot::CheckCollision(IBaseObject* pObj) { if(pObj == this) return false; if(!pObj->GetAlive()) return false; if(!GetAlive()) return false; int nType = pObj->GetID(); bool bAvoid = nType == OBJ_SMASH || nType == OBJ_SPIDER || nType >= OBJ_VAT && nType <= OBJ_BARREL || nType == OBJ_BOSSINV || nType == OBJ_INVERSION; if( bAvoid ) Utilities::CheckAvoid(this, pObj); if(nType >= OBJ_TRASH && nType <= OBJ_AIFIST || nType == OBJ_PLAYER || nType >= OBJ_VAT && nType <= OBJ_BARREL || nType == OBJ_INVERSION || OBJ_TUNNEL) { if(SphereToSphere(GetSphere(), pObj->GetSphere())) { if(OBJ_TUNNEL) CollisionResponse(pObj); else AddToReactVector(pObj); //CollisionResponse(pObj); return true; } } return false; }
void BoundingObjectManager::Update(void) { m_vCollidingNames.clear(); for(int nObject = 0; nObject < m_nObjects; nObject++) { m_vBoundingObject[nObject]->SetColorOBB(MEWHITE); m_vBoundingObject[nObject]->SetVisible(false); } CollisionCheck(); CollisionResponse(); }
void World::Update(const ObjectList& objList) { // Works each bodies' physics for (auto it1 = objList.begin(); it1 != objList.end(); ++it1) { // 1. If sprite has body and activated body to work. if (it1->second->HasRigidBody() && it1->second->GetRigidBody()->GetMoveToggle()) { // Work basic motion BodyPipeline(it1->second); // 2. if 2st sprite's colliders to be worked, check colliders if (it1->second->GetRigidBody()->GetColliderToggle()) { // Refresh collision-with info it1->second->GetRigidBody()->CheckCollided(false); it1->second->GetRigidBody()->SetCollisionWith(nullptr); auto new_begin = it1; for (auto it2 = new_begin; it2 != objList.end(); ++it2) { // 3. If both objs are differenct and both bodies has own body, // activated body and collider body, if (it1 != it2 && it2->second->HasRigidBody() && it2->second->GetRigidBody()->GetColliderToggle()) { // 4. then check the colliders. // Check two sprites' collision status bool collisionIntersect = CollisionIntersect(it1->second, it2->second); if (collisionIntersect) { // Collision response if (it1->second->GetRigidBody()->GetResponseToggle() || it2->second->GetRigidBody()->GetResponseToggle()) CollisionResponse(it1->second, it2->second); // Refresh the collision with info CollisionRelation(it1->second, it2->second); }// 4. Check the colliders }// 3. Has Rigid Body, 2 toggles to work } }// 2. Collider Toggle }// 1. Body Toggle } }
bool CBouncingBall::UpdatePhysics(float dt) { if (m_isActive == false) return false; bool bounce = false; m_position += m_velocity * dt + (m_acceleration * dt * dt) * 0.5; m_velocity += m_acceleration * dt; float yPlane = 0.0f; if(CollisionDetection(yPlane)) { CollisionResponse(); bounce = true; } return bounce; }
// This is the generic sweep test for all swept volumes, but not character-controller specific bool SweepTest::DoSweepTest(void* user_data, void* user_data2, NxU32 nb_boxes, const NxExtendedBounds3* boxes, const void** box_user_data, NxU32 nb_capsules, const NxExtendedCapsule* capsules, const void** capsule_user_data, SweptVolume& swept_volume, const NxVec3& direction, NxU32 max_iter, NxU32* nb_collisions, NxU32 group_flags, float min_dist, const NxGroupsMask* groupsMask, bool down_pass) { // Early exit when motion is zero. Since the motion is decomposed into several vectors // and this function is called for each of them, it actually happens quite often. if(direction.isZero()) return false; bool HasMoved = false; mValidTri = false; NxExtendedVec3 CurrentPosition = swept_volume.mCenter; NxExtendedVec3 TargetPosition = swept_volume.mCenter; TargetPosition += direction; NxU32 NbCollisions = 0; while(max_iter--) { gNbIters++; // Compute current direction NxVec3 CurrentDirection = TargetPosition - CurrentPosition; // Make sure the new TBV is still valid { // Compute temporal bounding box. We could use a capsule or an OBB instead: // - the volume would be smaller // - but the query would be slower // Overall it's unclear whether it's worth it or not. // TODO: optimize this part ? NxExtendedBounds3 TemporalBox; swept_volume.ComputeTemporalBox(*this, TemporalBox, CurrentPosition, CurrentDirection); // Gather touched geoms UpdateTouchedGeoms(user_data, swept_volume, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, group_flags, TemporalBox, groupsMask); } const float Length = CurrentDirection.magnitude(); if(Length<min_dist) break; CurrentDirection /= Length; // From Quake2: "if velocity is against the original velocity, stop dead to avoid tiny occilations in sloping corners" if((CurrentDirection|direction) <= 0.0f) break; // From this point, we're going to update the position at least once HasMoved = true; // Find closest collision SweptContact C; C.mDistance = Length + mSkinWidth; if(!CollideGeoms(this, swept_volume, mGeomStream, CurrentPosition, CurrentDirection, C)) { // no collision found => move to desired position CurrentPosition = TargetPosition; break; } ASSERT(C.mGeom); // If we reach this point, we must have touched a geom if(C.mGeom->mType==TOUCHED_USER_BOX || C.mGeom->mType==TOUCHED_USER_CAPSULE) { // We touched a user object, typically another CCT if(mValidateCallback) UserHitCallback(user_data2, C, CurrentDirection, Length); // Trying to solve the following problem: // - by default, the CCT "friction" is infinite, i.e. a CCT will not slide on a slope (this is by design) // - this produces bad results when a capsule CCT stands on top of another capsule CCT, without sliding. Visually it looks // like the character is standing on the other character's head, it looks bad. So, here, we would like to let the CCT // slide away, i.e. we don't want friction. // So here we simply increase the number of iterations (== let the CCT slide) when the first down collision is with another CCT. if(down_pass && !NbCollisions) max_iter += 9; } else { // We touched a normal object #ifdef USE_CONTACT_NORMAL_FOR_SLOPE_TEST mValidTri = true; mCN = C.mWorldNormal; #else if(C.mIndex!=INVALID_ID) { mValidTri = true; mTouched = mWorldTriangles[C.mIndex]; } #endif { if(mValidateCallback) ShapeHitCallback(user_data2, C, CurrentDirection, Length); } } NbCollisions++; mContactPointHeight = (float)C.mWorldPos[mUpDirection]; // UBI const float DynSkin = mSkinWidth; if(C.mDistance>DynSkin/*+0.01f*/) CurrentPosition += CurrentDirection*(C.mDistance-DynSkin); NxVec3 WorldNormal = C.mWorldNormal; if(mWalkExperiment) { // Make sure the auto-step doesn't bypass this ! WorldNormal[mUpDirection]=0.0f; WorldNormal.normalize(); } const float Bump = 0.0f; // ### doesn't work when !=0 because of Quake2 hack! const float Friction = 1.0f; CollisionResponse(TargetPosition, CurrentPosition, CurrentDirection, WorldNormal, Bump, Friction, mNormalizeResponse); } if(nb_collisions) *nb_collisions = NbCollisions; // Final box position that should be reflected in the graphics engine swept_volume.mCenter = CurrentPosition; // If we didn't move, don't update the box position at all (keeping possible lazy-evaluated structures valid) return HasMoved; }
bool CSmashBot::CheckCollision(IBaseObject* pObj) { if(pObj == this) return false; int nType = pObj->GetID(); if(nType == OBJ_SMASH || nType == OBJ_SPIDER || nType == OBJ_INVERSION || nType == OBJ_TUNNEL) { if(SphereToSphere(this->GetSphere(), pObj->GetSphere())) { if( m_bIsSmashing == false || nType == OBJ_INVERSION || OBJ_TUNNEL) { AddToReactVector(pObj); //CollisionResponse(pObj); return true; } } } if(nType == OBJ_PIT) { Sphere tempSphere = GetSphere(); tempSphere.m_Radius = 10.0f; if(SphereToAABB(tempSphere,((CDeathPit*)pObj)->GetAABB())) { ((CDeathPit*)pObj)->SetTrapCloseTimer(2.0f); if(((CDeathPit*)pObj)->GetTrapIsOpen()) { ((CDeathPit*)pObj)->SetIsTrapOpen(false); ((CDeathPit*)pObj)->ChangeAnimation(1); } return true; } } if(nType == OBJ_PLAYER) { if(SphereToSphere(this->GetSphere(), ((CPlayerObject*)pObj)->GetSphere())) { //m_bIsSmashing = true; AddToReactVector(pObj); //CollisionResponse(pObj); return true; } } if(nType == OBJ_CONVEYOR) { if(SphereToAABB(GetSphere(), ((CConveyor*)pObj)->GetAABB())) { pObj->AddToReactVector(this); //pObj->CollisionResponse(this); return true; } } if(nType >= OBJ_VAT && nType <= OBJ_BARREL) { if(SphereToSphere(GetSphere(),pObj->GetSphere())) { //AddToReactVector(this); CollisionResponse(pObj); return true; } } return false; }
bool CExplodingBullet::CheckCollision(IBaseObject* pObj) { if( !GetAlive() || !pObj->GetAlive()) return false; int nType = pObj->GetID(); switch(m_nType) { case SPECIALBULLET: { if( nType == OBJ_BULLET_ENEMY || nType > OBJ_PLAYER && nType <= OBJ_AIFIST || nType >= OBJ_VAT && nType <= OBJ_BARREL || nType == OBJ_INVERSION || nType == OBJ_BOSSINV || nType == OBJ_BOSSTURRET) { std::list<IBaseObject*>::iterator iter; for( iter = m_lEnemies.begin(); iter != m_lEnemies.end(); ++iter ) { if( (*iter) == pObj ) return false; } if( SphereToSphere(GetSphere(), pObj->GetSphere())) { m_lEnemies.push_back(pObj); CollisionResponse(pObj); CEffect* pEffect = CGameplayState::GetInstance()->GetFX()->CreateEffect(EFFECT_SPECIALHIT,pObj->GetMatrix()); if(pEffect) pEffect->SetColors((D3DXCOLOR)GetColor()); return true; } } } break; case SMASHBULLET: { if( nType == OBJ_PLAYER || nType == OBJ_TRASH ) { if( SphereToSphere(GetSphere(), pObj->GetSphere())) { CollisionResponse(pObj); return true; } } } break; case BARRELBULLET: { if( nType == OBJ_PLAYER || nType >= OBJ_TRASH && nType <= OBJ_STEAM) { if( SphereToSphere(GetSphere(), pObj->GetSphere())) { CollisionResponse(pObj); return true; } } else if( nType == OBJ_BARREL) { if( SphereToSphere(GetSphere(), pObj->GetSphere())) { pObj->CollisionResponse(this); return true; } } } break; case INVERSION_BULLET: { if(nType == OBJ_PLAYER) { if(SphereToSphere(GetSphere(), pObj->GetSphere())) { CollisionResponse(pObj); return true; } } } } return false; }