Ok, now for another bug; on Linux only, when you remove an actor that is colliding when it is removed, and you have collision stop reporting enabled, it crashes. I had trouble debugging this because I couldn’t get gdb to show me any information about the Python stack. (I even tried using the gdb macros from python.org, and they didn’t work for me)
Here’s the test case:
#!/usr/bin/env python
"""Demonstrate issues with PhysxActor.release() and collision stop.
If an actor is colliding when it is released, and the
PhysxEnums.CPFNotifyOnEndTouch flag is enabled for that collision, it will
crash the application.
Use the arrow keys to move the center box. ("Box-A")
"""
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.showbase.InputStateGlobal import inputState
from panda3d.core import AmbientLight
from panda3d.core import DirectionalLight
from panda3d.core import Vec3
from panda3d.core import Vec4
from panda3d.core import Point3
from panda3d.physx import PhysxManager
from panda3d.physx import PhysxSceneDesc
from panda3d.physx import PhysxBodyDesc
from panda3d.physx import PhysxActorDesc
from panda3d.physx import PhysxBoxShapeDesc
from panda3d.physx import PhysxCapsuleShapeDesc
from panda3d.physx import PhysxPlaneShapeDesc
from panda3d.physx import PhysxEnums
from panda3d.physx import PhysxRay
from panda3d.physx import PhysxGroupsMask
from panda3d.physx import PhysxMask
import sys
# Base
base.setBackgroundColor(0, 0, 0.6, 1)
base.setFrameRateMeter(True)
base.cam.setPos(0, -20, 4)
base.cam.lookAt(0, 0, 0)
alight = AmbientLight('ambientLight')
alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
alightNP = render.attachNewNode(alight)
dlight = DirectionalLight('directionalLight')
dlight.setDirection(Vec3(1, 1, -1))
dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
dlightNP = render.attachNewNode(dlight)
render.clearLight()
render.setLight(alightNP)
render.setLight(dlightNP)
inputState.watchWithModifiers('forward', 'arrow_up')
inputState.watchWithModifiers('left', 'arrow_left')
inputState.watchWithModifiers('reverse', 'arrow_down')
inputState.watchWithModifiers('right', 'arrow_right')
# Scene
sceneDesc = PhysxSceneDesc()
sceneDesc.setGravity(Vec3(0, 0, -9.81))
scene = PhysxManager.getGlobalPtr().createScene(sceneDesc)
# Plane
shapeDesc = PhysxPlaneShapeDesc()
shapeDesc.setPlane(Vec3(0, 0, 1), -2)
actorDesc = PhysxActorDesc()
actorDesc.setName('Plane')
actorDesc.addShape(shapeDesc)
actorP = scene.createActor(actorDesc)
actorP.setGroup(3)
# Actors
def createBox(name, *pos):
boxNode = loader.loadModel('box')
boxNode.reparentTo(render)
boxNode.setPos(Vec3(-0.5, -0.5, -0.5))
boxNode.flattenStrong()
shapeDesc = PhysxBoxShapeDesc()
shapeDesc.setDimensions(Vec3(0.5, 0.5, 0.5))
bodyDesc = PhysxBodyDesc()
bodyDesc.setMass(10.0)
actorDesc = PhysxActorDesc()
actorDesc.setBody(bodyDesc)
actorDesc.setName(name)
actorDesc.addShape(shapeDesc)
#actorDesc.setGlobalPos(Point3(*pos))
actor = scene.createActor(actorDesc)
actor.setGroup(1)
actor.attachNodePath(boxNode)
actor.setGlobalPos(Point3(*pos))
actor.setPythonTag('node', boxNode)
print "Created actor '%s'." % (actor.getName(), )
return actor
# Create box actors
for x in range(-8, 10, 2):
for y in range(-8, 10, 2):
if x == 0 and y == 0:
actorA = createBox('Box-A', x, y, 2)
# Set the player-controlled actor to have a different group.
actorA.setGroup(2)
else:
createBox('Box%+d%+d' % (x, y), x, y, 2)
# Debug
debugNP = render.attachNewNode(scene.getDebugGeomNode())
debugNP.node().on()
debugNP.node().visualizeWorldAxes(True)
def updateWorld(task):
dt = globalClock.getDt()
force = Vec3(0, 0, 0)
if inputState.isSet('forward'):
force.setY(90)
if inputState.isSet('reverse'):
force.setY(-90)
if inputState.isSet('left'):
force.setX(-90)
if inputState.isSet('right'):
force.setX(90)
actorA.addForce(force)
scene.simulate(dt)
scene.fetchResults()
return task.cont
taskMgr.add(updateWorld, 'updateWorld')
def doExit():
sys.exit(1)
def doScreenshot():
base.screenshot('test')
def toggleWireframe():
base.toggleWireframe()
def toggleDebug():
debugNP.node().toggle()
base.accept('escape', doExit)
base.accept('f1', toggleWireframe)
base.accept('f3', toggleDebug)
base.accept('f5', doScreenshot)
# Contact reporting
scene.enableContactReporting(True)
scene.setActorGroupPairFlag(1, 1, PhysxEnums.CPFNotifyOnStartTouch, 1)
scene.setActorGroupPairFlag(1, 1, PhysxEnums.CPFNotifyOnEndTouch, 1)
scene.setActorGroupPairFlag(1, 1, PhysxEnums.CPFNotifyOnTouch, 1)
scene.setActorGroupPairFlag(2, 1, PhysxEnums.CPFNotifyOnStartTouch, 1)
scene.setActorGroupPairFlag(2, 1, PhysxEnums.CPFNotifyOnEndTouch, 1)
scene.setActorGroupPairFlag(2, 1, PhysxEnums.CPFNotifyOnTouch, 1)
def onContactStart(pair):
print 'START', pair.getActorA().getName(), pair.getActorB().getName(), pair.getActorA().getGroup(), pair.getActorB().getGroup()
if pair.getActorA().getGroup() == pair.getActorB().getGroup():
print ' Releasing actor A...'
node = pair.getActorA().getNodePath()
node.removeNode()
node = None
pair.getActorA().release()
def onContactStop(pair):
print 'STOP', pair.getActorA().getName(), pair.getActorB().getName(), pair.getActorA().getGroup(), pair.getActorB().getGroup()
base.accept('physx-contact-start', onContactStart)
base.accept('physx-contact-stop', onContactStop)
# Run
run()