Page 1 of 1

Collisions between Characters Controllers

Posted: Mon Apr 02, 2012 2:44 pm
by Knn0N
(collisions between btPairCachingGhostObject)

Hi everybody,

Me and my team are currently developing a game using bullet physics. The genre of the is basically a tower defense. Well, I'm trying to use characters controllers for IA purposes, because using only rigidBody makes unstable behavior between IA's and the world.
I thought in configure the world to avoid this penetrations between rigid bodies, etc.

But finally I decided to use the KinematicCharacterController class. It works fine, but this is my problem:

-Before I take this decision, I implemented triggers for the game purposes using btPairCachingGhostObject. This works like a charm when I was using ridigBodies, the behavior was the expected. But well, when I change the IA physic part from rigidBodies to characterController (it uses internally a btPairCachingGhostObject, too), the behavior wasn't the expected.

After this little introduction I ask now:
-Is the collision between btPairCachingGhostObject provided?

Basically I'm using the next methods to detect the collision when a body joins into the trigger:

Code: Select all



//---------------------------------------------------------
void CManualTrigger::TriggerTick()
{
    btDiscreteDynamicsWorld* m_dynamicsWorld = CPhysicEngine::Ref().GetbtSoftDynamicWorld();
    //Retrives the content from all ghost objects in the world and call ProcessObectsInsideGhostObjects(...) for each.		
    if ( m_dynamicsWorld )
    {
        btAlignedObjectArray < btCollisionObject* > objsInsidePairCachingGhostObject;	// We might want this to be a member variable...							
        btAlignedObjectArray < btCollisionObject* >* pObjsInsideGhostObject = NULL;		// We will store a reference of the current array in this pointer
        const btAlignedObjectArray < btCollisionObject* >& objs = m_dynamicsWorld->getCollisionObjectArray();	
        for (int i=0,sz=objs.size();i<sz;i++)	
        {
            btCollisionObject* o = objs[i];
            btGhostObject* go = btGhostObject::upcast(o);
            if (go)	
            {
                objsInsidePairCachingGhostObject.resize(0);
                btPairCachingGhostObject* pgo = dynamic_cast < btPairCachingGhostObject* > (go);	// No upcast functionality...
                if (pgo)	
                {
                    GetCollidingObjectsInsidePairCachingGhostObject(static_cast < btDiscreteDynamicsWorld* > (m_dynamicsWorld),pgo,objsInsidePairCachingGhostObject);
                    pObjsInsideGhostObject = &objsInsidePairCachingGhostObject;
                }
                else 
                {
                    // It's better not to try and copy the whole array, but to keep a reference to it!
                    pObjsInsideGhostObject = &go->getOverlappingPairs();
                    
                    // Side Note: (at the moment) makes my program crash on my system...
                    //btAlignedObjectArray < btCollisionObject* > objs = go->getOverlappingPairs(); 
                    // Nevermind, that was the wrong way of doing it: 
                    //btAlignedObjectArray < btCollisionObject* >& objs2 = go->getOverlappingPairs(); 
                    //is much better.
                }	
                // Here pObjsInsideGhostObject should be valid.	
                ProcessObectsInsideGhostObjects(*pObjsInsideGhostObject, pgo);
            }
        }	
    }
}




//---------------------------------------------------------
// This static method is useful for the demo only. It's called by "void GhostObjectsDemo::clientMoveAndDisplay()".
// Basically we must find a way to "display" the objects inside ghost objects to the user.
// We choose to apply a vertical impulse to them (just because it's easier).
// (The strength of the impulse is different depending on the type of ghost object)
void CManualTrigger::ProcessObectsInsideGhostObjects(btAlignedObjectArray < btCollisionObject* >& objs, const bool isPairCachingGhostObject)	
{
    //Primer paso: Comprobando colisiones e insertando los nuevos objetos que no estaban ya insertados en el mapa de colisiones.
    for (int j=0,jsz=objs.size();j<jsz;j++) 
    {

        btPairCachingGhostObject* b = dynamic_cast < btPairCachingGhostObject* >(objs[j]);
        //This line was the original one, before I change by the line above.
        //btRigidBody* c = btRigidBody::upcast(objs[j]);
        if (b) 
        {
            //Obtenemos la informacion que relaciona bullet con la logica (TActorInfo).
            TActorInfo *info = (TActorInfo *)b->getUserPointer();
            //Obtenemos el componente entidad fisica al que pertenece el rigidBody 'b'.
            CPhysicEntity *physicEntity = reinterpret_cast<CPhysicEntity*> (info->pPhysicObj->userData);
            //Obtenemos la entidad logica que contiene el componente anterior.
            CEntity *entityCollisioned = physicEntity->getEntity();
            
            if (entityCollisioned->getType() == "StuffedAnimal" ||  entityCollisioned->getType() == "Player") 
            {                
                //Primero comprobamos que el objeto no conste ya en el mapa de objetos colisionados con el trigger.
                _it = _objectsColliding.find(b);
                if (_it == _objectsColliding.end()) 
                {
                    //Si no estuviera, lo insertamos.
                    _objectsColliding.insert(std::pair<btCollisionObject*,bool>(b, true));
                    //Y mandamos el mensaje oportuno.
                    //Dependiendo de la trampa, habrĂ¡ un comportamiento u otro.
                    doAction(entityCollisioned);
                }
            }
        }	
    }
    //Si hay algo en contacto con el trigger.
    if (objs.size() > 0)
    {
        //Segundo paso: Marcando en el mapa de colisiones los objetos que ya no esten colisionando con el trigger.
        for (_it = _objectsColliding.begin(); _it != _objectsColliding.end(); ++_it) 
        {
            //Si la busqueda devuelve un entero igual al tamanyo del map objs, es que no se ha encontrado el elemento.
            if ( objs.findLinearSearch(_it->first) == objs.size() )
            {
                _it->second = false;
            }
        }
        //Tercer paso: Notificar a las entidades que ya no estan colisionando con el trigger con su correspondiente mensaje.
        notifyingOnExitEntities();
    }
}


//---------------------------------------------------------
// Portable static method: prerequisite call: m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback()); 
void CManualTrigger::GetCollidingObjectsInsidePairCachingGhostObject(btDiscreteDynamicsWorld* m_dynamicsWorld,
                                                                    btPairCachingGhostObject* m_pairCachingGhostObject,
                                                                    btAlignedObjectArray<btCollisionObject*>& collisionArrayOut)	
{
    collisionArrayOut.resize(0);
    if (!m_pairCachingGhostObject || !m_dynamicsWorld) 
        return;
    // With "false" things don't change much, and the code is a bit faster and cleaner...
    const bool addOnlyObjectsWithNegativeDistance(true);	
    
    btBroadphasePairArray& collisionPairs = m_pairCachingGhostObject->getOverlappingPairCache()->getOverlappingPairArray();
    const int	numObjects=collisionPairs.size();	
    static btManifoldArray	m_manifoldArray;
    bool added;
    for(int i=0;i<numObjects;i++)	
    {
        m_manifoldArray.resize(0);
        added = false;
        for (int j=0;j<m_manifoldArray.size();j++)	
        {
            btPersistentManifold* manifold = m_manifoldArray[j];
            // Here we are in the narrowphase, but can happen that manifold->getNumContacts()==0:
            if (addOnlyObjectsWithNegativeDistance)	
            {
                for (int p=0,numContacts=manifold->getNumContacts();p<numContacts;p++)			
                {
                    const btManifoldPoint&pt = manifold->getContactPoint(p);
                    if (pt.getDistance() < 0.0) 	
                    {
                        // How can I be sure that the colObjs are all distinct ? I use the "added" flag.
                        collisionArrayOut.push_back((btCollisionObject*) (manifold->getBody0() == m_pairCachingGhostObject ? manifold->getBody1() : manifold->getBody0()));
                        added = true;
                        break;
                    }	
                }
                if (added) 
                    break;
            }
            else if (manifold->getNumContacts()>0) 
            {
                collisionArrayOut.push_back((btCollisionObject*) (manifold->getBody0() == m_pairCachingGhostObject ? manifold->getBody1() : manifold->getBody0()));
                break;
            }
        }
    }	
}




So, Is this possible?, I mean, Can we detect collision between characters controllers (between GhostObjects)?. This would be useful too, to avoid the overlapping between two or more btKinematicCharacterControllers.

Thanks!

Re: Collisions between Characters controllers

Posted: Tue Apr 03, 2012 1:36 pm
by Knn0N
Any ideas?!??!

Am I in a wrong way??

Should I change the functionality of my triggers??

thanks!

Re: Collisions between Characters Controllers

Posted: Tue Apr 03, 2012 4:11 pm
by bone
You might want to go back to the main forum page and read the red text regarding this sub-forum.

Re: Collisions between Characters Controllers

Posted: Tue Apr 03, 2012 4:24 pm
by Knn0N
ops! :oops:

sorry. I've been moved to the right sub forum.