Crash with PhysicsCollisionHandler

I’ve been trying to add a basic physics system, and ran into a bug that crashes Panda every time. Pro-rsoft gave me some help in IRC, but couldn’t figure it out so I’m posting it here. I tried adding ‘notify-level-physics debug’ to /etc/Config.prc but it didn’t do anything. I’m running 1.5.3 on amd64 Ubuntu Intrepid.

Below is the code stripped as bare as I could. That means there is nothing to see, but it basically
(1) Creates a custom class with a model parented to an ActorNode, and its collision geometry
(2) Creates a wall in front of the model
(3) Creates a PhysicsCollisionHandler with the model and the wall
(4) Moves the model forward into the wall. The instant they collide, panda crashes.

#~/usr/bin/python
import direct.directbase.DirectStart
from direct.showbase import DirectObject
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
#from direct.gui.DirectGui import *
from direct.showbase.DirectObject import *
import math, random, os, sys, cPickle
from direct.task.Task import Task, cont, time
from time import time, ctime

base.disableMouse()
class World(DirectObject):
  class player(DirectObject):
    def __init__(self, path, position=0, scale=1):
      self.scale = scale
      self.position = position
      self.model_path = path
      self.model = loader.loadModel(self.model_path)
      self.top = render.attachNewNode("player node")
      self.model.reparentTo(render)
      self.model.setScale(scale)
      self.model.setZ(10)
      taskMgr.add(self.update_pos,  "update-pos")
      bounds = self.model.getTightBounds()
      x = bounds[0][0] - bounds[1][0]
      y = bounds[0][1] - bounds [1][1]
      sphere = CollisionSphere(0, 0, 0, math.sqrt(x*x+y*y)/2)
      cNode = CollisionNode("player")
      cNode.addSolid(sphere)
      cNode.setFromCollideMask(BitMask32.bit(3))
      self.cNodePath = self.model.attachNewNode(cNode)
    def update_pos(self, task,  speed = 10):
      offset = self.model.getNetTransform().getMat().getRow3(1)
      offset.normalize()
      self.model.setPos(self.model.getPos() + offset*(.15))
      return Task.cont
  def __init__(self):
    cWall = CollisionNode("wall")
    plane = CollisionPlane(Plane(Vec3(0, -1, 0), Point3(0, 16, 0)))
    cWall.addSolid(plane)
    wall = render.attachNewNode(cWall)
    cWall.setIntoCollideMask(BitMask32.bit(3))
    self.panda = World.player("panda", scale = .5)
    pusher = PhysicsCollisionHandler()
    base.cTrav = CollisionTraverser()
    base.cTrav.addCollider(self.panda.cNodePath,pusher)
    pusher.addCollider(self.panda.cNodePath,self.panda.model)
    #Set up physics / gravity for the player
    base.enableParticles()
    Node=NodePath(PandaNode("PhysicsNode"))
    Node.reparentTo(render)
    an=ActorNode("player-physics")
    anp=Node.attachNewNode(an)
    base.physicsMgr.attachPhysicalNode(an)
    self.panda.model.reparentTo(anp)

w = World()
run()

Here is the output of gdb:

In my build, where Panda is compiled with more debugging features enabled, I get this useful error message before it crashes:

:express(error): Attempt to cast pointer from ModelRoot to ActorNode
Assertion failed: (void *)(actor) != (void *)NULL at line 110 of physicsCollisionHandler.cxx

From this I conclude that PhysicsCollisionHandler assumes that the NodePath you specify in pusher.addCollider() contains an ActorNode, which is sensible since this is the only kind of node that the physics system can act upon. In fact, you gave it an ordinary model.

Of course, it would be better if the PhysicsCollisionHandler raised an exception at the time you called addCollider(), and regardless of the debugging features enabled in Panda. I’ll make that fix.

David