Custom Callbacks

nathanwilliams6

15-06-2006 15:29:54

Okay, i have set up a custom callback between two materials, such that at one can pass thorough the other.

I then print out Collision begin, in UserBegin() and then i print end in UserEnd();

from reading the comments in ur example (demo3) i assumed that userbegin would be called once (as the bounding boxes overlapped) and userend would be called as it was about to leave (i.e. fall through the other side)

what i found was that for every newton update i did, there was a call to both userbegin and userend.

is this right ?

i would expect, that since i rejected the collision in the userproccess stage, that i would see this.

user begin (as its about to enter)
user process ( a load of times - as it pass through)
user end (as it falls out the other side)

instead i see
user begin
user process ( a few times)
user end
[all repeated continuously while it falls through]

am i missing something ? how can i use user end to play a sound effect if it will contiuously be called during every frame update while there is a small bit of contact ?

what ideally i want, is some way of telling my app, ButtonPressed() once as they start to collide, and then ButtonReleased() after they have fininshed.

if i implemented those into UserBegin and UserEnd i would get multiple button presses for each time my objecty falls through.

walaber

15-06-2006 22:05:42

yeah, you have the idea a bit wrong. here's now the callbacks work.

for EACH call to OgreNewt::World::Update(), it goes through and calculates all the collisions that happen.

when 2 bodies AABB (bounding boxes) overlap, there is a good chance of collision. so Newton calls userBegin(). this tells you "body0 and body1 have a good chance of colliding during this update". You can tell Newton to ignore any further interaction between these two by returning 0 from that callback.

if you return 1, you are telling Newton you would like to process the collision further, and look for an actual collision.

then, for each time the 2 bodies touch during the update, userProcess is called. this could happen many times during a single update, especially when a stack of objects in involved. In userProcess you get information about the collision, such as location, velocity, etc. you can also set the friction / softness / elasticity here on a per-contact basis. again, returning 0 tells Newton to ignore this collision (and let the bodies pass through each other).

finally, once all collisions between the 2 bodies are calculated FOR THIE UPDATE, the userEnd callback is called. this does not mean that the bodies hare stopped overlapping. it simply means that all of the collisions for this update have been calculated and handled. this callback is useful for acting upon the information you can gather from the (multiple calls to) userProcess. for example if you want to play a sound when 2 bodies hit, you don't want to do it in userProcess, because you might try to play the same sound 5 times in a single update. instead, you would keep track of the contact with the highest velocity, and use that information in userEnd to actually play the sound (because it's only called once).


so, to make a long story short, you will need a flag variable in your case. what you can do, is set the "bodies are overlapping" flag to "FALSE" at the beginning of each game loop.

then, inside the userProcess callback, set the flag to TRUE. by keeping track of when the value for the flag switches, you can trigger your events.

nathanwilliams6

16-06-2006 10:07:55

ok cheers, thanx for the clarification :)

just a quick question, surely if, as per your example, you played a sound in user end based on info during user process, then u would get a flood of sound.

in my application, per cycle through the physics listener, i call maybe 4/5 upodates to ogrenewt. see below. (bare in mind, my world updater works with multiple worlds, although i only use 1 atm.



m_rElapsed += evt.timeSinceLastFrame;
Ogre::Real m_rLoopElapsed; // a variable used within the loop to elapse the time in the physics worlds

std::map<Ogre::String, WorldStruct>::iterator iWorldIterator;



iWorldIterator = m_mWorlds.begin();
while ( iWorldIterator != m_mWorlds.end() )
{
if ( (*iWorldIterator).second.s_bWorldEnabled )
{
int count = 0;
m_rLoopElapsed = m_rElapsed;

if ((m_rLoopElapsed > m_rUpdate) && (m_rLoopElapsed < (1.0f)) )
{
while (m_rLoopElapsed > m_rUpdate)
{

Ogre::LogManager::getSingleton().logMessage(" ==");
staticTemp();
(*iWorldIterator).second.s_wWorld->update( m_rUpdate );
m_rLoopElapsed -= m_rUpdate;
count++;
}
}
else
{
if (m_rLoopElapsed < (m_rUpdate))
{
// not enough time has passed this loop, so ignore for now.
}
else
{
Ogre::LogManager::getSingleton().logMessage(" ==");
staticTemp();
(*iWorldIterator).second.s_wWorld->update( m_rLoopElapsed );
m_rLoopElapsed = 0;
count++;
}
}

Ogre::LogManager::getSingleton().logMessage(" Newton updates this loop: "+Ogre::StringConverter::toString(count));
}
iWorldIterator++;
}

m_rElapsed = m_rLoopElapsed;

walaber

16-06-2006 16:00:47

yeah, in the case of time-slicing, you would probably also want to keep track of the amount of time passed since last playing a sound, and only play if a reasonable amount of time has passed.