OgreOde no collision events caught

Zyzle

30-11-2008 12:39:45

Hey guys, been a while since I posted on this forum (what can I say, been busy with work)

Anyway I've finally got around to doing some more work for my game and I've ran into a few issues using OgreOde for collision detection.

The code is on the vast side so I wont post it all here , but here's what I think are the important parts.

First the collision listener:


class GameCollisionListener(OgreOde.CollisionListener):

def __init__(self, world):
print "making collision listener"
OgreOde.CollisionListener.__init__(self)
self.world = world
self.world.setCollisionListener(self)

def collision(self, contact):
print "caught collision"
g1 = contact.getFirstGeometry()
g2 = contact.getSecondGeometry()

if g1 and g2:
b1 = g1.getBody()
b2 = g2.getBody()
if b1 and b2 and ode.Joint.areConnected(b1, b2):
return False

contact.setCoulombFriction(9999999999)
contact.setBouncyness(0.1)

return True


I got the code from another forum post a while back where someone asked for ODE tutorials.

Next is setting up the players geom/body


self.entity.setQueryFlags(1<<2)
self.body = OgreOde.Body(world)
self.physNode.attachObject(self.body)
size = ogre.Vector3(1, 1, 1)
self.mass = OgreOde.BoxMass(0.5, size)
self.geom = OgreOde.BoxGeometry(size, world, space)
#self.humanPlayer.entityNode.setScale(size.x * 0.1, size.y * 0.1, size.z * 0.1)
self.body.setMass(self.mass)
self.geom.setBody(self.body)
self.entity.setUserObject(self.geom)


This code is run from the player objects constructor, hopefully its fairly self explanitory (again mostly stolen form another example)

Finally we have the world setup in the level class:


self.world = OgreOde.World(self.sceneManager)
#self.world.setGravity(ogre.Vector3(0,-9.80665,0))
self.world.setCFM(10e-5)
self.world.setERP(0.8)
self.world.setAutoSleep(True)
self.world.setAutoSleepAverageSamplesCount(10)
self.world.setContactCorrectionVelocity(1.0)
self.space = self.world.getDefaultSpace()

self.collisionListener = GameCollisionListener(self.world)

timeStep = 0.5
timeScale = 1.7
maxFrameTime = 1.0/4
self.stepper = OgreOde.StepHandler(self.world, OgreOde.StepHandler.QuickStep,
timeStep, maxFrameTime, timeScale)


The stepper is incremented each frame using:

if self.stepper.step(evt.timeSinceLastFrame):
#print frameEvent.timeSinceLastFrame
self.world.synchronise()


Now when I uncomment the "self.world.setGravity(ogre.Vector3(0,-9.80665,0))" line in the above code when the level loads I see both players fall through the floor as affected by gravity so I'm assuming the Ode stuff is set up on both players correctly.

The problem is that when I move one player over another I dont receive the "caught collision" output from the print statement in the collision method of the GameCollisionListener which is what I should expect when the two entities collide right?

Sorry there's so much to read, any help is appreciated.

Edit: Ok partially fixed the problem, I realised that the node containing the body was never actually being moved along with the entity so i fixed it by adding the physNode to the above player code. The problem is that the collision method now seems to be called every frame regardless of whether or not the objects are actually colliding,

Quadrofonic

29-09-2009 17:15:16

I used this example code to add OgreODE physics to the nXtank project. I got the same result: bodies were colliding every frame.

Enabling self.world.setShowDebugGeometries(True) showed me what was happening: the ODE bodies I had created and "attached" to sceneNodes were not attached to those nodes. All the ODE bodies were at the origin, and thus colliding every frame.

Once created, move the bodies to the node they are supposed to attach to:
self.body.setPosition(self.node.getPosition())
self.body.setOrientation(self.node.getOrientation())

This code will create an ODE Box Body which conforms to the size and shape of an entity, even if the entity origin is not at its center:
box = self.entity.getBoundingBox()
boxMin = box.getMinimum()
boxMax = box.getMaximum()
self.bodySize = ogre.Vector3(boxMax.x - boxMin.x, boxMax.y - boxMin.y, boxMax.z - boxMin.z)
offset = ogre.Vector3((boxMax.x + boxMin.x)/2,(boxMax.y + boxMin.y)/2,(boxMax.z + boxMin.z)/2)
self.geom = OgreOde.BoxGeometry(self.bodySize, self.world, self.space)
self.geom.setBody(self.body)
self.geom.setOffsetPosition(self.offset)


Once the collision bodies are created and placed, they will not follow the entity if you move the entity's sceneNode with setPosition() or translate(). Instead, if you move the Body with addRelativeForce() and addRelativeTorque() it will move the entity and sceneNode along with it.

I had presumed that the association of the physics Body and the SceneNode worked both ways, but this is not the case. Is this a bug or a feature?

Also, subclassing your player class from ogre.UserDefinedObject allows you to reference colliding objects directly in the collision listener callback.
Add to Player:
self.geom.setUserObject(self)Add to Listener:
g1 = contact.getFirstGeometry()
g2 = contact.getSecondGeometry()
o1 = g1.getUserObject()
o2 = g2.getUserObject()


BEWARE: Do not move, create or destroy physics bodies during the collision listener callback. The physics space is locked during the collision detection phase. Instead flag the objects and move/create/destroy them during your rendering loop.

I hope this helps other folks make OgreODE work for their own projects. It's been a big leap forward for nXtank.