Collisions between Characters Controllers

Please don't post Bullet support questions here, use the above forums instead.
Post Reply
Knn0N
Posts: 10
Joined: Mon Apr 02, 2012 2:25 pm

Collisions between Characters Controllers

Post 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!
Last edited by Knn0N on Tue Apr 03, 2012 2:01 pm, edited 1 time in total.
Knn0N
Posts: 10
Joined: Mon Apr 02, 2012 2:25 pm

Re: Collisions between Characters controllers

Post by Knn0N »

Any ideas?!??!

Am I in a wrong way??

Should I change the functionality of my triggers??

thanks!
bone
Posts: 231
Joined: Tue Feb 20, 2007 4:56 pm

Re: Collisions between Characters Controllers

Post by bone »

You might want to go back to the main forum page and read the red text regarding this sub-forum.
Knn0N
Posts: 10
Joined: Mon Apr 02, 2012 2:25 pm

Re: Collisions between Characters Controllers

Post by Knn0N »

ops! :oops:

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