[SOLVED]Dynamic Delete Body

wilsonwing

30-12-2008 13:33:15

Hi, I am trying to make a missile in my game using OgreNewt.
I got a problem to delete the missile itself at run time.
And I find this in the search:


you can't delete the body from inside a collision callback, because Newton is in the middle of it's internal loop there. it doesn't "realize" that the body has been deleted, and tries to access it later.

you should mark a flag, and delete the body after the call to World::update() has completed.


I write this:

void missile::forceCallback(OgreNewt::Body* m_pNewtonBody)
{
//if moves more then 1000 units , destroy itself
if(getPosition().squaredDistance(m_StartPosition) >m_LifeDistance*m_LifeDistance)
{
destroy = true;
}
else
setVelocity(MoveForceGlobal);
}


But I am not sure.... where should I delete the missile ?
I do this but still the same:

void missile::forceCallback(OgreNewt::Body* m_pNewtonBody)
{
//if moves more then 1000 units , destroy itself
if(destroy )
this->~missile();
if(getPosition().squaredDistance(m_StartPosition) >m_LifeDistance*m_LifeDistance)
{
destroy = true;
}
else
setVelocity(MoveForceGlobal);
}


I am a newbie still using the framework from the Demos.
I am thinking maybe I should delete this somewhere else in the Ogre_NewtBasicListener?
Should I put it in the framStart of Ogre_NewtBasicListener or ApplicationListener?

-----------------------------------------------------------------------------------------------------------------
PS.
Also, I wanted to implement two people, they have the same material type, and they can pass through each other's body (like ghost, but they still have other physic behavior)
This is I do in the CharacterMatCallback::userProcess() :

if (m_body0->getType() == BT_Character && m_body1->getType() == BT_FLOOR)
{
return 0;
}

But still they cannot go through each other :(

Please help me with this :D THANKS!

hellaeon

02-01-2009 08:11:06

Classic I just posted a similar problem. When to delete nodes, and how. I just need a fairly simple example.
I assumed it would be userEnd, after all collisions have been processed, but this seems to get called numerous times in the collision loop.
I just want to delete a box when it hits the ground. I am using the collision callback system with UserProcess etc.
This is the code I am using


int CCB_BoxGround::userBegin()
{ // first, find which body represents the box!
// okay, found the box... DIE
if (m_body0->getMaterialGroupID()->getID() == 2)
{
mBoxNode = m_body1->getOgreNode();
mBodyNode = m_body1;
}

if (m_body1->getMaterialGroupID()->getID() == 2)
{
mBoxNode = m_body0->getOgreNode();
mBodyNode = m_body0;
}

if (!mBoxNode) return 0;
return 1;
}

int CCB_BoxGround::userProcess()
{
if (mBoxNode != NULL)
{
// add to vector list
bbNode_Vector.push_back(mBoxNode->getName());
bbBody_Vector.push_back(mBodyNode);
}
mBoxNode = NULL;
return 1;
}

void CCB_BoxGround::userEnd()
{
for(int i=0;i<bbBody_Vector.size();i++){
OgreNewt::Body* mDelBody = bbBody_Vector[i];
if(mDelBody){
delete mDelBody;
mDelBody=0;
}
if(mySceneMgr->getSceneNode(bbNode_Vector[i])){
delete mySceneMgr->getSceneNode(bbNode_Vector[i]);
}
}
}


oddly an error occurs here in the file 'function_template.hpp'


#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS,
typename Allocator>
typename BOOST_FUNCTION_FUNCTION<
R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS,
Allocator>::result_type
BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS,

Allocator>
::operator()(BOOST_FUNCTION_PARMS) const
{
if (this->empty())
boost::throw_exception(bad_function_call());

return invoker(this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
}
#endif


the error occurs on the line return invoker(this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);


For now I simply want to know how to remove the nodes/boxes once they collide. I run into issues I believe because the UserProcess function gets called so many times during testing for collisions.
I want to eventually add some kind of particle system to show an explosion of sorts but cant get past this simple issue. Does anyone have a fairly straight forward example I can follow that shows 2 objects that collide, ignoring the other collision checking between them, and then of course, how I can just remove the body, node. (or show an explosion). Just need a good example or explanation. I will also refer to stunt playground and have a look.

Cheers all.

hellaeon

04-01-2009 04:24:14

I had another look and the consensus is to create a Vector list and delete the nodes in FrameListener::FrameEnded() (I believe)
I have something like that set up ( a vector list in my CollisionCallback class pointed to by my FrameListener class) but its still having dramas.

hellaeon

04-01-2009 05:37:42

Finally....

I have 2 materials - Box and Ground. I have about 50 boxes on screen.
I create a collision callback class called 'CCB_BoxGround'.

Using a Vector List in my collision class:

std::vector<std::string> bbNode_Vector;
std::vector<OgreNewt::Body*> bbBody_Vector;


These are accessible publicly from this collision class for the box/ground material.

During the declaration of MyFrameListener in createFrameListener() I pass a pointer to the instance of 'CCB_BoxGround' for my two materials - a Box and the Ground, thus making available access to the vectors via my FrameListener. In the frame listener class this instance is called 'myColClass'.

As I throw an object and it hits the pile of boxes on a higher pedestool -


int CCB_BoxGround::userBegin()
{ // first, find which body represents the box!
// okay, found the box... DIE
if (m_body0->getMaterialGroupID()->getID() == 2)
{
mBoxNode = m_body1->getOgreNode();
mBodyNode = m_body1;
}

if (m_body1->getMaterialGroupID()->getID() == 2)
{
mBoxNode = m_body0->getOgreNode();
mBodyNode = m_body0;
}

if (!mBoxNode) return 0;

// loop through our vector and see if we already have this node
for(int i=0;i<bbNode_Vector.size();i++)
if (mBoxNode->getName() == bbNode_Vector[i])
return 0;

return 1;
}

int CCB_BoxGround::userProcess()
{
// add to vector list
bbNode_Vector.push_back(mBoxNode->getName());
bbBody_Vector.push_back(mBodyNode);

return 1;
}


Oh yes its ugly - for now.

Now this way I am storing each frame the collided boxes in my vectors. I also am grabbing the node name, which I will delete. My box is not a 'class'. a class creates the node on the fly....but thats another issue. For now, just realise I want to store a pointer to the body and Node of the Box.

Now in my Frame Listener FrameEnded() - I access those public vector lists.

//// delete the boxes we dont want
for(int i=0;i<myColClass->bbBody_Vector.size();i++)
{
if(mySceneMgr->hasSceneNode(myColClass->bbNode_Vector[i]))
{
myColClass->bbBody_Vector[i]->removeTransformCallback();
myColClass->bbBody_Vector[i]->removeForceAndTorqueCallback();
delete myColClass->bbBody_Vector[i];
mySceneMgr->destroySceneNode(myColClass->bbNode_Vector[i]);
}
}

myColClass->bbBody_Vector.erase(myColClass->bbBody_Vector.begin(), myColClass->bbBody_Vector.end());
myColClass->bbNode_Vector.erase(myColClass->bbNode_Vector.begin(), myColClass->bbNode_Vector.end());



The reason I check if the node exists at first is because it is storing the name sometimes 2 or 3 times into the vector during the userProcess() callback function
Otherwise this successfully - for now - makes my boxes finally shove off. I guess I will probably handle sound etc in my frameEnded function, though I know its not the best way to do it.

Can some of you better smarter lot give me the going over on the code and make suggestions I obviously need to hear?
My next step is to move the Box to an actual class which should be easier to handle - or is it? Is it just as simple to do it this way rather then creating a box class? Would that become too much memory?....anyway wilsonwing - I hope this helps.

wilsonwing

04-01-2009 08:56:42


Thanks for your example code.
I will tried to figure out this as soon as possible after I finish my final exam. :D

hellaeon

04-01-2009 09:32:35

I have a class called BoxPile and a class called BoomBox.

BoxPile calls BoomBox a number of times to create a pile of boxes, however all BoomBox does at the moment is get given a heap of constructor variables, and from there creates a scene node with a box and body.
The best way to handle this would be to create a Vector list of Box classes that I create (rather then treat BoomBox like a function that builds scene nodes as I do now), Within the class create a new variable like 'dieNow' (set to true when collision occurs in my CollisionClass) that will be checked frameended() instead of just the node. This also brings it inline with how Demo 3 works in the OgreNewt Demo's.

This way I can store a particle emittion function or class within Box as well as some sound effect, so the whole life cycle stays within the class.
Also, I dont need to handle sounds or the like for random boxes outside there own class. Going forward and creating multiple objects, it seems a more managed approach to handling the 'userEnd()' function.

Anyone with any thoughts?

Cheers

EDIT: Having now succesfully moved my project to the above described model, the key I found for collision materials is the line mBody->setUserData(this); in your objects class.

wilsonwing

12-01-2009 05:10:03

Sorry for so late reply.
I 've managed to complete this.
I make a DynamicObjectManager to create and delete the dynamic objects.
I have a list inside.
And I check every frame End to see if the dynamicObject should be deleted.
If so, just delete it.
This works with no error. :D