Missiles handling

Druha

29-11-2009 14:24:51

Hi betajaen!
What is the best way to calculate collisions of rockets and other flying objects? I am not asking about instant objects like bullets - there is raycast for them. I am interested how to organize rockets, torpedos, etc in my world. Those objects are described only by its' position, direction and velocity, without any shape.
I was thinking about using raycasts every N frames/seconds. But it seems to be inaccurate and not very fast. Is there an eaiser way to do this?

betajaen

29-11-2009 14:53:50

Sup my man!

How about intersection or sweep testing? Perform a test where the rocket is likely to be, and check if there are collisions. You could even "fake CCD" by increasing the length of the sweep shape when the velocity increases - to account for the precision.

Druha

29-11-2009 15:26:12

Can you give give me a more detailed explanation about this?
... and check if there are collisions.

I just want PhysX to do all dirty work for me and find a body, which was hit by a rocket.

betajaen

29-11-2009 16:01:18

I expect you know this but a sweep test is a bit like a 3D-raycast. It's like placing a trigger over in a scene for a split second then getting all the points where it collides and what shapes it collides with.

You'll have to the hard work of working out the position yourself, PhysX won't do this without using Actors; which you won't use. Which is fine, instead just use the standard distance formula (s=Vt). Where s is displacement, V is linear velocity, and t is time. I'm sure you can come up with the bits to handle missile classes, and periodically workout the displacement for each missile each frame. Just a Missile struct, std::vector to store them, and MissileManager class inherting NxOgre::Timelistener will do.

To do the actual collision detection; Sadly Detritus is the only one (as I can see) that offers proper sweeping functions (Scene::linearOBBSweep, Actor::linearSweep) in BloodyMess you probably have to use the PhysX functions. Just sweep at the displacement, and using a OBB box to represent the shape of the missile. If you wish you can "fake CCD" by increasing the length of OBB box in the direction of travel based on the velocity of the missile; the missile accelerates - the length of the box increases. Once the sweep test is positive (i.e. you get a collision), you can explode your missile.

Hope this helps.

Druha

30-11-2009 20:39:07

Ok, I've moved to Detritus, and now I have a new question.
I can only get a Shape pointer from linearOBBSweep. How can I get more "high-level" object using this information? I have to do some damage to the player, which caught that rocket.

betajaen

30-11-2009 21:02:41

I've added a (untested) getRigidBody function to Shape for you.

As for your other problem with Heightfield, I am bringing up some test cases in Soy for you. But since my current Detritus release has many errors (due to some new allocation macros/functions), I can't really do anything. If you can come up with the solution for HeightFeilds before I can, I'll add your changes to git.

mpomares

03-12-2009 19:24:06

Hi, maybe this solution can help a little. It work for me with missiles.
First, i need a model like missil, late i have to code the collissions.
Steps
1.Add this files from Physx SDK

#include <NxActor.h>
#include <NxScene.h>
#include <NxUserContactReport.h>

2.Add this code to your principal class

class MyApplication : public ExampleApplication, public NxOgre::Callback, public NxUserContactReport
{

3.Now for contact between movable meshes. We need a event function for Contacts. We need set to nxscene the event
contact. Add this in your scene creation function.

//listener
//mScene (NxOgre scene)
mScene->getScene()->setUserContactReport(this);

And the functions for contacts have to be inside your principal class.

void onContactNotify(NxContactPair& pair, NxU32 events)
{
OGRE3DBody* body = static_cast<OGRE3DBody*>(pair.actors[0]->userData);
OGRE3DBody* bodycaracter = static_cast<OGRE3DBody*>(pair.actors[1]->userData);
//...
CreateExplosion(Ogre::Vector3(pair.actors[0]->getGlobalPosition().x,pair.actors[0]->getGlobalPosition().y,pair.actors[0]->getGlobalPosition().z),bodycaracter->getSceneNode());
//...
body->putToSleep();
pair.actors[0]->setGroup(100);
SetActorCollisionGroup(pair.actors[0],100);
body->getSceneNode()->detachAllObjects();
pair.actors[0]->raiseBodyFlag(NX_BF_KINEMATIC);
pair.actors[0]->raiseActorFlag(NX_AF_DISABLE_RESPONSE);
//...
}

When i create a new body with mRenderSystem of NxOgre i have to add this pointer.

OGRE3DBody* myrocket= mRenderSystem->createBody(new NxOgre::Box(2, 2, 2), NxOgre::Vec3(Arma->getPosition().x, Arma->getPosition().y, Arma->getPosition().z),"rocket.mesh");
myrocket->addForce(NxOgre::Vec3(mCamera->getDirection().x * 10000, mCamera->getDirection().y * 10000,
mCamera->getDirection().z * 10000), NxOgre::Enums::ForceMode_Force, false);
myrocket->getNxActor()->setGroup(1);
myrocket->getNxActor()->userData = myrocket;


For collisions with scene geometry we need volumens. In your scene creation function add this.

mVolume = mScene->createVolume(triangleGeometry, NxOgre::Matrix44(NxOgre::Vec3(0, 30, 0)),this, NxOgre::Enums::VolumeCollisionType_OnEnter);

And the event for the volume.

void onVolumeEvent(NxOgre::Volume* volume, NxOgre::Shape* volumeShape, NxOgre::RigidBody* rigidBody, NxOgre::Shape* rigidBodyShape, unsigned int collisionEvent)
{
// add explosion particles
NxOgre::Actor* actor = static_cast<NxOgre::Actor*>(rigidBody);
OGRE3DBody* body = static_cast<OGRE3DBody*>(rigidBody);

CreateExplotion(Ogre::Vector3(actor->getGlobalPosition().x,actor->getGlobalPosition().y,actor->getGlobalPosition().z),NULL);
SceneNode* node = body->getSceneNode();
if (node)
{
// Kill the emitters of any attached particle systems
for (int i = 0;i < node->numAttachedObjects();i++)
{
MovableObject* obj = node->getAttachedObject(i);
if (obj->getMovableType() == "ParticleSystem")
{
static_cast<ParticleSystem*>(obj)->removeAllEmitters();
}
}
}

body->putToSleep();
actor->setGroup(100);
SetActorCollisionGroup(actor->getNxActor(),100);
actor->getNxActor()->raiseBodyFlag(NX_BF_KINEMATIC);
actor->getNxActor()->raiseActorFlag(NX_AF_DISABLE_RESPONSE);

}

4.And the last, set the distinct groups in your scene creation.

mScene->getScene()->setGroupCollisionFlag(1, 1, true);
mScene->getScene()->setGroupCollisionFlag(1, 2, true);
mScene->getScene()->setGroupCollisionFlag(1,100,false);
mScene->getScene()->setGroupCollisionFlag(100,100,false);
mScene->getScene()->setActorGroupPairFlags(1, 1, NX_NOTIFY_ON_START_TOUCH);
mScene->getScene()->setActorGroupPairFlags(1,2, NX_NOTIFY_ON_START_TOUCH);

mScene->getScene()->setActorGroupPairFlags(1, 100, NX_IGNORE_PAIR);
mScene->getScene()->setActorGroupPairFlags(2, 100, NX_IGNORE_PAIR);
mScene->getScene()->setActorGroupPairFlags(100, 100, NX_IGNORE_PAIR);


If you wanna see a demo get one at this link
http://www.4shared.com/file/164280719/e98eec6d/Fisicas3.html

betajaen

03-12-2009 19:43:56

I believe my version is more elegant.

Your using a trigger (which is a static NxActor - which PhysX hates them being moved around) following the missile for collisions, which is dependant on frame rate; i.e. it may take two frames for the collision of the missile collision to get "noticed". Your also hacking Scene for collision reports, and your including the PhysX headers which isn't necessary or encouraged when working with BloodyMess/Detritus.

Mine; just doesn't use Actors or Triggers at all. It uses OBB sweep testing, which with a few lines of code can support CCD. The only slight disadvantage is that your have to calculate the missile position yourself but since the equation is (s=V*t), it isn't difficult to implement.