[SOLVED] Simulate contact begin and contact end with Newton2

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

[SOLVED] Simulate contact begin and contact end with Newton2

Postby Nodrev » Mon Jun 14, 2010 5:30 am

Hello,

I try to migrate my code to Newton 2.0, but i'm stuck with a little problem on Contacts callbacks.
Let me explain my problem: i got a little sample game with a ball rolling on a terrain (a kind of marble madness :)), and i want to play a sound while the ball is rolling.
I want this sound played continuelly, modulating it by the speed of the ball.
So, I basicly want to start the sound when the ball start to contact with the terrain, and stop when it's not the case anymore (ball is jumping). But it don't work the way i was expecting: when the ball roll, the contact is stopped and it's another one that is started, making the sound start/stop...
The only solution i see is to register the two bodies in a map when the contact start, but i don't see how to detect the stop event...

Any idea about this?
Last edited by Nodrev on Tue Jun 15, 2010 9:25 am, edited 1 time in total.
Nodrev
 
Posts: 4
Joined: Mon Jun 14, 2010 5:05 am

Re: Simulate contact begin and contact end with Newton 2.0

Postby Stucuk » Mon Jun 14, 2010 6:48 am

1. When the ball is in contact with the ground and rolling set a variable(Lets say called BallIsRolling) to true. Also only start a sound if there is currently no sound playing. Also reset the timer in number 2.
2. Every X time set BallIsRolling to false and stop the sound.
User avatar
Stucuk
 
Posts: 801
Joined: Sat Mar 12, 2005 3:54 pm
Location: Scotland

Re: Simulate contact begin and contact end with Newton 2.0

Postby Nodrev » Mon Jun 14, 2010 8:16 am

So, if i understand well, there's no possibility to detect when two bodies are not in contact anymore by event?
Here the code for the "begin" event, in contactsProcess callback function (myMap is not declared in this function obviously, but in the constructor of a materialPair wrapper, so a list by material pair):
Code: Select all
    typedef std::map<SBody*, SBody*> BodyPairMap;
    BodyPairMap myMap;

    SNode* nodeScol0                = Ogre::any_cast<SNode*>(contactJoint.getBody0()->getUserData()) ;
    SNode* nodeScol1                = Ogre::any_cast<SNode*>(contactJoint.getBody1()->getUserData()) ;

    BodyPairMap::iterator iBodyPairSearched = myMap.find(b0);
    if (iBodyPairSearched == myMap.end())
    {   
      iBodyPairSearched = myMap.find(b1);
      if (iBodyPairSearched == myMap.end())
      {
        // Contact between those two bodies begin!
        myMap.insert(BodyPairMap::value_type(b0, b1));

        // Send event begin!
        // TODO send callback "contact begin" to scol virtual machine
      }
    }

    // For each contact point between those two bodies.
    for (OgreNewt::Contact contact = contactJoint.getFirstContact(); contact; contact = contact.getNext())
    {
        // TODO send callback "contact" to scol virtual machine
    }

    // TODO send "contact end" (between to bodies), and remove the entry from my map


The timer solution do not satisify me, as the ball rolling is just a sample, i got plenty of apps using the "end contact" event from newton 1.5...
Nodrev
 
Posts: 4
Joined: Mon Jun 14, 2010 5:05 am

Re: Simulate contact begin and contact end with Newton 2.0

Postby Julio Jerez » Mon Jun 14, 2010 9:16 am

you do not need timer, the map or list shoul work fine, in fact there are many more funtionalitity to do stuff like that in 2.00 that in 1.53
Beside in 1.53 contact end was no call when body separate either. or when body when to rest in contact
2.0 have many more funtion to adress those issues, 2.0 is the game play programmen best friend with Joint iterators, body iterators, Material iterators, and concact iterators.
here one way using the contact iterator in the body, say you have a list. you write function to update you sound updtae like this.

Code: Select all
UpdateSound()
{
   for each body in list
   {   
           bool bodyInContact = false; 
          for (contactJoint = body->GetFistContact (); conatctJoint; contact = NewtonGetNextContact (body, conttact) {
                if ((jointbody0 == Terrain) or (jointbody2 == Terrain) {
                        PlaySound (body)
                        bodyInContact = true;
                } 
          }
          if (BodyInCntact == false) {
                  RemoveBodyFoprmList (body)
          }
   }
}


you have it almost right but you try to make it too complex by implemnetiong everything in the contact proccess callback,
but it work better function if the cfuntion is after the Newton update since when body detach from collision there is not notification callback.
nor there is notification when body are in contact by they are at rest.
with this function you can querie all information you need from the contact joint. and when the contact is destroyed, the list is cleanup up automatically, so it is efficent.
Code: Select all
MyLoop()
{
    NetwonUPdate();
    UpdateSound();
    ....
    ... 
}


Then in your contact proccess all you need to do is add the bodies for wich your logic decides it should play looping sounds.
you save all relevant info to modulate the sound volome, and pitch.

Thsio will start teh soudn by and event send form Netwon update, an dwill stop teh soudn by and event send form teh SoundUpdate.
The code is very efficient since only body in contct are update, and they are remove for the list automatically, just once, that is and even.
Not Event trigger would be having to iterate over the array of all bodies in the scene.

There are many different ways to do it you just need to use your creativity.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Simulate contact begin and contact end with Newton 2.0

Postby Nodrev » Tue Jun 15, 2010 9:23 am

Finally, i got it worked, thanks to you Julio :D

Here my code, in case someone found it usefull, but i must warn you that it's a mix of Newton's API code, OgreNewt code, and some abstract classes from our Scol framework.
The contact process callback (send a "contact begin" event, or if you prefer, two bodies begins to contact each other, and the "standard" contact callback):
Code: Select all
void SContactCallback::contactsProcess(OgreNewt::ContactJoint &contactJoint, Ogre::Real timeStep, int threadIndex)
{
  SNode* nodeScol0                = Ogre::any_cast<SNode*>(contactJoint.getBody0()->getUserData()) ;
   SNode* nodeScol1                = Ogre::any_cast<SNode*>(contactJoint.getBody1()->getUserData()) ;

   if(nodeScol0 != NULL && nodeScol1 != NULL)
   {
      SBody * b0 ;
      SBody * b1 ;
    SScene* mScene = nodeScol0->currentScene;

    // Contact begin detection
    BodyPairMap::iterator iBodyPairSearched = mScene->bodyPairMap.find(nodeScol0->nodeBody);
    if (iBodyPairSearched == mScene->bodyPairMap.end())
    {
      iBodyPairSearched = mScene->bodyPairMap.find(nodeScol1->nodeBody);
      if (iBodyPairSearched == mScene->bodyPairMap.end())
      {
        // Construct CollResult
        MCOLL* mCollResult = (MCOLL*)malloc(sizeof (MCOLL));
          mCollResult->body0 = nodeScol0->nodeBody;
          mCollResult->body1 = nodeScol1->nodeBody;
          mCollResult->curScene = mScene;

        // Contact begin!
        mScene->bodyPairMap.insert(BodyPairMap::value_type(nodeScol0->nodeBody, nodeScol1->nodeBody));
        getMaterialOverlapStartedCallback(mm, (int)this->matPair, mCollResult);

        // Release memory.
        free(mCollResult);
      }
    }

    // For each contact point between those two bodies.
    for (OgreNewt::Contact contact = contactJoint.getFirstContact(); contact; contact = contact.getNext())
    {
        b0 = nodeScol0->nodeBody ;
        b1 = nodeScol1->nodeBody ;

      MCOLL* mCollResult = (MCOLL*)malloc(sizeof (MCOLL));
        mCollResult->body0 = b0 ;
        mCollResult->body1 = b1 ;
        mCollResult->curScene = mScene ;

      // TODO: une seule callback pour tous les contacts de ce material pair
      getMaterialContactCallback(mm, (int)this->matPair, mCollResult);

      // Release memory.
      free(mCollResult);
    }
   }
}


And somewhere in the render loop, after the code that update Newton, and before rendering a graphic frame, the detection of a "contact end" (two bodies are not in contact anymore):
Code: Select all
  // Parsing all bodies that were detected in contact
  BodyPairMap::iterator iBodyPairMap = mScene->bodyPairMap.begin();
  while (iBodyPairMap != mScene->bodyPairMap.end())
  {
      // Checking if bodies are still in contact. Note that NewtonBodyGetFirstContactJoint() is not binded in OgreNewt for the moment.
      bool bodiesInContact = false;
      NewtonBody* b0 = iBodyPairMap->first->getOgreNewtBodyPointer()->getNewtonBody();
      NewtonBody* b1 = iBodyPairMap->second->getOgreNewtBodyPointer()->getNewtonBody();
      NewtonJoint* contactJoint = NewtonBodyGetFirstContactJoint(b0);
      while((contactJoint) && (!bodiesInContact))
      {
        // Get infos about the bodies of contact from Newton
        NewtonBody* b0Bis = NewtonJointGetBody0(contactJoint);
        NewtonBody* b1Bis = NewtonJointGetBody1(contactJoint);

        // Is the body still in contact with the second body of the pair value?
        if(((b0Bis == b0)&&(b1Bis == b1)) || ((b0Bis == b1)&&(b1Bis == b0)))
          bodiesInContact = true;
        else
          contactJoint = NewtonBodyGetNextContactJoint(b0, contactJoint);
      }

      // If not, remove the bodies pair from the map.
      if (!bodiesInContact)
      {
        // Keep a reference to current entry in the map.
        BodyPairMap::iterator iBodyPairSearched = iBodyPairMap;

        // Getting the material pair. TODO: cleaner way to parse MaterialPair list
        SMaterialPair* matPair = 0;
        SMaterialPairMap::iterator iMaterialPairList = mScene->listOfPhysicsMaterialPair.begin();
        while((iMaterialPairList != mScene->listOfPhysicsMaterialPair.end()) && (!matPair))
        {
          if (((*iMaterialPairList)->getID1() == iBodyPairSearched->first->getMaterialID()->getID() && (*iMaterialPairList)->getID2() == iBodyPairSearched->second->getMaterialID()->getID())
            ||((*iMaterialPairList)->getID2() == iBodyPairSearched->first->getMaterialID()->getID() && (*iMaterialPairList)->getID1() == iBodyPairSearched->second->getMaterialID()->getID()))
              matPair = *iMaterialPairList;

          iMaterialPairList++;
        }

        if (matPair != 0)
        {
          // Construct CollResult
          MCOLL* mCollResult = (MCOLL*)malloc(sizeof (MCOLL));
           mCollResult->body0 = iBodyPairSearched->first;
           mCollResult->body1 = iBodyPairSearched->second;
           mCollResult->curScene = mScene;

          // Send contact end callback to scol virtual machine.
          getMaterialOverlapEndedCallback(mm, (int)matPair, mCollResult);

          // Release memory.
          free(mCollResult);
        }

        // erase the entry from the map.
        mScene->bodyPairMap.erase(iBodyPairSearched);
    }
    // Next couple.
    iBodyPairMap++;
  }


If you need such a functionality, note again that you'll have to cleanup code, cause there's much call to our framework functions, but i think you could catch the main idea with the comments.

Thanks again.
Nodrev
 
Posts: 4
Joined: Mon Jun 14, 2010 5:05 am


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 1 guest

cron